Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/pyvex/expr.py: 73%
606 statements
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
« prev ^ index » next coverage.py v7.3.1, created at 2023-09-25 06:15 +0000
1import logging
2import re
3from typing import List, Optional
5from archinfo import RegisterOffset, TmpVar
7from .const import U8, U16, U32, U64, IRConst, get_type_size
8from .enums import IRCallee, IRRegArray, VEXObject, get_enum_from_int, get_int_from_enum
9from .errors import PyVEXError
10from .native import ffi, pvc
12log = logging.getLogger("pyvex.expr")
15class IRExpr(VEXObject):
16 """
17 IR expressions in VEX represent operations without side effects.
18 """
20 __slots__ = []
22 tag: Optional[str] = None
23 tag_int = 0 # set automatically at bottom of file
25 def pp(self):
26 print(self.__str__())
28 @property
29 def child_expressions(self) -> List["IRExpr"]:
30 """
31 A list of all of the expressions that this expression ends up evaluating.
32 """
33 expressions = []
34 for k in self.__slots__:
35 v = getattr(self, k)
36 if isinstance(v, IRExpr):
37 expressions.append(v)
38 expressions.extend(v.child_expressions)
39 return expressions
41 @property
42 def constants(self):
43 """
44 A list of all of the constants that this expression ends up using.
45 """
46 constants = []
47 for k in self.__slots__:
48 v = getattr(self, k)
49 if isinstance(v, IRExpr):
50 constants.extend(v.constants)
51 elif isinstance(v, IRConst):
52 constants.append(v)
53 return constants
55 def result_size(self, tyenv):
56 return get_type_size(self.result_type(tyenv))
58 def result_type(self, tyenv):
59 raise NotImplementedError()
61 def replace_expression(self, replacements):
62 """
63 Replace child expressions in-place.
65 :param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with
66 :return: None
67 """
69 for k in self.__slots__:
70 v = getattr(self, k)
71 if isinstance(v, IRExpr) and v in replacements:
72 setattr(self, k, replacements.get(v))
73 elif isinstance(v, list):
74 # Replace the instance in the list
75 for i, expr_ in enumerate(v):
76 if isinstance(expr_, IRExpr) and expr_ in replacements:
77 v[i] = replacements.get(expr_)
78 elif type(v) is tuple:
79 # Rebuild the tuple
80 _lst = []
81 replaced = False
82 for i, expr_ in enumerate(v):
83 if isinstance(expr_, IRExpr) and expr_ in replacements:
84 _lst.append(replacements.get(expr_))
85 replaced = True
86 else:
87 _lst.append(expr_)
88 if replaced:
89 setattr(self, k, tuple(_lst))
90 elif isinstance(v, IRExpr):
91 v.replace_expression(replacements)
93 @staticmethod
94 def _from_c(c_expr) -> "IRExpr":
95 if c_expr == ffi.NULL or c_expr[0] == ffi.NULL:
96 return None
98 try:
99 return enum_to_expr_class(c_expr.tag)._from_c(c_expr)
100 except KeyError:
101 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % get_enum_from_int(c_expr.tag))
103 _translate = _from_c
105 @staticmethod
106 def _to_c(expr):
107 try:
108 return tag_to_expr_class(expr.tag)._to_c(expr)
109 except KeyError:
110 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % expr.tag)
112 def typecheck(self, tyenv):
113 return self.result_type(tyenv)
116class Binder(IRExpr):
117 """
118 Used only in pattern matching within Vex. Should not be seen outside of Vex.
119 """
121 __slots__ = ["binder"]
123 tag = "Iex_Binder"
125 def __init__(self, binder):
126 self.binder = binder
128 def __str__(self):
129 return "Binder"
131 @staticmethod
132 def _from_c(c_expr):
133 return Binder(c_expr.iex.Binder.binder)
135 @staticmethod
136 def _to_c(expr):
137 return pvc.IRExpr_Binder(expr.binder)
139 def result_type(self, tyenv):
140 return "Ity_INVALID"
143class VECRET(IRExpr):
144 tag = "Iex_VECRET"
146 __slots__ = []
148 def __str__(self):
149 return "VECRET"
151 @staticmethod
152 def _from_c(c_expr):
153 return VECRET()
155 @staticmethod
156 def _to_c(expr):
157 return pvc.IRExpr_VECRET()
159 def result_type(self, tyenv):
160 return "Ity_INVALID"
163class GSPTR(IRExpr):
164 __slots__ = []
166 tag = "Iex_GSPTR"
168 def __str__(self):
169 return "GSPTR"
171 @staticmethod
172 def _from_c(c_expr):
173 return GSPTR()
175 @staticmethod
176 def _to_c(expr):
177 return pvc.IRExpr_GSPTR()
179 def result_type(self, tyenv):
180 return "Ity_INVALID"
183class GetI(IRExpr):
184 """
185 Read a guest register at a non-fixed offset in the guest state.
186 """
188 __slots__ = ["descr", "ix", "bias"]
190 tag = "Iex_GetI"
192 def __init__(self, descr, ix, bias):
193 self.descr = descr
194 self.ix = ix
195 self.bias = bias
197 @property
198 def description(self):
199 return self.descr
201 @property
202 def index(self):
203 return self.ix
205 def __str__(self):
206 return f"GetI({self.descr})[{self.ix},{self.bias}]"
208 @staticmethod
209 def _from_c(c_expr):
210 descr = IRRegArray._from_c(c_expr.Iex.GetI.descr)
211 ix = IRExpr._from_c(c_expr.Iex.GetI.ix)
212 bias = c_expr.Iex.GetI.bias
213 return GetI(descr, ix, bias)
215 @staticmethod
216 def _to_c(expr):
217 return pvc.IRExpr_GetI(IRRegArray._to_c(expr.descr), IRExpr._to_c(expr.ix), expr.bias)
219 def result_type(self, tyenv):
220 return self.descr.elemTy
223class RdTmp(IRExpr):
224 """
225 Read the value held by a temporary.
226 """
228 __slots__ = ["_tmp"]
230 tag = "Iex_RdTmp"
232 def __init__(self, tmp: TmpVar):
233 self._tmp = tmp
235 def __str__(self):
236 return "t%d" % self.tmp
238 @property
239 def tmp(self) -> TmpVar:
240 return self._tmp
242 @staticmethod
243 def _from_c(c_expr):
244 tmp = c_expr.Iex.RdTmp.tmp
245 return RdTmp.get_instance(tmp)
247 @staticmethod
248 def _to_c(expr):
249 return pvc.IRExpr_RdTmp(expr.tmp)
251 @staticmethod
252 def get_instance(tmp):
253 if tmp < 1024:
254 # for small tmp reads, they are cached and are only created once globally
255 return _RDTMP_POOL[tmp]
256 return RdTmp(tmp)
258 def replace_expression(self, replacements):
259 # RdTmp is one of the terminal IRExprs, which cannot be replaced.
260 pass
262 def result_type(self, tyenv):
263 return tyenv.lookup(self.tmp)
265 def __hash__(self):
266 return 133700 + self._tmp
269_RDTMP_POOL = list(RdTmp(i) for i in range(0, 1024))
272class Get(IRExpr):
273 """
274 Read a guest register, at a fixed offset in the guest state.
275 """
277 __slots__ = ["offset", "ty_int"]
279 tag = "Iex_Get"
281 def __init__(self, offset: RegisterOffset, ty: str, ty_int: Optional[int] = None):
282 self.offset = offset
283 if ty_int is None:
284 self.ty_int = get_int_from_enum(ty)
285 else:
286 self.ty_int = ty_int
288 @property
289 def ty(self):
290 return get_enum_from_int(self.ty_int)
292 @property
293 def type(self):
294 return get_enum_from_int(self.ty_int)
296 def __str__(self, reg_name=None):
297 if reg_name:
298 return f"GET:{self.ty[4:]}({reg_name})"
299 else:
300 return f"GET:{self.ty[4:]}(offset={self.offset})"
302 @staticmethod
303 def _from_c(c_expr):
304 return Get(c_expr.Iex.Get.offset, get_enum_from_int(c_expr.Iex.Get.ty))
306 @staticmethod
307 def _to_c(expr):
308 return pvc.IRExpr_Get(expr.offset, expr.ty_int)
310 def result_type(self, tyenv):
311 return self.ty
313 def __hash__(self):
314 return (self.offset << 8) | self.ty_int
317class Qop(IRExpr):
318 """
319 A quaternary operation (4 arguments).
320 """
322 __slots__ = ["op", "args"]
324 tag = "Iex_Qop"
326 def __init__(self, op, args):
327 self.op = op
328 self.args = args
330 def __str__(self):
331 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
333 @property
334 def child_expressions(self):
335 expressions = sum((a.child_expressions for a in self.args), [])
336 expressions.extend(self.args)
337 return expressions
339 @staticmethod
340 def _from_c(c_expr):
341 return Qop(
342 get_enum_from_int(c_expr.Iex.Qop.details.op),
343 [
344 IRExpr._from_c(arg)
345 for arg in [
346 c_expr.Iex.Qop.details.arg1,
347 c_expr.Iex.Qop.details.arg2,
348 c_expr.Iex.Qop.details.arg3,
349 c_expr.Iex.Qop.details.arg4,
350 ]
351 ],
352 )
354 @staticmethod
355 def _to_c(expr):
356 return pvc.IRExpr_Qop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
358 def result_type(self, tyenv):
359 return get_op_retty(self.op)
361 def typecheck(self, tyenv): # TODO change all this to use PyvexTypeErrorException
362 resty, (arg1ty, arg2ty, arg3ty, arg4ty) = op_arg_types(self.op)
363 arg1ty_real = self.args[0].typecheck(tyenv)
364 arg2ty_real = self.args[1].typecheck(tyenv)
365 arg3ty_real = self.args[2].typecheck(tyenv)
366 arg4ty_real = self.args[3].typecheck(tyenv)
367 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None or arg4ty_real is None:
368 return None
370 if arg1ty_real != arg1ty:
371 log.debug("First arg of %s must be %s", self.op, arg1ty)
372 return None
373 if arg2ty_real != arg2ty:
374 log.debug("Second arg of %s must be %s", self.op, arg2ty)
375 return None
376 if arg3ty_real != arg3ty:
377 log.debug("Third arg of %s must be %s", self.op, arg3ty)
378 return None
379 if arg4ty_real != arg4ty:
380 log.debug("Fourth arg of %s must be %s", self.op, arg4ty)
381 return None
383 return resty
386class Triop(IRExpr):
387 """
388 A ternary operation (3 arguments)
389 """
391 __slots__ = ["op", "args"]
393 tag = "Iex_Triop"
395 def __init__(self, op, args):
396 self.op = op
397 self.args = args
399 def __str__(self):
400 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
402 @property
403 def child_expressions(self):
404 expressions = sum((a.child_expressions for a in self.args), [])
405 expressions.extend(self.args)
406 return expressions
408 @staticmethod
409 def _from_c(c_expr):
410 return Triop(
411 get_enum_from_int(c_expr.Iex.Triop.details.op),
412 [
413 IRExpr._from_c(arg)
414 for arg in [c_expr.Iex.Triop.details.arg1, c_expr.Iex.Triop.details.arg2, c_expr.Iex.Triop.details.arg3]
415 ],
416 )
418 @staticmethod
419 def _to_c(expr):
420 return pvc.IRExpr_Triop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
422 def result_type(self, tyenv):
423 return get_op_retty(self.op)
425 def typecheck(self, tyenv):
426 resty, (arg1ty, arg2ty, arg3ty) = op_arg_types(self.op)
427 arg1ty_real = self.args[0].typecheck(tyenv)
428 arg2ty_real = self.args[1].typecheck(tyenv)
429 arg3ty_real = self.args[2].typecheck(tyenv)
430 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None:
431 return None
433 if arg1ty_real != arg1ty:
434 log.debug("First arg of %s must be %s", self.op, arg1ty)
435 return None
436 if arg2ty_real != arg2ty:
437 log.debug("Second arg of %s must be %s", self.op, arg2ty)
438 return None
439 if arg3ty_real != arg3ty:
440 log.debug("Third arg of %s must be %s", self.op, arg3ty)
441 return None
443 return resty
446class Binop(IRExpr):
447 """
448 A binary operation (2 arguments).
449 """
451 __slots__ = ["_op", "op_int", "args"]
453 tag = "Iex_Binop"
455 def __init__(self, op, args, op_int=None):
456 self.op_int = op_int
457 self.args = args
458 self._op = op if op is not None else None
460 def __str__(self):
461 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
463 @property
464 def op(self):
465 if self._op is None:
466 self._op = get_enum_from_int(self.op_int)
467 return self._op
469 @property
470 def child_expressions(self):
471 expressions = sum((a.child_expressions for a in self.args), [])
472 expressions.extend(self.args)
473 return expressions
475 @staticmethod
476 def _from_c(c_expr):
477 return Binop(
478 None,
479 [IRExpr._from_c(arg) for arg in [c_expr.Iex.Binop.arg1, c_expr.Iex.Binop.arg2]],
480 op_int=c_expr.Iex.Binop.op,
481 )
483 @staticmethod
484 def _to_c(expr):
485 return pvc.IRExpr_Binop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
487 def result_type(self, tyenv):
488 return get_op_retty(self.op)
490 def typecheck(self, tyenv):
491 arg1ty_real = self.args[0].typecheck(tyenv)
492 arg2ty_real = self.args[1].typecheck(tyenv)
494 resty, (arg1ty, arg2ty) = op_arg_types(self.op)
495 if arg1ty_real is None or arg2ty_real is None:
496 return None
498 if arg1ty_real != arg1ty:
499 log.debug("First arg of %s must be %s", self.op, arg1ty)
500 return None
501 if arg2ty_real != arg2ty:
502 log.debug("Second arg of %s must be %s", self.op, arg2ty)
503 return None
505 return resty
508class Unop(IRExpr):
509 """
510 A unary operation (1 argument).
511 """
513 __slots__ = ["op", "args"]
515 tag = "Iex_Unop"
517 def __init__(self, op, args):
518 self.op = op
519 self.args = args
521 def __str__(self):
522 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
524 @property
525 def child_expressions(self):
526 expressions = sum((a.child_expressions for a in self.args), [])
527 expressions.extend(self.args)
528 return expressions
530 @staticmethod
531 def _from_c(c_expr):
532 return Unop(get_enum_from_int(c_expr.Iex.Unop.op), [IRExpr._from_c(c_expr.Iex.Unop.arg)])
534 @staticmethod
535 def _to_c(expr):
536 return pvc.IRExpr_Unop(get_int_from_enum(expr.op), IRExpr._to_c(expr.args[0]))
538 def result_type(self, tyenv):
539 return get_op_retty(self.op)
541 def typecheck(self, tyenv):
542 resty, (arg1ty,) = op_arg_types(self.op)
543 arg1ty_real = self.args[0].typecheck(tyenv)
544 if arg1ty_real is None:
545 return None
547 if arg1ty_real != arg1ty:
548 log.debug("First arg of %s must be %s", self.op, arg1ty)
549 return None
551 return resty
554class Load(IRExpr):
555 """
556 A load from memory.
557 """
559 __slots__ = ["end", "ty", "addr"]
561 tag = "Iex_Load"
563 def __init__(self, end, ty, addr):
564 self.end = end
565 self.ty = ty
566 self.addr = addr
568 @property
569 def endness(self):
570 return self.end
572 @property
573 def type(self):
574 return self.ty
576 def __str__(self):
577 return f"LD{self.end[-2:].lower()}:{self.ty[4:]}({self.addr})"
579 @staticmethod
580 def _from_c(c_expr):
581 return Load(
582 get_enum_from_int(c_expr.Iex.Load.end),
583 get_enum_from_int(c_expr.Iex.Load.ty),
584 IRExpr._from_c(c_expr.Iex.Load.addr),
585 )
587 @staticmethod
588 def _to_c(expr):
589 return pvc.IRExpr_Load(get_int_from_enum(expr.end), get_int_from_enum(expr.ty), IRExpr._to_c(expr.addr))
591 def result_type(self, tyenv):
592 return self.ty
594 def typecheck(self, tyenv):
595 addrty = self.addr.typecheck(tyenv)
596 if addrty is None:
597 return None
598 if addrty != tyenv.wordty:
599 log.debug("Address must be word-sized")
600 return None
601 return self.ty
604class Const(IRExpr):
605 """
606 A constant expression.
607 """
609 __slots__ = ["_con"]
611 tag = "Iex_Const"
613 def __init__(self, con: "IRConst"):
614 self._con = con
616 def __str__(self):
617 return str(self.con)
619 @property
620 def con(self) -> "IRConst":
621 return self._con
623 @staticmethod
624 def _from_c(c_expr):
625 con = IRConst._from_c(c_expr.Iex.Const.con)
626 return Const.get_instance(con)
628 @staticmethod
629 def _to_c(expr):
630 return pvc.IRExpr_Const(IRConst._to_c(expr.con))
632 @staticmethod
633 def get_instance(con):
634 if con.value < 1024 and con.__class__ in _CONST_POOL:
635 return _CONST_POOL[con.__class__][con.value]
636 return Const(con)
638 def result_type(self, tyenv):
639 return self.con.type
642_CONST_POOL = {
643 U8: [Const(U8(i)) for i in range(0, 1024)],
644 U16: [Const(U16(i)) for i in range(0, 1024)],
645 U32: [Const(U32(i)) for i in range(0, 1024)],
646 U64: [Const(U64(i)) for i in range(0, 1024)],
647}
650class ITE(IRExpr):
651 """
652 An if-then-else expression.
653 """
655 __slots__ = ["cond", "iffalse", "iftrue"]
657 tag = "Iex_ITE"
659 def __init__(self, cond, iffalse, iftrue):
660 self.cond = cond
661 self.iffalse = iffalse
662 self.iftrue = iftrue
664 def __str__(self):
665 return f"ITE({self.cond},{self.iftrue},{self.iffalse})"
667 @staticmethod
668 def _from_c(c_expr):
669 return ITE(
670 IRExpr._from_c(c_expr.Iex.ITE.cond),
671 IRExpr._from_c(c_expr.Iex.ITE.iffalse),
672 IRExpr._from_c(c_expr.Iex.ITE.iftrue),
673 )
675 @staticmethod
676 def _to_c(expr):
677 return pvc.IRExpr_ITE(IRExpr._to_c(expr.cond), IRExpr._to_c(expr.iftrue), IRExpr._to_c(expr.iffalse))
679 def result_type(self, tyenv):
680 return self.iftrue.result_type(tyenv)
682 def typecheck(self, tyenv):
683 condty = self.cond.typecheck(tyenv)
684 falsety = self.iffalse.typecheck(tyenv)
685 truety = self.iftrue.typecheck(tyenv)
687 if condty is None or falsety is None or truety is None:
688 return None
690 if condty != "Ity_I1":
691 log.debug("guard must be Ity_I1")
692 return None
694 if falsety != truety:
695 log.debug("false condition must be same type as true condition")
696 return None
698 return falsety
701class CCall(IRExpr):
702 """
703 A call to a pure (no side-effects) helper C function.
704 """
706 __slots__ = ["retty", "cee", "args"]
708 tag = "Iex_CCall"
710 def __init__(self, retty, cee, args):
711 self.retty = retty
712 self.cee = cee
713 self.args = tuple(args)
715 @property
716 def ret_type(self):
717 return self.retty
719 @property
720 def callee(self):
721 return self.cee
723 def __str__(self):
724 return "{}({}):{}".format(self.cee, ",".join(str(a) for a in self.args), self.retty)
726 @property
727 def child_expressions(self):
728 expressions = sum((a.child_expressions for a in self.args), [])
729 expressions.extend(self.args)
730 return expressions
732 @staticmethod
733 def _from_c(c_expr):
734 i = 0
735 args = []
736 while True:
737 arg = c_expr.Iex.CCall.args[i]
738 if arg == ffi.NULL:
739 break
740 args.append(IRExpr._from_c(arg))
741 i += 1
743 return CCall(get_enum_from_int(c_expr.Iex.CCall.retty), IRCallee._from_c(c_expr.Iex.CCall.cee), tuple(args))
745 @staticmethod
746 def _to_c(expr):
747 args = [IRExpr._to_c(arg) for arg in expr.args]
748 mkIRExprVec = getattr(pvc, "mkIRExprVec_%d" % len(args))
749 return pvc.IRExpr_CCall(IRCallee._to_c(expr.cee), get_int_from_enum(expr.retty), mkIRExprVec(*args))
751 def result_type(self, tyenv):
752 return self.retty
755def get_op_retty(op):
756 return op_arg_types(op)[0]
759op_signatures = {}
762def _request_op_type_from_cache(op):
763 return op_signatures[op]
766def _request_op_type_from_libvex(op):
767 Ity_INVALID = 0x1100 # as defined in enum IRType in VEX
769 res_ty = ffi.new("IRType *")
770 arg_tys = [ffi.new("IRType *") for _ in range(4)]
771 # initialize all IRTypes to Ity_INVALID
772 for arg in arg_tys:
773 arg[0] = Ity_INVALID
774 pvc.typeOfPrimop(get_int_from_enum(op), res_ty, *arg_tys)
775 arg_ty_vals = [a[0] for a in arg_tys]
777 try:
778 numargs = arg_ty_vals.index(Ity_INVALID)
779 except ValueError:
780 numargs = 4
781 args_tys_list = [get_enum_from_int(arg_ty_vals[i]) for i in range(numargs)]
783 op_ty_sig = (get_enum_from_int(res_ty[0]), tuple(args_tys_list))
784 op_signatures[op] = op_ty_sig
785 return op_ty_sig
788class PyvexOpMatchException(Exception):
789 pass
792class PyvexTypeErrorException(Exception):
793 pass
796def int_type_for_size(size):
797 return "Ity_I%d" % size
800# precompiled regexes
801unop_signature_re = re.compile(r"Iop_(Not|Ctz|Clz)(?P<size>\d+)$")
802binop_signature_re = re.compile(r"Iop_(Add|Sub|Mul|Xor|Or|And|Div[SU]|Mod)(?P<size>\d+)$")
803shift_signature_re = re.compile(r"Iop_(Shl|Shr|Sar)(?P<size>\d+)$")
804cmp_signature_re_1 = re.compile(r"Iop_Cmp(EQ|NE)(?P<size>\d+)$")
805cmp_signature_re_2 = re.compile(r"Iop_Cmp(GT|GE|LT|LE)(?P<size>\d+)[SU]$")
806mull_signature_re = re.compile(r"Iop_Mull[SU](?P<size>\d+)$")
807half_signature_re = re.compile(r"Iop_DivMod[SU](?P<fullsize>\d+)to(?P<halfsize>\d+)$")
808cast_signature_re = re.compile(r"Iop_(?P<srcsize>\d+)(U|S|HI|HL)?to(?P<dstsize>\d+)")
811def unop_signature(op):
812 m = unop_signature_re.match(op)
813 if m is None:
814 raise PyvexOpMatchException()
815 size = int(m.group("size"))
816 size_type = int_type_for_size(size)
817 return size_type, (size_type,)
820def binop_signature(op):
821 m = binop_signature_re.match(op)
822 if m is None:
823 raise PyvexOpMatchException()
824 size = int(m.group("size"))
825 size_type = int_type_for_size(size)
826 return (size_type, (size_type, size_type))
829def shift_signature(op):
830 m = shift_signature_re.match(op)
831 if m is None:
832 raise PyvexOpMatchException()
833 size = int(m.group("size"))
834 if size > 255:
835 raise PyvexTypeErrorException("Cannot apply shift operation to %d size int because shift index is 8-bit" % size)
836 size_type = int_type_for_size(size)
837 return (size_type, (size_type, int_type_for_size(8)))
840def cmp_signature(op):
841 m = cmp_signature_re_1.match(op)
842 m2 = cmp_signature_re_2.match(op)
843 if (m is None) == (m2 is None):
844 raise PyvexOpMatchException()
845 mfound = m if m is not None else m2
846 size = int(mfound.group("size"))
847 size_type = int_type_for_size(size)
848 return (int_type_for_size(1), (size_type, size_type))
851def mull_signature(op):
852 m = mull_signature_re.match(op)
853 if m is None:
854 raise PyvexOpMatchException()
855 size = int(m.group("size"))
856 size_type = int_type_for_size(size)
857 doubled_size_type = int_type_for_size(2 * size)
858 return (doubled_size_type, (size_type, size_type))
861def half_signature(op):
862 m = half_signature_re.match(op)
863 if m is None:
864 raise PyvexOpMatchException()
865 fullsize = int(m.group("fullsize"))
866 halfsize = int(m.group("halfsize"))
867 if halfsize * 2 != fullsize:
868 raise PyvexTypeErrorException("Invalid Instruction %s: Type 1 must be twice the size of type 2" % op)
869 fullsize_type = int_type_for_size(fullsize)
870 halfsize_type = int_type_for_size(halfsize)
871 return (fullsize_type, (fullsize_type, halfsize_type))
874def cast_signature(op):
875 m = cast_signature_re.match(op)
876 if m is None:
877 raise PyvexOpMatchException()
878 src_type = int_type_for_size(int(m.group("srcsize")))
879 dst_type = int_type_for_size(int(m.group("dstsize")))
880 return (dst_type, (src_type,))
883polymorphic_op_processors = [
884 unop_signature,
885 binop_signature,
886 shift_signature,
887 cmp_signature,
888 mull_signature,
889 half_signature,
890 cast_signature,
891]
894def _request_polymorphic_op_type(op):
895 for polymorphic_signature in polymorphic_op_processors:
896 try:
897 op_ty_sig = polymorphic_signature(op)
898 break
899 except PyvexOpMatchException:
900 continue
901 else:
902 raise PyvexOpMatchException("Op %s not recognized" % op)
903 return op_ty_sig
906_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type]
909def op_arg_types(op):
910 for _request_func in _request_funcs:
911 try:
912 return _request_func(op)
913 except KeyError:
914 continue
915 raise ValueError("Cannot find type of op %s" % op)
918_globals = globals().copy()
919#
920# Mapping from tag strings/enums to IRExpr classes
921#
922tag_to_expr_mapping = {}
923enum_to_expr_mapping = {}
924tag_count = 0
925cls = None
926for cls in _globals.values():
927 if type(cls) is type and issubclass(cls, IRExpr) and cls is not IRExpr:
928 tag_to_expr_mapping[cls.tag] = cls
929 enum_to_expr_mapping[get_int_from_enum(cls.tag)] = cls
930 cls.tag_int = tag_count
931 tag_count += 1
932del cls
935def tag_to_expr_class(tag):
936 """
937 Convert a tag string to the corresponding IRExpr class type.
939 :param str tag: The tag string.
940 :return: A class.
941 :rtype: type
942 """
944 try:
945 return tag_to_expr_mapping[tag]
946 except KeyError:
947 raise KeyError("Cannot find expression class for type %s." % tag)
950def enum_to_expr_class(tag_enum):
951 """
952 Convert a tag enum to the corresponding IRExpr class.
954 :param int tag_enum: The tag enum.
955 :return: A class.
956 :rtype: type
957 """
959 try:
960 return enum_to_expr_mapping[tag_enum]
961 except KeyError:
962 raise KeyError("Cannot find expression class for type %s." % get_enum_from_int(tag_enum))