From: Florian Krohm Date: Mon, 14 Jul 2025 13:11:01 +0000 (+0000) Subject: Enable folding for Iop_Left8/16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1831258a9ec588dd921327d56708e93a08456f32;p=thirdparty%2Fvalgrind.git Enable folding for Iop_Left8/16 In iropt-test add independent implementation of the "Left" operator for checking purposes. --- diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 9a3f39c2c..52b8e0957 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -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); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index b22434dab..45b0e728c 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -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 }, diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 51ad51505..537c29a72 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -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__); + } +}