From: Florian Krohm Date: Wed, 16 Jul 2025 17:43:34 +0000 (+0000) Subject: Constant folding for Iop_CtzNat32/64. (BZ 506211) X-Git-Tag: VALGRIND_3_26_0~295 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0593738843903c7c2d6299bf2a47f63ebc08e947;p=thirdparty%2Fvalgrind.git Constant folding for Iop_CtzNat32/64. (BZ 506211) Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211 --- diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 140899480..c37ff08a7 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -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))); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index 1d06919d1..02afa6423 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -101,8 +101,8 @@ { 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 }, diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 6d664a1b8..e6554cef6 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -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; +}