From: Florian Krohm Date: Wed, 16 Jul 2025 14:54:44 +0000 (+0000) Subject: Constant folding for Iop_ClzNat32/64. (BZ 506211) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c164cf37aca7661f76440e14d817dcfeb4c4fc82;p=thirdparty%2Fvalgrind.git Constant folding for Iop_ClzNat32/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 f0458cb28..140899480 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -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))); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index e73ec46a8..1d06919d1 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -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 diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index bb2613848..6d664a1b8 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -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; +}