Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/pyvex/expr.py: 73%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import logging
2import re
3from typing import Dict, List, Optional, Tuple
5from .const import U8, U16, U32, U64, IRConst, get_type_size
6from .enums import IRCallee, IRRegArray, VEXObject, get_enum_from_int, get_int_from_enum
7from .errors import PyVEXError
8from .native import ffi, pvc
10log = logging.getLogger("pyvex.expr")
13class IRExpr(VEXObject):
14 """
15 IR expressions in VEX represent operations without side effects.
16 """
18 __slots__ = []
20 tag: Optional[str] = None
21 tag_int = 0 # set automatically at bottom of file
23 def pp(self):
24 print(str(self))
26 def __str__(self):
27 return self._pp_str()
29 def _pp_str(self) -> str:
30 raise NotImplementedError
32 @property
33 def child_expressions(self) -> List["IRExpr"]:
34 """
35 A list of all of the expressions that this expression ends up evaluating.
36 """
37 expressions = []
38 for k in self.__slots__:
39 v = getattr(self, k)
40 if isinstance(v, IRExpr):
41 expressions.append(v)
42 expressions.extend(v.child_expressions)
43 return expressions
45 @property
46 def constants(self):
47 """
48 A list of all of the constants that this expression ends up using.
49 """
50 constants = []
51 for k in self.__slots__:
52 v = getattr(self, k)
53 if isinstance(v, IRExpr):
54 constants.extend(v.constants)
55 elif isinstance(v, IRConst):
56 constants.append(v)
57 return constants
59 def result_size(self, tyenv):
60 return get_type_size(self.result_type(tyenv))
62 def result_type(self, tyenv):
63 raise NotImplementedError()
65 def replace_expression(self, replacements):
66 """
67 Replace child expressions in-place.
69 :param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with
70 :return: None
71 """
73 for k in self.__slots__:
74 v = getattr(self, k)
75 if isinstance(v, IRExpr) and v in replacements:
76 setattr(self, k, replacements.get(v))
77 elif isinstance(v, list):
78 # Replace the instance in the list
79 for i, expr_ in enumerate(v):
80 if isinstance(expr_, IRExpr) and expr_ in replacements:
81 v[i] = replacements.get(expr_)
82 elif type(v) is tuple:
83 # Rebuild the tuple
84 _lst = []
85 replaced = False
86 for i, expr_ in enumerate(v):
87 if isinstance(expr_, IRExpr) and expr_ in replacements:
88 _lst.append(replacements.get(expr_))
89 replaced = True
90 else:
91 _lst.append(expr_)
92 if replaced:
93 setattr(self, k, tuple(_lst))
94 elif isinstance(v, IRExpr):
95 v.replace_expression(replacements)
97 @staticmethod
98 def _from_c(c_expr) -> Optional["IRExpr"]:
99 if c_expr == ffi.NULL or c_expr[0] == ffi.NULL:
100 return None
102 try:
103 return enum_to_expr_class(c_expr.tag)._from_c(c_expr)
104 except KeyError:
105 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % get_enum_from_int(c_expr.tag))
107 _translate = _from_c
109 @staticmethod
110 def _to_c(expr):
111 try:
112 return tag_to_expr_class(expr.tag)._to_c(expr)
113 except KeyError:
114 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % expr.tag)
116 def typecheck(self, tyenv):
117 return self.result_type(tyenv)
120class Binder(IRExpr):
121 """
122 Used only in pattern matching within Vex. Should not be seen outside of Vex.
123 """
125 __slots__ = ["binder"]
127 tag = "Iex_Binder"
129 def __init__(self, binder):
130 self.binder = binder
132 def _pp_str(self):
133 return "Binder"
135 @staticmethod
136 def _from_c(c_expr):
137 return Binder(c_expr.iex.Binder.binder)
139 @staticmethod
140 def _to_c(expr):
141 return pvc.IRExpr_Binder(expr.binder)
143 def result_type(self, tyenv):
144 return "Ity_INVALID"
147class VECRET(IRExpr):
148 tag = "Iex_VECRET"
150 __slots__ = []
152 def _pp_str(self):
153 return "VECRET"
155 @staticmethod
156 def _from_c(c_expr):
157 return VECRET()
159 @staticmethod
160 def _to_c(expr):
161 return pvc.IRExpr_VECRET()
163 def result_type(self, tyenv):
164 return "Ity_INVALID"
167class GSPTR(IRExpr):
168 __slots__ = []
170 tag = "Iex_GSPTR"
172 def _pp_str(self):
173 return "GSPTR"
175 @staticmethod
176 def _from_c(c_expr):
177 return GSPTR()
179 @staticmethod
180 def _to_c(expr):
181 return pvc.IRExpr_GSPTR()
183 def result_type(self, tyenv):
184 return "Ity_INVALID"
187class GetI(IRExpr):
188 """
189 Read a guest register at a non-fixed offset in the guest state.
190 """
192 __slots__ = ["descr", "ix", "bias"]
194 tag = "Iex_GetI"
196 def __init__(self, descr, ix, bias):
197 self.descr = descr
198 self.ix = ix
199 self.bias = bias
201 @property
202 def description(self):
203 return self.descr
205 @property
206 def index(self):
207 return self.ix
209 def _pp_str(self):
210 return f"GetI({self.descr})[{self.ix},{self.bias}]"
212 @staticmethod
213 def _from_c(c_expr):
214 descr = IRRegArray._from_c(c_expr.Iex.GetI.descr)
215 ix = IRExpr._from_c(c_expr.Iex.GetI.ix)
216 bias = c_expr.Iex.GetI.bias
217 return GetI(descr, ix, bias)
219 @staticmethod
220 def _to_c(expr):
221 return pvc.IRExpr_GetI(IRRegArray._to_c(expr.descr), IRExpr._to_c(expr.ix), expr.bias)
223 def result_type(self, tyenv):
224 return self.descr.elemTy
227class RdTmp(IRExpr):
228 """
229 Read the value held by a temporary.
230 """
232 __slots__ = ["_tmp"]
234 tag = "Iex_RdTmp"
236 def __init__(self, tmp):
237 self._tmp = tmp
239 def _pp_str(self):
240 return "t%d" % self.tmp
242 @property
243 def tmp(self):
244 return self._tmp
246 @staticmethod
247 def _from_c(c_expr):
248 tmp = c_expr.Iex.RdTmp.tmp
249 return RdTmp.get_instance(tmp)
251 @staticmethod
252 def _to_c(expr):
253 return pvc.IRExpr_RdTmp(expr.tmp)
255 @staticmethod
256 def get_instance(tmp):
257 if tmp < 1024:
258 # for small tmp reads, they are cached and are only created once globally
259 return _RDTMP_POOL[tmp]
260 return RdTmp(tmp)
262 def replace_expression(self, replacements):
263 # RdTmp is one of the terminal IRExprs, which cannot be replaced.
264 pass
266 def result_type(self, tyenv):
267 return tyenv.lookup(self.tmp)
269 def __hash__(self):
270 return 133700 + self._tmp
273_RDTMP_POOL = list(RdTmp(i) for i in range(0, 1024))
276class Get(IRExpr):
277 """
278 Read a guest register, at a fixed offset in the guest state.
279 """
281 __slots__ = ["offset", "ty_int"]
283 tag = "Iex_Get"
285 def __init__(self, offset, ty: str, ty_int: Optional[int] = None):
286 self.offset = offset
287 if ty_int is None:
288 self.ty_int = get_int_from_enum(ty)
289 else:
290 self.ty_int = ty_int
292 @property
293 def ty(self):
294 return get_enum_from_int(self.ty_int)
296 @property
297 def type(self):
298 return get_enum_from_int(self.ty_int)
300 def _pp_str(self):
301 return f"GET:{self.ty[4:]}(offset={self.offset})"
303 def pp_str_with_name(self, reg_name: str):
304 """pp_str_with_name is used to print the expression with the name of the
305 register instead of the offset"""
306 return f"GET:{self.ty[4:]}({reg_name})"
308 @staticmethod
309 def _from_c(c_expr):
310 return Get(c_expr.Iex.Get.offset, get_enum_from_int(c_expr.Iex.Get.ty))
312 @staticmethod
313 def _to_c(expr):
314 return pvc.IRExpr_Get(expr.offset, expr.ty_int)
316 def result_type(self, tyenv):
317 return self.ty
319 def __hash__(self):
320 return (self.offset << 8) | self.ty_int
323class Qop(IRExpr):
324 """
325 A quaternary operation (4 arguments).
326 """
328 __slots__ = ["op", "args"]
330 tag = "Iex_Qop"
332 def __init__(self, op, args):
333 self.op = op
334 self.args = args
336 def _pp_str(self):
337 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
339 @property
340 def child_expressions(self):
341 expressions = sum((a.child_expressions for a in self.args), [])
342 expressions.extend(self.args)
343 return expressions
345 @staticmethod
346 def _from_c(c_expr):
347 return Qop(
348 get_enum_from_int(c_expr.Iex.Qop.details.op),
349 [
350 IRExpr._from_c(arg)
351 for arg in [
352 c_expr.Iex.Qop.details.arg1,
353 c_expr.Iex.Qop.details.arg2,
354 c_expr.Iex.Qop.details.arg3,
355 c_expr.Iex.Qop.details.arg4,
356 ]
357 ],
358 )
360 @staticmethod
361 def _to_c(expr):
362 return pvc.IRExpr_Qop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
364 def result_type(self, tyenv):
365 return get_op_retty(self.op)
367 def typecheck(self, tyenv): # TODO change all this to use PyvexTypeErrorException
368 resty, (arg1ty, arg2ty, arg3ty, arg4ty) = op_arg_types(self.op)
369 arg1ty_real = self.args[0].typecheck(tyenv)
370 arg2ty_real = self.args[1].typecheck(tyenv)
371 arg3ty_real = self.args[2].typecheck(tyenv)
372 arg4ty_real = self.args[3].typecheck(tyenv)
373 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None or arg4ty_real is None:
374 return None
376 if arg1ty_real != arg1ty:
377 log.debug("First arg of %s must be %s", self.op, arg1ty)
378 return None
379 if arg2ty_real != arg2ty:
380 log.debug("Second arg of %s must be %s", self.op, arg2ty)
381 return None
382 if arg3ty_real != arg3ty:
383 log.debug("Third arg of %s must be %s", self.op, arg3ty)
384 return None
385 if arg4ty_real != arg4ty:
386 log.debug("Fourth arg of %s must be %s", self.op, arg4ty)
387 return None
389 return resty
392class Triop(IRExpr):
393 """
394 A ternary operation (3 arguments)
395 """
397 __slots__ = ["op", "args"]
399 tag = "Iex_Triop"
401 def __init__(self, op, args):
402 self.op = op
403 self.args = args
405 def _pp_str(self):
406 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
408 @property
409 def child_expressions(self):
410 expressions = sum((a.child_expressions for a in self.args), [])
411 expressions.extend(self.args)
412 return expressions
414 @staticmethod
415 def _from_c(c_expr):
416 return Triop(
417 get_enum_from_int(c_expr.Iex.Triop.details.op),
418 [
419 IRExpr._from_c(arg)
420 for arg in [c_expr.Iex.Triop.details.arg1, c_expr.Iex.Triop.details.arg2, c_expr.Iex.Triop.details.arg3]
421 ],
422 )
424 @staticmethod
425 def _to_c(expr):
426 return pvc.IRExpr_Triop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
428 def result_type(self, tyenv):
429 return get_op_retty(self.op)
431 def typecheck(self, tyenv):
432 resty, (arg1ty, arg2ty, arg3ty) = op_arg_types(self.op)
433 arg1ty_real = self.args[0].typecheck(tyenv)
434 arg2ty_real = self.args[1].typecheck(tyenv)
435 arg3ty_real = self.args[2].typecheck(tyenv)
436 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None:
437 return None
439 if arg1ty_real != arg1ty:
440 log.debug("First arg of %s must be %s", self.op, arg1ty)
441 return None
442 if arg2ty_real != arg2ty:
443 log.debug("Second arg of %s must be %s", self.op, arg2ty)
444 return None
445 if arg3ty_real != arg3ty:
446 log.debug("Third arg of %s must be %s", self.op, arg3ty)
447 return None
449 return resty
452class Binop(IRExpr):
453 """
454 A binary operation (2 arguments).
455 """
457 __slots__ = ["_op", "op_int", "args"]
459 tag = "Iex_Binop"
461 def __init__(self, op, args, op_int=None):
462 self.op_int = op_int
463 self.args = args
464 self._op = op if op is not None else None
466 def _pp_str(self):
467 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
469 @property
470 def op(self):
471 if self._op is None:
472 self._op = get_enum_from_int(self.op_int)
473 return self._op
475 @property
476 def child_expressions(self):
477 expressions = sum((a.child_expressions for a in self.args), [])
478 expressions.extend(self.args)
479 return expressions
481 @staticmethod
482 def _from_c(c_expr):
483 return Binop(
484 None,
485 [IRExpr._from_c(arg) for arg in [c_expr.Iex.Binop.arg1, c_expr.Iex.Binop.arg2]],
486 op_int=c_expr.Iex.Binop.op,
487 )
489 @staticmethod
490 def _to_c(expr):
491 return pvc.IRExpr_Binop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
493 def result_type(self, tyenv):
494 return get_op_retty(self.op)
496 def typecheck(self, tyenv):
497 arg1ty_real = self.args[0].typecheck(tyenv)
498 arg2ty_real = self.args[1].typecheck(tyenv)
500 resty, (arg1ty, arg2ty) = op_arg_types(self.op)
501 if arg1ty_real is None or arg2ty_real is None:
502 return None
504 if arg1ty_real != arg1ty:
505 log.debug("First arg of %s must be %s", self.op, arg1ty)
506 return None
507 if arg2ty_real != arg2ty:
508 log.debug("Second arg of %s must be %s", self.op, arg2ty)
509 return None
511 return resty
514class Unop(IRExpr):
515 """
516 A unary operation (1 argument).
517 """
519 __slots__ = ["op", "args"]
521 tag = "Iex_Unop"
523 def __init__(self, op, args):
524 self.op = op
525 self.args = args
527 def _pp_str(self):
528 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
530 @property
531 def child_expressions(self):
532 expressions = sum((a.child_expressions for a in self.args), [])
533 expressions.extend(self.args)
534 return expressions
536 @staticmethod
537 def _from_c(c_expr):
538 return Unop(get_enum_from_int(c_expr.Iex.Unop.op), [IRExpr._from_c(c_expr.Iex.Unop.arg)])
540 @staticmethod
541 def _to_c(expr):
542 return pvc.IRExpr_Unop(get_int_from_enum(expr.op), IRExpr._to_c(expr.args[0]))
544 def result_type(self, tyenv):
545 return get_op_retty(self.op)
547 def typecheck(self, tyenv):
548 resty, (arg1ty,) = op_arg_types(self.op)
549 arg1ty_real = self.args[0].typecheck(tyenv)
550 if arg1ty_real is None:
551 return None
553 if arg1ty_real != arg1ty:
554 log.debug("First arg of %s must be %s", self.op, arg1ty)
555 return None
557 return resty
560class Load(IRExpr):
561 """
562 A load from memory.
563 """
565 __slots__ = ["end", "ty", "addr"]
567 tag = "Iex_Load"
569 def __init__(self, end, ty, addr):
570 self.end = end
571 self.ty = ty
572 self.addr = addr
574 @property
575 def endness(self):
576 return self.end
578 @property
579 def type(self):
580 return self.ty
582 def _pp_str(self):
583 return f"LD{self.end[-2:].lower()}:{self.ty[4:]}({self.addr})"
585 @staticmethod
586 def _from_c(c_expr):
587 return Load(
588 get_enum_from_int(c_expr.Iex.Load.end),
589 get_enum_from_int(c_expr.Iex.Load.ty),
590 IRExpr._from_c(c_expr.Iex.Load.addr),
591 )
593 @staticmethod
594 def _to_c(expr):
595 return pvc.IRExpr_Load(get_int_from_enum(expr.end), get_int_from_enum(expr.ty), IRExpr._to_c(expr.addr))
597 def result_type(self, tyenv):
598 return self.ty
600 def typecheck(self, tyenv):
601 addrty = self.addr.typecheck(tyenv)
602 if addrty is None:
603 return None
604 if addrty != tyenv.wordty:
605 log.debug("Address must be word-sized")
606 return None
607 return self.ty
610class Const(IRExpr):
611 """
612 A constant expression.
613 """
615 __slots__ = ["_con"]
617 tag = "Iex_Const"
619 def __init__(self, con: "IRConst"):
620 self._con = con
622 def _pp_str(self):
623 return str(self.con)
625 @property
626 def con(self) -> "IRConst":
627 return self._con
629 @staticmethod
630 def _from_c(c_expr):
631 con = IRConst._from_c(c_expr.Iex.Const.con)
632 return Const.get_instance(con)
634 @staticmethod
635 def _to_c(expr):
636 return pvc.IRExpr_Const(IRConst._to_c(expr.con))
638 @staticmethod
639 def get_instance(con):
640 if con.value < 1024 and con.__class__ in _CONST_POOL:
641 return _CONST_POOL[con.__class__][con.value]
642 return Const(con)
644 def result_type(self, tyenv):
645 return self.con.type
648_CONST_POOL = {
649 U8: [Const(U8(i)) for i in range(0, 1024)],
650 U16: [Const(U16(i)) for i in range(0, 1024)],
651 U32: [Const(U32(i)) for i in range(0, 1024)],
652 U64: [Const(U64(i)) for i in range(0, 1024)],
653}
656class ITE(IRExpr):
657 """
658 An if-then-else expression.
659 """
661 __slots__ = ["cond", "iffalse", "iftrue"]
663 tag = "Iex_ITE"
665 def __init__(self, cond, iffalse, iftrue):
666 self.cond = cond
667 self.iffalse = iffalse
668 self.iftrue = iftrue
670 def _pp_str(self):
671 return f"ITE({self.cond},{self.iftrue},{self.iffalse})"
673 @staticmethod
674 def _from_c(c_expr):
675 return ITE(
676 IRExpr._from_c(c_expr.Iex.ITE.cond),
677 IRExpr._from_c(c_expr.Iex.ITE.iffalse),
678 IRExpr._from_c(c_expr.Iex.ITE.iftrue),
679 )
681 @staticmethod
682 def _to_c(expr):
683 return pvc.IRExpr_ITE(IRExpr._to_c(expr.cond), IRExpr._to_c(expr.iftrue), IRExpr._to_c(expr.iffalse))
685 def result_type(self, tyenv):
686 return self.iftrue.result_type(tyenv)
688 def typecheck(self, tyenv):
689 condty = self.cond.typecheck(tyenv)
690 falsety = self.iffalse.typecheck(tyenv)
691 truety = self.iftrue.typecheck(tyenv)
693 if condty is None or falsety is None or truety is None:
694 return None
696 if condty != "Ity_I1":
697 log.debug("guard must be Ity_I1")
698 return None
700 if falsety != truety:
701 log.debug("false condition must be same type as true condition")
702 return None
704 return falsety
707class CCall(IRExpr):
708 """
709 A call to a pure (no side-effects) helper C function.
710 """
712 __slots__ = ["retty", "cee", "args"]
714 tag = "Iex_CCall"
716 def __init__(self, retty, cee, args):
717 self.retty = retty
718 self.cee = cee
719 self.args = tuple(args)
721 @property
722 def ret_type(self):
723 return self.retty
725 @property
726 def callee(self):
727 return self.cee
729 def _pp_str(self):
730 return "{}({}):{}".format(self.cee, ",".join(str(a) for a in self.args), self.retty)
732 @property
733 def child_expressions(self):
734 expressions = sum((a.child_expressions for a in self.args), [])
735 expressions.extend(self.args)
736 return expressions
738 @staticmethod
739 def _from_c(c_expr):
740 i = 0
741 args = []
742 while True:
743 arg = c_expr.Iex.CCall.args[i]
744 if arg == ffi.NULL:
745 break
746 args.append(IRExpr._from_c(arg))
747 i += 1
749 return CCall(get_enum_from_int(c_expr.Iex.CCall.retty), IRCallee._from_c(c_expr.Iex.CCall.cee), tuple(args))
751 @staticmethod
752 def _to_c(expr):
753 args = [IRExpr._to_c(arg) for arg in expr.args]
754 mkIRExprVec = getattr(pvc, "mkIRExprVec_%d" % len(args))
755 return pvc.IRExpr_CCall(IRCallee._to_c(expr.cee), get_int_from_enum(expr.retty), mkIRExprVec(*args))
757 def result_type(self, tyenv):
758 return self.retty
761def get_op_retty(op):
762 return op_arg_types(op)[0]
765op_signatures: Dict[str, Tuple[str, Tuple[str, ...]]] = {}
768def _request_op_type_from_cache(op):
769 return op_signatures[op]
772def _request_op_type_from_libvex(op):
773 Ity_INVALID = 0x1100 # as defined in enum IRType in VEX
775 res_ty = ffi.new("IRType *")
776 arg_tys = [ffi.new("IRType *") for _ in range(4)]
777 # initialize all IRTypes to Ity_INVALID
778 for arg in arg_tys:
779 arg[0] = Ity_INVALID
780 pvc.typeOfPrimop(get_int_from_enum(op), res_ty, *arg_tys)
781 arg_ty_vals = [a[0] for a in arg_tys]
783 try:
784 numargs = arg_ty_vals.index(Ity_INVALID)
785 except ValueError:
786 numargs = 4
787 args_tys_list = [get_enum_from_int(arg_ty_vals[i]) for i in range(numargs)]
789 op_ty_sig = (get_enum_from_int(res_ty[0]), tuple(args_tys_list))
790 op_signatures[op] = op_ty_sig
791 return op_ty_sig
794class PyvexOpMatchException(Exception):
795 pass
798class PyvexTypeErrorException(Exception):
799 pass
802def int_type_for_size(size):
803 return "Ity_I%d" % size
806# precompiled regexes
807unop_signature_re = re.compile(r"Iop_(Not|Ctz|Clz)(?P<size>\d+)$")
808binop_signature_re = re.compile(r"Iop_(Add|Sub|Mul|Xor|Or|And|Div[SU]|Mod)(?P<size>\d+)$")
809shift_signature_re = re.compile(r"Iop_(Shl|Shr|Sar)(?P<size>\d+)$")
810cmp_signature_re_1 = re.compile(r"Iop_Cmp(EQ|NE)(?P<size>\d+)$")
811cmp_signature_re_2 = re.compile(r"Iop_Cmp(GT|GE|LT|LE)(?P<size>\d+)[SU]$")
812mull_signature_re = re.compile(r"Iop_Mull[SU](?P<size>\d+)$")
813half_signature_re = re.compile(r"Iop_DivMod[SU](?P<fullsize>\d+)to(?P<halfsize>\d+)$")
814cast_signature_re = re.compile(r"Iop_(?P<srcsize>\d+)(U|S|HI|HL)?to(?P<dstsize>\d+)")
817def unop_signature(op):
818 m = unop_signature_re.match(op)
819 if m is None:
820 raise PyvexOpMatchException()
821 size = int(m.group("size"))
822 size_type = int_type_for_size(size)
823 return size_type, (size_type,)
826def binop_signature(op):
827 m = binop_signature_re.match(op)
828 if m is None:
829 raise PyvexOpMatchException()
830 size = int(m.group("size"))
831 size_type = int_type_for_size(size)
832 return (size_type, (size_type, size_type))
835def shift_signature(op):
836 m = shift_signature_re.match(op)
837 if m is None:
838 raise PyvexOpMatchException()
839 size = int(m.group("size"))
840 if size > 255:
841 raise PyvexTypeErrorException("Cannot apply shift operation to %d size int because shift index is 8-bit" % size)
842 size_type = int_type_for_size(size)
843 return (size_type, (size_type, int_type_for_size(8)))
846def cmp_signature(op):
847 m = cmp_signature_re_1.match(op)
848 m2 = cmp_signature_re_2.match(op)
849 if (m is None) == (m2 is None):
850 raise PyvexOpMatchException()
851 mfound = m if m is not None else m2
852 size = int(mfound.group("size"))
853 size_type = int_type_for_size(size)
854 return (int_type_for_size(1), (size_type, size_type))
857def mull_signature(op):
858 m = mull_signature_re.match(op)
859 if m is None:
860 raise PyvexOpMatchException()
861 size = int(m.group("size"))
862 size_type = int_type_for_size(size)
863 doubled_size_type = int_type_for_size(2 * size)
864 return (doubled_size_type, (size_type, size_type))
867def half_signature(op):
868 m = half_signature_re.match(op)
869 if m is None:
870 raise PyvexOpMatchException()
871 fullsize = int(m.group("fullsize"))
872 halfsize = int(m.group("halfsize"))
873 if halfsize * 2 != fullsize:
874 raise PyvexTypeErrorException("Invalid Instruction %s: Type 1 must be twice the size of type 2" % op)
875 fullsize_type = int_type_for_size(fullsize)
876 halfsize_type = int_type_for_size(halfsize)
877 return (fullsize_type, (fullsize_type, halfsize_type))
880def cast_signature(op):
881 m = cast_signature_re.match(op)
882 if m is None:
883 raise PyvexOpMatchException()
884 src_type = int_type_for_size(int(m.group("srcsize")))
885 dst_type = int_type_for_size(int(m.group("dstsize")))
886 return (dst_type, (src_type,))
889polymorphic_op_processors = [
890 unop_signature,
891 binop_signature,
892 shift_signature,
893 cmp_signature,
894 mull_signature,
895 half_signature,
896 cast_signature,
897]
900def _request_polymorphic_op_type(op):
901 for polymorphic_signature in polymorphic_op_processors:
902 try:
903 op_ty_sig = polymorphic_signature(op)
904 break
905 except PyvexOpMatchException:
906 continue
907 else:
908 raise PyvexOpMatchException("Op %s not recognized" % op)
909 return op_ty_sig
912_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type]
915def op_arg_types(op):
916 for _request_func in _request_funcs:
917 try:
918 return _request_func(op)
919 except KeyError:
920 continue
921 raise ValueError("Cannot find type of op %s" % op)
924_globals = globals().copy()
925#
926# Mapping from tag strings/enums to IRExpr classes
927#
928tag_to_expr_mapping = {}
929enum_to_expr_mapping = {}
930tag_count = 0
931cls = None
932for cls in _globals.values():
933 if type(cls) is type and issubclass(cls, IRExpr) and cls is not IRExpr:
934 tag_to_expr_mapping[cls.tag] = cls
935 enum_to_expr_mapping[get_int_from_enum(cls.tag)] = cls
936 cls.tag_int = tag_count
937 tag_count += 1
938del cls
941def tag_to_expr_class(tag):
942 """
943 Convert a tag string to the corresponding IRExpr class type.
945 :param str tag: The tag string.
946 :return: A class.
947 :rtype: type
948 """
950 try:
951 return tag_to_expr_mapping[tag]
952 except KeyError:
953 raise KeyError("Cannot find expression class for type %s." % tag)
956def enum_to_expr_class(tag_enum):
957 """
958 Convert a tag enum to the corresponding IRExpr class.
960 :param int tag_enum: The tag enum.
961 :return: A class.
962 :rtype: type
963 """
965 try:
966 return enum_to_expr_mapping[tag_enum]
967 except KeyError:
968 raise KeyError("Cannot find expression class for type %s." % get_enum_from_int(tag_enum))