about summary refs log tree commit diff stats
path: root/miasm2/expression/expression.py
diff options
context:
space:
mode:
Diffstat (limited to 'miasm2/expression/expression.py')
-rw-r--r--miasm2/expression/expression.py103
1 files changed, 83 insertions, 20 deletions
diff --git a/miasm2/expression/expression.py b/miasm2/expression/expression.py
index 8e63e6a2..3cf37070 100644
--- a/miasm2/expression/expression.py
+++ b/miasm2/expression/expression.py
@@ -1018,26 +1018,12 @@ class ExprOp(Expr):
                            TOK_POS_STRICT,
                           ]:
             size = 1
-        elif self._op in ['mem_16_to_double', 'mem_32_to_double',
-                           'mem_64_to_double', 'mem_80_to_double',
-                           'int_16_to_double', 'int_32_to_double',
-                           'int_64_to_double', 'int_80_to_double']:
-            size = 64
-        elif self._op in ['double_to_mem_16', 'double_to_int_16',
-                           'float_trunc_to_int_16', 'double_trunc_to_int_16']:
-            size = 16
-        elif self._op in ['double_to_mem_32', 'double_to_int_32',
-                           'float_trunc_to_int_32', 'double_trunc_to_int_32',
-                           'double_to_float']:
-            size = 32
-        elif self._op in ['double_to_mem_64', 'double_to_int_64',
-                           'float_trunc_to_int_64', 'double_trunc_to_int_64',
-                           'float_to_double']:
-            size = 64
-        elif self._op in ['double_to_mem_80', 'double_to_int_80',
-                           'float_trunc_to_int_80',
-                           'double_trunc_to_int_80']:
-            size = 80
+        elif self._op.startswith("sint_to_fp"):
+            size = int(self._op[len("sint_to_fp"):])
+        elif self._op.startswith("fp_to_sint"):
+            size = int(self._op[len("fp_to_sint"):])
+        elif self._op.startswith("fpconvert_fp"):
+            size = int(self._op[len("fpconvert_fp"):])
         elif self._op in ['segm']:
             size = self._args[1].size
         else:
@@ -1884,3 +1870,80 @@ def expr_is_signed_lower_or_equal(op1, op2):
     of = _expr_compute_of(op1, op2)
     zf = _expr_compute_zf(op1, op2)
     return zf | (nf ^ of)
+
+# sign bit | exponent | significand
+size_to_IEEE754_info = {
+    16: {
+        "exponent": 5,
+        "significand": 10,
+    },
+    32: {
+        "exponent": 8,
+        "significand": 23,
+    },
+    64: {
+        "exponent": 11,
+        "significand": 52,
+    },
+}
+
+def expr_is_NaN(expr):
+    """Return 1 or 0 on 1 bit if expr represent a NaN value according to IEEE754
+    """
+    info = size_to_IEEE754_info[expr.size]
+    exponent = expr[info["significand"]: info["significand"] + info["exponent"]]
+
+    # exponent is full of 1s and significand is not NULL
+    return ExprCond(exponent - ExprInt(-1, exponent.size),
+                    ExprInt(0, 1),
+                    ExprCond(expr[:info["significand"]], ExprInt(1, 1),
+                             ExprInt(0, 1)))
+
+
+def expr_is_qNaN(expr):
+    """Return 1 or 0 on 1 bit if expr represent a qNaN (quiet) value according to
+    IEEE754
+    """
+    info = size_to_IEEE754_info[expr.size]
+    significand_top = expr[info["significand"]: info["significand"] + 1]
+    return expr_is_NaN(expr) & significand_top
+
+
+def expr_is_sNaN(expr):
+    """Return 1 or 0 on 1 bit if expr represent a sNaN (signalling) value according
+    to IEEE754
+    """
+    info = size_to_IEEE754_info[expr.size]
+    significand_top = expr[info["significand"]: info["significand"] + 1]
+    return expr_is_NaN(expr) & ~significand_top
+
+
+def expr_is_float_lower(op1, op2):
+    """Return 1 on 1 bit if @op1 < @op2, 0 otherwise.
+    /!\ Assume @op1 and @op2 are not NaN
+    Comparision is the floating point one, defined in IEEE754
+    """
+    sign1, sign2 = op1.msb(), op2.msb()
+    magn1, magn2 = op1[:-1], op2[:-1]
+    return ExprCond(sign1 ^ sign2,
+                    # Sign different, only the sign matters
+                    sign1, # sign1 ? op1 < op2 : op1 >= op2
+                    # Sign equals, the result is inversed for negatives
+                    sign1 ^ (expr_is_unsigned_lower(magn1, magn2)))
+
+
+def expr_is_float_equal(op1, op2):
+    """Return 1 on 1 bit if @op1 == @op2, 0 otherwise.
+    /!\ Assume @op1 and @op2 are not NaN
+    Comparision is the floating point one, defined in IEEE754
+    """
+    sign1, sign2 = op1.msb(), op2.msb()
+    magn1, magn2 = op1[:-1], op2[:-1]
+    return ExprCond(magn1 ^ magn2,
+                    ExprInt(0, 1),
+                    ExprCond(magn1,
+                             # magn1 == magn2, are the signal equals?
+                             ~(sign1 ^ sign2),
+                             # Special case: -0.0 == +0.0
+                             ExprInt(1, 1))
+                    )