]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Constant folding for Iop_CtzNat32/64. (BZ 506211)
authorFlorian Krohm <flo2030@eich-krohm.de>
Wed, 16 Jul 2025 17:43:34 +0000 (17:43 +0000)
committerFlorian Krohm <flo2030@eich-krohm.de>
Wed, 16 Jul 2025 17:43:34 +0000 (17:43 +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 140899480ff51f877dbfaf0fa52c1c00adab16d3..c37ff08a775ceeb306ebd7ed6d22d95790c43eee 100644 (file)
@@ -1365,6 +1365,30 @@ static UInt fold_ClzNat32 ( UInt value )
    return 32;
 }
 
+/* Helpers for folding CtzNat32/64. */
+static UInt fold_CtzNat_WRK ( ULong value, UInt num_bits )
+{
+  UInt count = 0;
+
+  for (UInt i = 1; i <= num_bits; ++i) {
+    if (value & 0x1)
+      return count;
+    value >>= 1;
+    ++count;
+  }
+  return count;
+}
+
+static UInt fold_CtzNat64 ( ULong value )
+{
+   return fold_CtzNat_WRK(value, 64);
+}
+
+static UInt fold_CtzNat32 ( UInt value )
+{
+   return fold_CtzNat_WRK(value, 32);
+}
+
 /* Helpers for folding PopCount32/64.
    https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
    As many iterations as 1-bits present.
@@ -1739,6 +1763,17 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e )
             break;
          }
 
+         case Iop_CtzNat32: {
+            UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32;
+            e2 = IRExpr_Const(IRConst_U32(fold_CtzNat32(u32)));
+            break;
+         }
+         case Iop_CtzNat64: {
+            ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64;
+            e2 = IRExpr_Const(IRConst_U64(fold_CtzNat64(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 1d06919d1643197251a20b17dee67c3b4a4f337b..02afa6423a4441117ddfdadccca82b4854e2b0f1 100644 (file)
    { 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
+   { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 },
+   { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 },
 
    { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 },
    { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 },
index 6d664a1b841a16bd03de6e63c58079c8035a92a0..e6554cef60b20952f592fb759bf18773429d5b72 100644 (file)
@@ -33,6 +33,7 @@ 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);
+static uint32_t ctz(uint64_t, unsigned);
 
 
 void
@@ -201,6 +202,9 @@ check_result(const irop_t *op, const test_data_t *data)
    case Iop_ClzNat32: expected = clz(opnd, 32); break;
    case Iop_ClzNat64: expected = clz(opnd, 64); break;
 
+   case Iop_CtzNat32: expected = ctz(opnd, 32); break;
+   case Iop_CtzNat64: expected = ctz(opnd, 64); break;
+
    default:
       panic("%s: operator %s not handled\n", __func__, op->name);
    }
@@ -283,3 +287,22 @@ clz(uint64_t value, unsigned num_bits)
    }
    return num_bits - last_seen_1bit;
 }
+
+
+static uint32_t
+ctz(uint64_t value, unsigned num_bits )
+{
+  unsigned count = 0;
+  unsigned num_nibbles = num_bits / 4;
+
+  for (unsigned i = 0; i < num_nibbles; ++i) {
+    UInt nibble = value & 0xF;
+    if ((nibble & 0x1) == 0x1) return count;
+    if ((nibble & 0x2) == 0x2) return count + 1;
+    if ((nibble & 0x4) == 0x4) return count + 2;
+    if ((nibble & 0x8) == 0x8) return count + 3;
+    count  += 4;
+    value >>= 4;
+  }
+  return count;
+}