]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Enable folding for Iop_Left8/16
authorFlorian Krohm <flo2030@eich-krohm.de>
Mon, 14 Jul 2025 13:11:01 +0000 (13:11 +0000)
committerFlorian Krohm <flo2030@eich-krohm.de>
Mon, 14 Jul 2025 13:11:01 +0000 (13:11 +0000)
In iropt-test add independent implementation of the "Left" operator
for checking purposes.

VEX/priv/ir_opt.c
none/tests/iropt-test/irops.tab
none/tests/iropt-test/unary.c

index 9a3f39c2c9d9f15539b4568c81b53fb0f8207495..52b8e09571edefd10728f86d30c9586d3e3dada0 100644 (file)
@@ -1633,6 +1633,22 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e )
             break;
          }
 
+         case Iop_Left8: {
+            UChar u8 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8;
+            Char  s8 = (Char)(u8 & 0xFF);
+            s8 = (s8 | (-s8));
+            e2 = IRExpr_Const( IRConst_U8( (UChar)s8 ));
+            break;
+         }
+
+         case Iop_Left16: {
+            UShort u16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16;
+            Short  s16 = (Short)(u16 & 0xFFFF);
+            s16 = (s16 | (-s16));
+            e2 = IRExpr_Const( IRConst_U16( (UShort)s16 ));
+            break;
+         }
+
          case Iop_Left32: {
             UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
             Int  s32 = (Int)(u32 & 0xFFFFFFFF);
index b22434dab1f92bd968caa06b2f06dd80e6c87c65..45b0e728cc64d4148c6bb1d260bbca792c435c8a 100644 (file)
@@ -87,8 +87,8 @@
    { OPNAME(CmpwNEZ32), Ity_I32,  1, Ity_I32 },
    { OPNAME(CmpwNEZ64), Ity_I64,  1, Ity_I64 },
 
-// { OPNAME(Left8),  Ity_I8,   1, Ity_I8  }, // no folding yet
-// { OPNAME(Left16), Ity_I16,  1, Ity_I16 }, // no folding yet
+   { OPNAME(Left8),  Ity_I8,   1, Ity_I8  },
+   { OPNAME(Left16), Ity_I16,  1, Ity_I16 },
    { OPNAME(Left32), Ity_I32,  1, Ity_I32 },
    { OPNAME(Left64), Ity_I64,  1, Ity_I64 },
 
index 51ad51505b4d727dc2141ee029734baf19dcaabd..537c29a7233779044cd29956fae15670acc047ee 100644 (file)
@@ -28,6 +28,7 @@
 
 static void check_result(const irop_t *, const test_data_t *);
 static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *);
+static uint64_t left(uint64_t, unsigned);
 
 
 void
@@ -189,19 +190,10 @@ check_result(const irop_t *op, const test_data_t *data)
    case Iop_CmpwNEZ32: expected = opnd == 0 ? 0 : UINT32_MAX; break;
    case Iop_CmpwNEZ64: expected = opnd == 0 ? 0 : UINT64_MAX; break;
 
-// case Iop_Left8:
-// case Iop_Left16:
-   case Iop_Left32: {
-      int32_t opnd_s = (int32_t)opnd;
-      expected = (opnd_s | -opnd_s) & UINT32_MAX;
-      break;
-   }
-
-   case Iop_Left64: {
-      int64_t opnd_s = (int64_t)opnd;
-      expected = (opnd_s | -opnd_s) & UINT64_MAX;
-      break;
-   }
+   case Iop_Left8:  expected = left(opnd, 8);  break;
+   case Iop_Left16: expected = left(opnd, 16); break;
+   case Iop_Left32: expected = left(opnd, 32); break;
+   case Iop_Left64: expected = left(opnd, 64); break;
 
    default:
       panic("%s: operator %s not handled\n", __func__, op->name);
@@ -227,3 +219,34 @@ check_result(const irop_t *op, const test_data_t *data)
    if (! ok)
       complain(op, data, expected);
 }
+
+
+/* An implementation for Iop_Left/8/16/32/64.
+   The semantics of those operators are defined in Section 2.5 of
+   https://valgrind.org/docs/memcheck2005.pdf as follows:
+
+   Iop_Left(v) is the same as v, except that all bits to the left of the
+   rightmost 1-bit in v are set. */
+static uint64_t
+left(uint64_t val, unsigned width)
+{
+  uint64_t ret = 0;
+
+  /* Find the rightmost 1-bit, then sign-extend. */
+  for (unsigned bit = 0; bit < width; ++bit) {
+    if (val & ((uint64_t)1 << bit)) {
+      ret = (int64_t)((uint64_t)val << (63 - bit)) >> (63 - bit);
+      break;
+    }
+  }
+
+  /* Truncate to desired width */
+  switch (width) {
+  case 8:  return ret & UINT8_MAX;
+  case 16: return ret & UINT16_MAX;
+  case 32: return ret & UINT32_MAX;
+  case 64: return ret & UINT64_MAX;
+  default:
+     panic(__func__);
+  }
+}