https://sourceware.org/cgit/valgrind/commit/?id=1831258a9ec588dd921327d56708e93a08456f32
commit 1831258a9ec588dd921327d56708e93a08456f32
Author: Florian Krohm <fl...@ei...>
Date: Mon Jul 14 13:11:01 2025 +0000
Enable folding for Iop_Left8/16
In iropt-test add independent implementation of the "Left" operator
for checking purposes.
Diff:
---
VEX/priv/ir_opt.c | 16 ++++++++++++++
none/tests/iropt-test/irops.tab | 4 ++--
none/tests/iropt-test/unary.c | 49 ++++++++++++++++++++++++++++++-----------
3 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c
index 9a3f39c2c9..52b8e09571 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 b22434dab1..45b0e728cc 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 51ad51505b..537c29a723 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__);
+ }
+}
|