Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyvex/expr.py: 72%
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
1from __future__ import annotations
3import logging
4import re
5from typing import TYPE_CHECKING
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
12if TYPE_CHECKING:
13 from .block import IRTypeEnv
15log = logging.getLogger("pyvex.expr")
18class IRExpr(VEXObject):
19 """
20 IR expressions in VEX represent operations without side effects.
21 """
23 __slots__ = []
25 tag: str | None = None
26 tag_int = 0 # set automatically at bottom of file
28 def pp(self):
29 print(str(self))
31 def __str__(self):
32 return self._pp_str()
34 def _pp_str(self) -> str:
35 raise NotImplementedError
37 @property
38 def child_expressions(self) -> list[IRExpr]:
39 """
40 A list of all of the expressions that this expression ends up evaluating.
41 """
42 expressions = []
43 for k in self.__slots__:
44 v = getattr(self, k)
45 if isinstance(v, IRExpr):
46 expressions.append(v)
47 expressions.extend(v.child_expressions)
48 return expressions
50 @property
51 def constants(self):
52 """
53 A list of all of the constants that this expression ends up using.
54 """
55 constants = []
56 for k in self.__slots__:
57 v = getattr(self, k)
58 if isinstance(v, IRExpr):
59 constants.extend(v.constants)
60 elif isinstance(v, IRConst):
61 constants.append(v)
62 return constants
64 def result_size(self, tyenv: IRTypeEnv):
65 return get_type_size(self.result_type(tyenv))
67 def result_type(self, tyenv: IRTypeEnv):
68 raise NotImplementedError()
70 def replace_expression(self, replacements):
71 """
72 Replace child expressions in-place.
74 :param Dict[IRExpr, IRExpr] replacements: A mapping from expression-to-find to expression-to-replace-with
75 :return: None
76 """
78 for k in self.__slots__:
79 v = getattr(self, k)
80 if isinstance(v, IRExpr) and v in replacements:
81 setattr(self, k, replacements.get(v))
82 elif isinstance(v, list):
83 # Replace the instance in the list
84 for i, expr_ in enumerate(v):
85 if isinstance(expr_, IRExpr) and expr_ in replacements:
86 v[i] = replacements.get(expr_)
87 elif type(v) is tuple:
88 # Rebuild the tuple
89 _lst = []
90 replaced = False
91 for i, expr_ in enumerate(v):
92 if isinstance(expr_, IRExpr) and expr_ in replacements:
93 _lst.append(replacements.get(expr_))
94 replaced = True
95 else:
96 _lst.append(expr_)
97 if replaced:
98 setattr(self, k, tuple(_lst))
99 elif isinstance(v, IRExpr):
100 v.replace_expression(replacements)
102 @staticmethod
103 def _from_c(c_expr) -> IRExpr | None:
104 if c_expr == ffi.NULL or c_expr[0] == ffi.NULL:
105 return None
107 try:
108 return enum_to_expr_class(c_expr.tag)._from_c(c_expr)
109 except KeyError:
110 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % get_enum_from_int(c_expr.tag))
112 _translate = _from_c
114 @staticmethod
115 def _to_c(expr):
116 try:
117 return tag_to_expr_class(expr.tag)._to_c(expr)
118 except KeyError:
119 raise PyVEXError("Unknown/unsupported IRExprTag %s\n" % expr.tag)
121 def typecheck(self, tyenv):
122 return self.result_type(tyenv)
125class Binder(IRExpr):
126 """
127 Used only in pattern matching within Vex. Should not be seen outside of Vex.
128 """
130 __slots__ = ["binder"]
132 tag = "Iex_Binder"
134 def __init__(self, binder):
135 self.binder = binder
137 def _pp_str(self):
138 return "Binder"
140 @staticmethod
141 def _from_c(c_expr):
142 return Binder(c_expr.iex.Binder.binder)
144 @staticmethod
145 def _to_c(expr):
146 return pvc.IRExpr_Binder(expr.binder)
148 def result_type(self, tyenv):
149 return "Ity_INVALID"
152class VECRET(IRExpr):
153 tag = "Iex_VECRET"
155 __slots__ = []
157 def _pp_str(self):
158 return "VECRET"
160 @staticmethod
161 def _from_c(c_expr):
162 return VECRET()
164 @staticmethod
165 def _to_c(expr):
166 return pvc.IRExpr_VECRET()
168 def result_type(self, tyenv):
169 return "Ity_INVALID"
172class GSPTR(IRExpr):
173 __slots__ = []
175 tag = "Iex_GSPTR"
177 def _pp_str(self):
178 return "GSPTR"
180 @staticmethod
181 def _from_c(c_expr):
182 return GSPTR()
184 @staticmethod
185 def _to_c(expr):
186 return pvc.IRExpr_GSPTR()
188 def result_type(self, tyenv):
189 return "Ity_INVALID"
192class GetI(IRExpr):
193 """
194 Read a guest register at a non-fixed offset in the guest state.
195 """
197 __slots__ = ["descr", "ix", "bias"]
199 tag = "Iex_GetI"
201 def __init__(self, descr, ix, bias):
202 self.descr = descr
203 self.ix = ix
204 self.bias = bias
206 @property
207 def description(self):
208 return self.descr
210 @property
211 def index(self):
212 return self.ix
214 def _pp_str(self):
215 return f"GetI({self.descr})[{self.ix},{self.bias}]"
217 @staticmethod
218 def _from_c(c_expr):
219 descr = IRRegArray._from_c(c_expr.Iex.GetI.descr)
220 ix = IRExpr._from_c(c_expr.Iex.GetI.ix)
221 bias = c_expr.Iex.GetI.bias
222 return GetI(descr, ix, bias)
224 @staticmethod
225 def _to_c(expr):
226 return pvc.IRExpr_GetI(IRRegArray._to_c(expr.descr), IRExpr._to_c(expr.ix), expr.bias)
228 def result_type(self, tyenv):
229 return self.descr.elemTy
232class RdTmp(IRExpr):
233 """
234 Read the value held by a temporary.
235 """
237 __slots__ = ["_tmp"]
239 tag = "Iex_RdTmp"
241 def __init__(self, tmp):
242 self._tmp = tmp
244 def _pp_str(self):
245 return "t%d" % self.tmp
247 @property
248 def tmp(self):
249 return self._tmp
251 @staticmethod
252 def _from_c(c_expr):
253 tmp = c_expr.Iex.RdTmp.tmp
254 return RdTmp.get_instance(tmp)
256 @staticmethod
257 def _to_c(expr):
258 return pvc.IRExpr_RdTmp(expr.tmp)
260 @staticmethod
261 def get_instance(tmp):
262 if tmp < 1024:
263 # for small tmp reads, they are cached and are only created once globally
264 return _RDTMP_POOL[tmp]
265 return RdTmp(tmp)
267 def replace_expression(self, replacements):
268 # RdTmp is one of the terminal IRExprs, which cannot be replaced.
269 pass
271 def result_type(self, tyenv):
272 return tyenv.lookup(self.tmp)
274 def __hash__(self):
275 return 133700 + self._tmp
278_RDTMP_POOL = list(RdTmp(i) for i in range(0, 1024))
281class Get(IRExpr):
282 """
283 Read a guest register, at a fixed offset in the guest state.
284 """
286 __slots__ = ["offset", "ty_int"]
288 tag = "Iex_Get"
290 def __init__(self, offset: int, ty: str, ty_int: int | None = None):
291 self.offset = offset
292 if ty_int is None:
293 self.ty_int = get_int_from_enum(ty)
294 else:
295 self.ty_int = ty_int
297 @property
298 def ty(self):
299 return get_enum_from_int(self.ty_int)
301 @property
302 def type(self):
303 return get_enum_from_int(self.ty_int)
305 def _pp_str(self):
306 return f"GET:{self.ty[4:]}(offset={self.offset})"
308 def pp_str_with_name(self, reg_name: str):
309 """pp_str_with_name is used to print the expression with the name of the
310 register instead of the offset"""
311 return f"GET:{self.ty[4:]}({reg_name})"
313 @staticmethod
314 def _from_c(c_expr):
315 return Get(c_expr.Iex.Get.offset, get_enum_from_int(c_expr.Iex.Get.ty))
317 @staticmethod
318 def _to_c(expr):
319 return pvc.IRExpr_Get(expr.offset, expr.ty_int)
321 def result_type(self, tyenv):
322 return self.ty
324 def __hash__(self):
325 return (self.offset << 8) | self.ty_int
328class Qop(IRExpr):
329 """
330 A quaternary operation (4 arguments).
331 """
333 __slots__ = ["op", "args"]
335 tag = "Iex_Qop"
337 def __init__(self, op, args):
338 self.op = op
339 self.args = args
341 def _pp_str(self):
342 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
344 @property
345 def child_expressions(self):
346 expressions = sum((a.child_expressions for a in self.args), [])
347 expressions.extend(self.args)
348 return expressions
350 @staticmethod
351 def _from_c(c_expr):
352 return Qop(
353 get_enum_from_int(c_expr.Iex.Qop.details.op),
354 [
355 IRExpr._from_c(arg)
356 for arg in [
357 c_expr.Iex.Qop.details.arg1,
358 c_expr.Iex.Qop.details.arg2,
359 c_expr.Iex.Qop.details.arg3,
360 c_expr.Iex.Qop.details.arg4,
361 ]
362 ],
363 )
365 @staticmethod
366 def _to_c(expr):
367 return pvc.IRExpr_Qop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
369 def result_type(self, tyenv):
370 return get_op_retty(self.op)
372 def typecheck(self, tyenv): # TODO change all this to use PyvexTypeErrorException
373 resty, (arg1ty, arg2ty, arg3ty, arg4ty) = op_arg_types(self.op)
374 arg1ty_real = self.args[0].typecheck(tyenv)
375 arg2ty_real = self.args[1].typecheck(tyenv)
376 arg3ty_real = self.args[2].typecheck(tyenv)
377 arg4ty_real = self.args[3].typecheck(tyenv)
378 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None or arg4ty_real is None:
379 return None
381 if arg1ty_real != arg1ty:
382 log.debug("First arg of %s must be %s", self.op, arg1ty)
383 return None
384 if arg2ty_real != arg2ty:
385 log.debug("Second arg of %s must be %s", self.op, arg2ty)
386 return None
387 if arg3ty_real != arg3ty:
388 log.debug("Third arg of %s must be %s", self.op, arg3ty)
389 return None
390 if arg4ty_real != arg4ty:
391 log.debug("Fourth arg of %s must be %s", self.op, arg4ty)
392 return None
394 return resty
397class Triop(IRExpr):
398 """
399 A ternary operation (3 arguments)
400 """
402 __slots__ = ["op", "args"]
404 tag = "Iex_Triop"
406 def __init__(self, op, args):
407 self.op = op
408 self.args = args
410 def _pp_str(self):
411 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
413 @property
414 def child_expressions(self):
415 expressions = sum((a.child_expressions for a in self.args), [])
416 expressions.extend(self.args)
417 return expressions
419 @staticmethod
420 def _from_c(c_expr):
421 return Triop(
422 get_enum_from_int(c_expr.Iex.Triop.details.op),
423 [
424 IRExpr._from_c(arg)
425 for arg in [c_expr.Iex.Triop.details.arg1, c_expr.Iex.Triop.details.arg2, c_expr.Iex.Triop.details.arg3]
426 ],
427 )
429 @staticmethod
430 def _to_c(expr):
431 return pvc.IRExpr_Triop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
433 def result_type(self, tyenv):
434 return get_op_retty(self.op)
436 def typecheck(self, tyenv):
437 resty, (arg1ty, arg2ty, arg3ty) = op_arg_types(self.op)
438 arg1ty_real = self.args[0].typecheck(tyenv)
439 arg2ty_real = self.args[1].typecheck(tyenv)
440 arg3ty_real = self.args[2].typecheck(tyenv)
441 if arg1ty_real is None or arg2ty_real is None or arg3ty_real is None:
442 return None
444 if arg1ty_real != arg1ty:
445 log.debug("First arg of %s must be %s", self.op, arg1ty)
446 return None
447 if arg2ty_real != arg2ty:
448 log.debug("Second arg of %s must be %s", self.op, arg2ty)
449 return None
450 if arg3ty_real != arg3ty:
451 log.debug("Third arg of %s must be %s", self.op, arg3ty)
452 return None
454 return resty
457class Binop(IRExpr):
458 """
459 A binary operation (2 arguments).
460 """
462 __slots__ = ["_op", "op_int", "args"]
464 tag = "Iex_Binop"
466 def __init__(self, op, args, op_int=None):
467 self.op_int = op_int
468 self.args = args
469 self._op = op if op is not None else None
471 def _pp_str(self):
472 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
474 @property
475 def op(self):
476 if self._op is None:
477 self._op = get_enum_from_int(self.op_int)
478 return self._op
480 @property
481 def child_expressions(self):
482 expressions = sum((a.child_expressions for a in self.args), [])
483 expressions.extend(self.args)
484 return expressions
486 @staticmethod
487 def _from_c(c_expr):
488 return Binop(
489 None,
490 [IRExpr._from_c(arg) for arg in [c_expr.Iex.Binop.arg1, c_expr.Iex.Binop.arg2]],
491 op_int=c_expr.Iex.Binop.op,
492 )
494 @staticmethod
495 def _to_c(expr):
496 return pvc.IRExpr_Binop(get_int_from_enum(expr.op), *[IRExpr._to_c(arg) for arg in expr.args])
498 def result_type(self, tyenv):
499 return get_op_retty(self.op)
501 def typecheck(self, tyenv):
502 arg1ty_real = self.args[0].typecheck(tyenv)
503 arg2ty_real = self.args[1].typecheck(tyenv)
505 resty, (arg1ty, arg2ty) = op_arg_types(self.op)
506 if arg1ty_real is None or arg2ty_real is None:
507 return None
509 if arg1ty_real != arg1ty:
510 log.debug("First arg of %s must be %s", self.op, arg1ty)
511 return None
512 if arg2ty_real != arg2ty:
513 log.debug("Second arg of %s must be %s", self.op, arg2ty)
514 return None
516 return resty
519class Unop(IRExpr):
520 """
521 A unary operation (1 argument).
522 """
524 __slots__ = ["op", "args"]
526 tag = "Iex_Unop"
528 def __init__(self, op: str, args: list[IRExpr]):
529 self.op = op
530 self.args = args
532 def _pp_str(self):
533 return "{}({})".format(self.op[4:], ",".join(str(a) for a in self.args))
535 @property
536 def child_expressions(self):
537 expressions = sum((a.child_expressions for a in self.args), [])
538 expressions.extend(self.args)
539 return expressions
541 @staticmethod
542 def _from_c(c_expr):
543 return Unop(get_enum_from_int(c_expr.Iex.Unop.op), [IRExpr._from_c(c_expr.Iex.Unop.arg)])
545 @staticmethod
546 def _to_c(expr):
547 return pvc.IRExpr_Unop(get_int_from_enum(expr.op), IRExpr._to_c(expr.args[0]))
549 def result_type(self, tyenv):
550 return get_op_retty(self.op)
552 def typecheck(self, tyenv):
553 resty, (arg1ty,) = op_arg_types(self.op)
554 arg1ty_real = self.args[0].typecheck(tyenv)
555 if arg1ty_real is None:
556 return None
558 if arg1ty_real != arg1ty:
559 log.debug("First arg of %s must be %s", self.op, arg1ty)
560 return None
562 return resty
565class Load(IRExpr):
566 """
567 A load from memory.
568 """
570 __slots__ = ["end", "ty", "addr"]
572 tag = "Iex_Load"
574 def __init__(self, end, ty, addr):
575 self.end = end
576 self.ty = ty
577 self.addr = addr
579 @property
580 def endness(self):
581 return self.end
583 @property
584 def type(self):
585 return self.ty
587 def _pp_str(self):
588 return f"LD{self.end[-2:].lower()}:{self.ty[4:]}({self.addr})"
590 @staticmethod
591 def _from_c(c_expr):
592 return Load(
593 get_enum_from_int(c_expr.Iex.Load.end),
594 get_enum_from_int(c_expr.Iex.Load.ty),
595 IRExpr._from_c(c_expr.Iex.Load.addr),
596 )
598 @staticmethod
599 def _to_c(expr):
600 return pvc.IRExpr_Load(get_int_from_enum(expr.end), get_int_from_enum(expr.ty), IRExpr._to_c(expr.addr))
602 def result_type(self, tyenv):
603 return self.ty
605 def typecheck(self, tyenv):
606 addrty = self.addr.typecheck(tyenv)
607 if addrty is None:
608 return None
609 if addrty != tyenv.wordty:
610 log.debug("Address must be word-sized")
611 return None
612 return self.ty
615class Const(IRExpr):
616 """
617 A constant expression.
618 """
620 __slots__ = ["_con"]
622 tag = "Iex_Const"
624 def __init__(self, con: IRConst):
625 self._con = con
627 def _pp_str(self):
628 return str(self.con)
630 @property
631 def con(self) -> IRConst:
632 return self._con
634 @staticmethod
635 def _from_c(c_expr):
636 con = IRConst._from_c(c_expr.Iex.Const.con)
637 return Const.get_instance(con)
639 @staticmethod
640 def _to_c(expr):
641 return pvc.IRExpr_Const(IRConst._to_c(expr.con))
643 @staticmethod
644 def get_instance(con):
645 if con.value < 1024 and con.__class__ in _CONST_POOL:
646 return _CONST_POOL[con.__class__][con.value]
647 return Const(con)
649 def result_type(self, tyenv):
650 return self.con.type
653_CONST_POOL = {
654 U8: [Const(U8(i)) for i in range(0, 1024)],
655 U16: [Const(U16(i)) for i in range(0, 1024)],
656 U32: [Const(U32(i)) for i in range(0, 1024)],
657 U64: [Const(U64(i)) for i in range(0, 1024)],
658}
661class ITE(IRExpr):
662 """
663 An if-then-else expression.
664 """
666 __slots__ = ["cond", "iffalse", "iftrue"]
668 tag = "Iex_ITE"
670 def __init__(self, cond, iffalse, iftrue):
671 self.cond = cond
672 self.iffalse = iffalse
673 self.iftrue = iftrue
675 def _pp_str(self):
676 return f"ITE({self.cond},{self.iftrue},{self.iffalse})"
678 @staticmethod
679 def _from_c(c_expr):
680 return ITE(
681 IRExpr._from_c(c_expr.Iex.ITE.cond),
682 IRExpr._from_c(c_expr.Iex.ITE.iffalse),
683 IRExpr._from_c(c_expr.Iex.ITE.iftrue),
684 )
686 @staticmethod
687 def _to_c(expr):
688 return pvc.IRExpr_ITE(IRExpr._to_c(expr.cond), IRExpr._to_c(expr.iftrue), IRExpr._to_c(expr.iffalse))
690 def result_type(self, tyenv):
691 return self.iftrue.result_type(tyenv)
693 def typecheck(self, tyenv):
694 condty = self.cond.typecheck(tyenv)
695 falsety = self.iffalse.typecheck(tyenv)
696 truety = self.iftrue.typecheck(tyenv)
698 if condty is None or falsety is None or truety is None:
699 return None
701 if condty != "Ity_I1":
702 log.debug("guard must be Ity_I1")
703 return None
705 if falsety != truety:
706 log.debug("false condition must be same type as true condition")
707 return None
709 return falsety
712class CCall(IRExpr):
713 """
714 A call to a pure (no side-effects) helper C function.
715 """
717 __slots__ = ["retty", "cee", "args"]
719 tag = "Iex_CCall"
721 def __init__(self, retty, cee, args):
722 self.retty = retty
723 self.cee = cee
724 self.args = tuple(args)
726 @property
727 def ret_type(self):
728 return self.retty
730 @property
731 def callee(self):
732 return self.cee
734 def _pp_str(self):
735 return "{}({}):{}".format(self.cee, ",".join(str(a) for a in self.args), self.retty)
737 @property
738 def child_expressions(self):
739 expressions = sum((a.child_expressions for a in self.args), [])
740 expressions.extend(self.args)
741 return expressions
743 @staticmethod
744 def _from_c(c_expr):
745 i = 0
746 args = []
747 while True:
748 arg = c_expr.Iex.CCall.args[i]
749 if arg == ffi.NULL:
750 break
751 args.append(IRExpr._from_c(arg))
752 i += 1
754 return CCall(get_enum_from_int(c_expr.Iex.CCall.retty), IRCallee._from_c(c_expr.Iex.CCall.cee), tuple(args))
756 @staticmethod
757 def _to_c(expr):
758 args = [IRExpr._to_c(arg) for arg in expr.args]
759 mkIRExprVec = getattr(pvc, "mkIRExprVec_%d" % len(args))
760 return pvc.IRExpr_CCall(IRCallee._to_c(expr.cee), get_int_from_enum(expr.retty), mkIRExprVec(*args))
762 def result_type(self, tyenv):
763 return self.retty
766def get_op_retty(op):
767 return op_arg_types(op)[0]
770op_signatures: dict[str, tuple[str, tuple[str, ...]]] = {}
773def _request_op_type_from_cache(op):
774 return op_signatures[op]
777def _request_op_type_from_libvex(op):
778 Ity_INVALID = 0x1100 # as defined in enum IRType in VEX
780 res_ty = ffi.new("IRType *")
781 arg_tys = [ffi.new("IRType *") for _ in range(4)]
782 # initialize all IRTypes to Ity_INVALID
783 for arg in arg_tys:
784 arg[0] = Ity_INVALID
785 pvc.typeOfPrimop(get_int_from_enum(op), res_ty, *arg_tys)
786 arg_ty_vals = [a[0] for a in arg_tys]
788 try:
789 numargs = arg_ty_vals.index(Ity_INVALID)
790 except ValueError:
791 numargs = 4
792 args_tys_list = [get_enum_from_int(arg_ty_vals[i]) for i in range(numargs)]
794 op_ty_sig = (get_enum_from_int(res_ty[0]), tuple(args_tys_list))
795 op_signatures[op] = op_ty_sig
796 return op_ty_sig
799class PyvexOpMatchException(Exception):
800 pass
803class PyvexTypeErrorException(Exception):
804 pass
807def int_type_for_size(size):
808 return "Ity_I%d" % size
811# precompiled regexes
812unop_signature_re = re.compile(r"Iop_(Not|Ctz|Clz)(?P<size>\d+)$")
813binop_signature_re = re.compile(r"Iop_(Add|Sub|Mul|Xor|Or|And|Div[SU]|Mod)(?P<size>\d+)$")
814shift_signature_re = re.compile(r"Iop_(Shl|Shr|Sar)(?P<size>\d+)$")
815cmp_signature_re_1 = re.compile(r"Iop_Cmp(EQ|NE)(?P<size>\d+)$")
816cmp_signature_re_2 = re.compile(r"Iop_Cmp(GT|GE|LT|LE)(?P<size>\d+)[SU]$")
817mull_signature_re = re.compile(r"Iop_Mull[SU](?P<size>\d+)$")
818half_signature_re = re.compile(r"Iop_DivMod[SU](?P<fullsize>\d+)to(?P<halfsize>\d+)$")
819cast_signature_re = re.compile(r"Iop_(?P<srcsize>\d+)(U|S|HI|HL)?to(?P<dstsize>\d+)")
822def unop_signature(op):
823 m = unop_signature_re.match(op)
824 if m is None:
825 raise PyvexOpMatchException()
826 size = int(m.group("size"))
827 size_type = int_type_for_size(size)
828 return size_type, (size_type,)
831def binop_signature(op):
832 m = binop_signature_re.match(op)
833 if m is None:
834 raise PyvexOpMatchException()
835 size = int(m.group("size"))
836 size_type = int_type_for_size(size)
837 return (size_type, (size_type, size_type))
840def shift_signature(op):
841 m = shift_signature_re.match(op)
842 if m is None:
843 raise PyvexOpMatchException()
844 size = int(m.group("size"))
845 if size > 255:
846 raise PyvexTypeErrorException("Cannot apply shift operation to %d size int because shift index is 8-bit" % size)
847 size_type = int_type_for_size(size)
848 return (size_type, (size_type, int_type_for_size(8)))
851def cmp_signature(op):
852 m = cmp_signature_re_1.match(op)
853 m2 = cmp_signature_re_2.match(op)
854 if (m is None) == (m2 is None):
855 raise PyvexOpMatchException()
856 mfound = m if m is not None else m2
857 assert mfound is not None
858 size = int(mfound.group("size"))
859 size_type = int_type_for_size(size)
860 return (int_type_for_size(1), (size_type, size_type))
863def mull_signature(op):
864 m = mull_signature_re.match(op)
865 if m is None:
866 raise PyvexOpMatchException()
867 size = int(m.group("size"))
868 size_type = int_type_for_size(size)
869 doubled_size_type = int_type_for_size(2 * size)
870 return (doubled_size_type, (size_type, size_type))
873def half_signature(op):
874 m = half_signature_re.match(op)
875 if m is None:
876 raise PyvexOpMatchException()
877 fullsize = int(m.group("fullsize"))
878 halfsize = int(m.group("halfsize"))
879 if halfsize * 2 != fullsize:
880 raise PyvexTypeErrorException("Invalid Instruction %s: Type 1 must be twice the size of type 2" % op)
881 fullsize_type = int_type_for_size(fullsize)
882 halfsize_type = int_type_for_size(halfsize)
883 return (fullsize_type, (fullsize_type, halfsize_type))
886def cast_signature(op):
887 m = cast_signature_re.match(op)
888 if m is None:
889 raise PyvexOpMatchException()
890 src_type = int_type_for_size(int(m.group("srcsize")))
891 dst_type = int_type_for_size(int(m.group("dstsize")))
892 return (dst_type, (src_type,))
895polymorphic_op_processors = [
896 unop_signature,
897 binop_signature,
898 shift_signature,
899 cmp_signature,
900 mull_signature,
901 half_signature,
902 cast_signature,
903]
906def _request_polymorphic_op_type(op):
907 for polymorphic_signature in polymorphic_op_processors:
908 try:
909 op_ty_sig = polymorphic_signature(op)
910 break
911 except PyvexOpMatchException:
912 continue
913 else:
914 raise PyvexOpMatchException("Op %s not recognized" % op)
915 return op_ty_sig
918_request_funcs = [_request_op_type_from_cache, _request_op_type_from_libvex, _request_polymorphic_op_type]
921def op_arg_types(op):
922 for _request_func in _request_funcs:
923 try:
924 return _request_func(op)
925 except KeyError:
926 continue
927 raise ValueError("Cannot find type of op %s" % op)
930_globals = globals().copy()
931#
932# Mapping from tag strings/enums to IRExpr classes
933#
934tag_to_expr_mapping = {}
935enum_to_expr_mapping = {}
936tag_count = 0
937cls = None
938for cls in _globals.values():
939 if type(cls) is type and issubclass(cls, IRExpr) and cls is not IRExpr:
940 tag_to_expr_mapping[cls.tag] = cls
941 enum_to_expr_mapping[get_int_from_enum(cls.tag)] = cls
942 cls.tag_int = tag_count
943 tag_count += 1
944del cls
947def tag_to_expr_class(tag):
948 """
949 Convert a tag string to the corresponding IRExpr class type.
951 :param str tag: The tag string.
952 :return: A class.
953 :rtype: type
954 """
956 try:
957 return tag_to_expr_mapping[tag]
958 except KeyError:
959 raise KeyError("Cannot find expression class for type %s." % tag)
962def enum_to_expr_class(tag_enum):
963 """
964 Convert a tag enum to the corresponding IRExpr class.
966 :param int tag_enum: The tag enum.
967 :return: A class.
968 :rtype: type
969 """
971 try:
972 return enum_to_expr_mapping[tag_enum]
973 except KeyError:
974 raise KeyError("Cannot find expression class for type %s." % get_enum_from_int(tag_enum))