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);
{ 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 },
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
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);
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__);
+ }
+}