]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Constant folding for Iop_ClzNat32/64. (BZ 506211)
authorFlorian Krohm <flo2030@eich-krohm.de>
Wed, 16 Jul 2025 14:54:44 +0000 (14:54 +0000)
committerFlorian Krohm <flo2030@eich-krohm.de>
Wed, 16 Jul 2025 14:54:44 +0000 (14:54 +0000)
Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211

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

index f0458cb2850f379c3377165ed71497d76835bbc6..140899480ff51f877dbfaf0fa52c1c00adab16d3 100644 (file)
@@ -1346,6 +1346,25 @@ static UInt fold_Clz32 ( UInt value )
    return 0;
 }
 
+/* Helpers for folding ClzNat32/64. */
+static UInt fold_ClzNat64 ( ULong value )
+{
+   UInt i;
+   for (i = 0; i < 64; ++i) {
+      if (0ULL != (value & (((ULong)1) << (63 - i)))) return i;
+   }
+   return 64;
+}
+
+static UInt fold_ClzNat32 ( UInt value )
+{
+   UInt i;
+   for (i = 0; i < 32; ++i) {
+      if (0 != (value & (((UInt)1) << (31 - i)))) return i;
+   }
+   return 32;
+}
+
 /* Helpers for folding PopCount32/64.
    https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
    As many iterations as 1-bits present.
@@ -1709,6 +1728,17 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e )
             break;
          }
 
+         case Iop_ClzNat32: {
+            UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
+            e2 = IRExpr_Const(IRConst_U32(fold_ClzNat32(u32)));
+            break;
+         }
+         case Iop_ClzNat64: {
+            ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
+            e2 = IRExpr_Const(IRConst_U64(fold_ClzNat64(u64)));
+            break;
+         }
+
          case Iop_PopCount32: {
             UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
             e2 = IRExpr_Const(IRConst_U32(fold_PopCount32(u32)));
index e73ec46a87019530d8b5a093e45639a721562092..1d06919d1643197251a20b17dee67c3b4a4f337b 100644 (file)
@@ -98,8 +98,8 @@
 // { OPNAME(Ctz32),  Ity_I32,  1, Ity_I32 }, // deprecated, undefined behaviour
 // { OPNAME(Ctz64),  Ity_I64,  1, Ity_I64 }, // deprecated, undefined behaviour
 
-// { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet
-// { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet
+   { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 },
+   { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 },
 
 // { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet
 // { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet
index bb261384874a1df3112ef6fa47dfde3ffca9dc38..6d664a1b841a16bd03de6e63c58079c8035a92a0 100644 (file)
@@ -32,6 +32,7 @@ static void run_selected_tests(const irop_t *, test_data_t *);
 static void run_random_tests(const irop_t *, test_data_t *);
 static uint64_t left(uint64_t, unsigned);
 static uint32_t popcount(uint64_t);
+static uint32_t clz(uint64_t, unsigned);
 
 
 void
@@ -197,6 +198,9 @@ check_result(const irop_t *op, const test_data_t *data)
       expected = popcount(opnd);
       break;
 
+   case Iop_ClzNat32: expected = clz(opnd, 32); break;
+   case Iop_ClzNat64: expected = clz(opnd, 64); break;
+
    default:
       panic("%s: operator %s not handled\n", __func__, op->name);
    }
@@ -265,3 +269,17 @@ popcount(uint64_t value)
    }
    return count;
 }
+
+
+static uint32_t
+clz(uint64_t value, unsigned num_bits)
+{
+   unsigned last_seen_1bit = 0;
+
+   for (int i = 1; i <= num_bits; ++i) {
+      if (value & 0x1)
+         last_seen_1bit = i;
+      value >>= 1;
+   }
+   return num_bits - last_seen_1bit;
+}