From 25b9956679338c2150a7ea089be53e1f6a6f3150 Mon Sep 17 00:00:00 2001 From: Florian Krohm Date: Fri, 22 Aug 2025 17:48:23 +0000 Subject: [PATCH] iropt-test: Run tests with and without constant folding. That way we can check whether the result of constant folding matches the value computed by the insn sequence that is generated to implement a specific IROp. Bugs were found for all architectures. s390 has been fixed. The other architectures are currently disabled. - irops.tab modified to enable only those IROps that are actually implemented for a given architecture. Architectures considered here are amd64, x86, ppc32, ppc64be/le - IRICB_iropt_payload amended to store both the folded and unfolded result - In valgrind_execute_test call IR injection twice: with and without constant folding enabled (--vex-iropt-fold-expr=yes/no) --- VEX/priv/ir_inject.c | 26 ++--- VEX/pub/libvex.h | 3 +- none/tests/iropt-test/irops.tab | 191 ++++++++++++++++++------------- none/tests/iropt-test/main.c | 76 +++++++++++- none/tests/iropt-test/valgrind.c | 64 ++++++++--- none/tests/iropt-test/vtest.h | 4 +- 6 files changed, 253 insertions(+), 111 deletions(-) diff --git a/VEX/priv/ir_inject.c b/VEX/priv/ir_inject.c index 750bb588d..04228538f 100644 --- a/VEX/priv/ir_inject.c +++ b/VEX/priv/ir_inject.c @@ -31,6 +31,7 @@ #include "libvex_ir.h" #include "libvex.h" #include "main_util.h" +#include "main_globals.h" // vex_control /* Convenience macros for readibility */ #define mkU1(v) IRExpr_Const(IRConst_U1(v)) @@ -364,31 +365,28 @@ vex_inject_ir_iropt(IRSB *irsb, IREndness endian) vpanic("unsupported operator"); } + if (! vex_control.iropt_fold_expr) { + store(irsb, endian, iricb.result_nofold, expr); + return; + } + /* Make sure the expression gets folded ! */ IRExpr *env[1] = { 0 }; IRExpr *res = foldIRExpr(env, expr); +// vex_printf("FOLDED RESULT "); ppIRExpr(res); vex_printf("\n"); + if (res->tag != Iex_Const) { vex_printf("*** "); ppIROp(iricb.op); vex_printf(": not folded: result = "); ppIRExpr(res); vex_printf("\n"); - *(ULong *)iricb.result = 0; // whatever - return; - } - - /* Store the folded result in the IRICB. We're only handling integers - up to 64-bit wide. */ - switch (iricb.t_result) { - case Ity_I1: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U1; break; - case Ity_I8: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U8; break; - case Ity_I16: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U16; break; - case Ity_I32: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U32; break; - case Ity_I64: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U64; break; - default: - vpanic("unsupported type"); +// *(ULong *)iricb.result_fold = 0; // whatever +// return; + res = mkU32(0); // whatever } + store(irsb, endian, iricb.result_fold, res); } diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index da295f85f..e580160d3 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -1001,7 +1001,8 @@ typedef typedef struct { IROp op; // the operation to perform - HWord result; // address of the result + HWord result_fold; // address of the result (with folding) + HWord result_nofold; // address of the result (without folding) HWord opnd1; // address of 1st operand HWord opnd2; // address of 2nd operand IRType t_result; // type of result diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index f2ffd007c..c65ff4cfb 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -24,6 +24,35 @@ #define OPNAME(op) #op, Iop_##op +#define A(x) ARCH_##x + +#define ARCH_ppc32 0x0001 +#define ARCH_ppc64be 0x0002 +#define ARCH_ppc64le 0x0004 +#define ARCH_ppc64 (ARCH_ppc64be | ARCH_ppc64le) +#define ARCH_ppc (ARCH_ppc32 | ARCH_ppc64) +#define ARCH_amd64 0x0008 +#define ARCH_x86 0x0010 +#define ARCH_s390 0x0020 +#define ARCH_ALL 0x003F // OR of all above + +/* FIXME: Add support for mips, arm, and riscv. + When doing so ARCH_ALL needs to be adjusted */ +#if 0 +#define ARCH_mips32 0x0040 +#define ARCH_mips64 0x0080 +#define ARCH_mips (mips32 | mips64) +#define ARCH_nanomips 0x0100 +#define ARCH_arm 0x0200 +#define ARCH_arm64 0x0400 +#define ARCH_riscv64 0x0800 +#endif + +#define ONLY(x) .enabled_arch = A(x) +#define ONLY2(x1,x2) .enabled_arch = A(x1) | A(x2) +#define EXCEPT(x) .enabled_arch = ARCH_ALL & ~A(x) +#define EXCEPT2(x1,x2) .enabled_arch = ARCH_ALL & ~(A(x1) | A(x2)) + /* Definition of IROps: - no IROps having floating point operands or result - no IROPs having vector operands or results (V128, V256) @@ -39,7 +68,8 @@ { OPNAME(1Uto8), Ity_I8, 1, Ity_I1, }, // { OPNAME(1Uto16), Ity_I16, 1, Ity_I1, }, // missing in libvex_ir.h { OPNAME(1Uto32), Ity_I32, 1, Ity_I1, }, - { OPNAME(1Uto64), Ity_I64, 1, Ity_I1, }, + { OPNAME(1Uto64), Ity_I64, 1, Ity_I1, EXCEPT2(ppc32,x86) }, + { OPNAME(1Sto8), Ity_I8, 1, Ity_I1, }, { OPNAME(1Sto16), Ity_I16, 1, Ity_I1, }, { OPNAME(1Sto32), Ity_I32, 1, Ity_I1, }, @@ -47,15 +77,16 @@ { OPNAME(8Uto16), Ity_I16, 1, Ity_I8, }, { OPNAME(8Uto32), Ity_I32, 1, Ity_I8, }, - { OPNAME(8Uto64), Ity_I64, 1, Ity_I8, }, + { OPNAME(8Uto64), Ity_I64, 1, Ity_I8, EXCEPT2(ppc32, x86) }, + { OPNAME(8Sto16), Ity_I16, 1, Ity_I8, }, { OPNAME(8Sto32), Ity_I32, 1, Ity_I8, }, - { OPNAME(8Sto64), Ity_I64, 1, Ity_I8, }, + { OPNAME(8Sto64), Ity_I64, 1, Ity_I8, EXCEPT2(ppc32, x86) }, { OPNAME(16Uto32), Ity_I32, 1, Ity_I16, }, - { OPNAME(16Uto64), Ity_I64, 1, Ity_I16, }, + { OPNAME(16Uto64), Ity_I64, 1, Ity_I16, EXCEPT(ppc32) }, { OPNAME(16Sto32), Ity_I32, 1, Ity_I16, }, - { OPNAME(16Sto64), Ity_I64, 1, Ity_I16, }, + { OPNAME(16Sto64), Ity_I64, 1, Ity_I16, EXCEPT2(ppc32, x86) }, { OPNAME(32Uto64), Ity_I64, 1, Ity_I32, }, { OPNAME(32Sto64), Ity_I64, 1, Ity_I32, }, @@ -70,19 +101,20 @@ { OPNAME(32to16), Ity_I16, 1, Ity_I32, }, { OPNAME(32HIto16), Ity_I16, 1, Ity_I32, }, - { OPNAME(64to1), Ity_I1, 1, Ity_I64, }, - { OPNAME(64to8), Ity_I8, 1, Ity_I64, }, - { OPNAME(64to16), Ity_I16, 1, Ity_I64, }, + { OPNAME(64to1), Ity_I1, 1, Ity_I64, EXCEPT2(ppc32, x86) }, + { OPNAME(64to8), Ity_I8, 1, Ity_I64, EXCEPT2(ppc32, x86) }, + { OPNAME(64to16), Ity_I16, 1, Ity_I64, EXCEPT2(ppc32, x86) }, + { OPNAME(64to32), Ity_I32, 1, Ity_I64, }, { OPNAME(64HIto32), Ity_I32, 1, Ity_I64, }, // { OPNAME(128to64), Ity_I64, 1, Ity_I128, }, // 128 bit // { OPNAME(128HIto64), Ity_I64, 1, Ity_I128, }, // 128 bit - { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8 }, - { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, - { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32 }, - { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64 }, + { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8, }, + { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16, EXCEPT(ppc) }, + { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32, }, + { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64, }, { OPNAME(CmpwNEZ32), Ity_I32, 1, Ity_I32 }, { OPNAME(CmpwNEZ64), Ity_I64, 1, Ity_I64 }, @@ -98,16 +130,14 @@ // { 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 }, - { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, - - { 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 }, + { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32, ONLY2(ppc, x86) }, + { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64, EXCEPT2(ppc32, x86) }, + { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32, ONLY2(ppc, x86) }, + { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64, ONLY2(ppc64, amd64) }, + { OPNAME(PopCount32), Ity_I32, 1, Ity_I32, ONLY(ppc) }, + { OPNAME(PopCount64), Ity_I64, 1, Ity_I64, ONLY(ppc64) }, // BINARY { OPNAME(Add8), Ity_I8, 2, Ity_I8, Ity_I8 }, @@ -118,37 +148,37 @@ { OPNAME(Sub8), Ity_I8, 2, Ity_I8, Ity_I8 }, { OPNAME(Sub16), Ity_I16, 2, Ity_I16, Ity_I16 }, { OPNAME(Sub32), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(Sub64), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(Sub64), Ity_I64, 2, Ity_I64, Ity_I64, EXCEPT(ppc32) }, - { OPNAME(Mul8), Ity_I8, 2, Ity_I8, Ity_I8 }, - { OPNAME(Mul16), Ity_I16, 2, Ity_I16, Ity_I16 }, - { OPNAME(Mul32), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(Mul64), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(Mul8), Ity_I8, 2, Ity_I8, Ity_I8, ONLY(s390) }, + { OPNAME(Mul16), Ity_I16, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(Mul32), Ity_I32, 2, Ity_I32, Ity_I32, }, + { OPNAME(Mul64), Ity_I64, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) }, - { OPNAME(MullU8), Ity_I16, 2, Ity_I8, Ity_I8 }, - { OPNAME(MullU16), Ity_I32, 2, Ity_I16, Ity_I16 }, - { OPNAME(MullU32), Ity_I64, 2, Ity_I32, Ity_I32 }, -// { OPNAME(MullU64), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit + { OPNAME(MullU8), Ity_I16, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(MullU16), Ity_I32, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(MullU32), Ity_I64, 2, Ity_I32, Ity_I32, }, +// { OPNAME(MullU64), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit - { OPNAME(MullS8), Ity_I16, 2, Ity_I8, Ity_I8 }, - { OPNAME(MullS16), Ity_I32, 2, Ity_I16, Ity_I16 }, - { OPNAME(MullS32), Ity_I64, 2, Ity_I32, Ity_I32 }, -// { OPNAME(MullS64), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit + { OPNAME(MullS8), Ity_I16, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(MullS16), Ity_I32, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(MullS32), Ity_I64, 2, Ity_I32, Ity_I32, }, +// { OPNAME(MullS64), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit - { OPNAME(DivU32), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(DivU64), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(DivU32), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, + { OPNAME(DivU64), Ity_I64, 2, Ity_I64, Ity_I64, ONLY(ppc64) }, // { OPNAME(DivU128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit - { OPNAME(DivS32), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(DivS64), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(DivS32), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, + { OPNAME(DivS64), Ity_I64, 2, Ity_I64, Ity_I64, ONLY(ppc64) }, // { OPNAME(DivS128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit - { OPNAME(DivU32E), Ity_I32, 2, Ity_I32, Ity_I32 }, -// { OPNAME(DivU64E), Ity_I64, 2, Ity_I64, Ity_I64 }, // 128 bit + { OPNAME(DivU32E), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, +// { OPNAME(DivU64E), Ity_I64, 2, Ity_I64, Ity_I64, }, // 128 bit // { OPNAME(DivU128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit - { OPNAME(DivS32E), Ity_I32, 2, Ity_I32, Ity_I32 }, -// { OPNAME(DivS64E), Ity_I32, 2, Ity_I32, Ity_I32 }, // 128 bit + { OPNAME(DivS32E), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, +// { OPNAME(DivS64E), Ity_I32, 2, Ity_I32, Ity_I32, }, // 128 bit // { OPNAME(DivS128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit // { OPNAME(DivModU32to32), Ity_I64, 2, Ity_I32, Ity_I64 }, // no folding yet @@ -167,17 +197,17 @@ { OPNAME(Shl8), Ity_I8, 2, Ity_I8, Ity_I8 }, { OPNAME(Shl16), Ity_I16, 2, Ity_I16, Ity_I8 }, { OPNAME(Shl32), Ity_I32, 2, Ity_I32, Ity_I8 }, - { OPNAME(Shl64), Ity_I64, 2, Ity_I64, Ity_I8 }, + { OPNAME(Shl64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) }, { OPNAME(Shr8), Ity_I8, 2, Ity_I8, Ity_I8 }, { OPNAME(Shr16), Ity_I16, 2, Ity_I16, Ity_I8 }, { OPNAME(Shr32), Ity_I32, 2, Ity_I32, Ity_I8 }, - { OPNAME(Shr64), Ity_I64, 2, Ity_I64, Ity_I8 }, + { OPNAME(Shr64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) }, { OPNAME(Sar8), Ity_I8, 2, Ity_I8, Ity_I8 }, { OPNAME(Sar16), Ity_I16, 2, Ity_I16, Ity_I8 }, { OPNAME(Sar32), Ity_I32, 2, Ity_I32, Ity_I8 }, - { OPNAME(Sar64), Ity_I64, 2, Ity_I64, Ity_I8 }, + { OPNAME(Sar64), Ity_I64, 2, Ity_I64, Ity_I8, EXCEPT(ppc32) }, { OPNAME(Or1), Ity_I1, 2, Ity_I1, Ity_I1 }, { OPNAME(Or8), Ity_I8, 2, Ity_I8, Ity_I8 }, @@ -197,52 +227,51 @@ { OPNAME(Xor32), Ity_I32, 2, Ity_I32, Ity_I32 }, { OPNAME(Xor64), Ity_I64, 2, Ity_I64, Ity_I64 }, - { OPNAME(CmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8 }, - { OPNAME(CmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16 }, - { OPNAME(CmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64 }, - - { OPNAME(CmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, - { OPNAME(CmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, - { OPNAME(CmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(CmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(CmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT(ppc32) }, - { OPNAME(CmpLT32U), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpLT64U), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpNE8), Ity_I1, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(CmpNE16), Ity_I1, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(CmpNE32), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpNE64), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT(ppc32) }, - { OPNAME(CmpLT32S), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpLT64S), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpLT32U), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpLT64U), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) }, - { OPNAME(CmpLE32U), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpLE64U), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpLT32S), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpLT64S), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) }, - { OPNAME(CmpLE32S), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpLE64S), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpLE32U), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpLE64U), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) }, - { OPNAME(CasCmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8 }, - { OPNAME(CasCmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16 }, - { OPNAME(CasCmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CasCmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpLE32S), Ity_I1, 2, Ity_I32, Ity_I32, }, + { OPNAME(CmpLE64S), Ity_I1, 2, Ity_I64, Ity_I64, EXCEPT2(ppc32, x86) }, - { OPNAME(CasCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, - { OPNAME(CasCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, - { OPNAME(CasCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(CasCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CasCmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(CasCmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(CasCmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32, EXCEPT(ppc) }, + { OPNAME(CasCmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64, ONLY2(s390, amd64) }, - { OPNAME(ExpCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, - { OPNAME(ExpCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, - { OPNAME(ExpCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, - { OPNAME(ExpCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + { OPNAME(CasCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(CasCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(CasCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32, EXCEPT(ppc) }, + { OPNAME(CasCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64, ONLY2(s390, amd64) }, - { OPNAME(CmpORD32U), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpORD64U), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(ExpCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8, ONLY(s390) }, + { OPNAME(ExpCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16, ONLY2(s390, x86) }, + { OPNAME(ExpCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32, EXCEPT(ppc) }, + { OPNAME(ExpCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64, ONLY2(s390, amd64) }, - { OPNAME(CmpORD32S), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(CmpORD64S), Ity_I64, 2, Ity_I64, Ity_I64 }, + { OPNAME(CmpORD32U), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, + { OPNAME(CmpORD32S), Ity_I32, 2, Ity_I32, Ity_I32, ONLY(ppc) }, + { OPNAME(CmpORD64U), Ity_I64, 2, Ity_I64, Ity_I64, ONLY(ppc64) }, + { OPNAME(CmpORD64S), Ity_I64, 2, Ity_I64, Ity_I64, ONLY(ppc64) }, { OPNAME(Max32U), Ity_I32, 2, Ity_I32, Ity_I32 }, - { OPNAME(8HLto16), Ity_I16, 2, Ity_I8, Ity_I8 }, - { OPNAME(16HLto32), Ity_I32, 2, Ity_I16, Ity_I16 }, - { OPNAME(32HLto64), Ity_I64, 2, Ity_I32, Ity_I32 }, -// { OPNAME(64HLto128), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit + { OPNAME(8HLto16), Ity_I16, 2, Ity_I8, Ity_I8, EXCEPT(ppc) }, + { OPNAME(16HLto32), Ity_I32, 2, Ity_I16, Ity_I16, EXCEPT(ppc) }, + { OPNAME(32HLto64), Ity_I64, 2, Ity_I32, Ity_I32, }, +// { OPNAME(64HLto128), Ity_I128, 2, Ity_I64, Ity_I64, }, // 128 bit diff --git a/none/tests/iropt-test/main.c b/none/tests/iropt-test/main.c index 8fcf9fb45..29bc1c71f 100644 --- a/none/tests/iropt-test/main.c +++ b/none/tests/iropt-test/main.c @@ -36,6 +36,7 @@ static irop_t irops[] = { static void check_irops_table(void); static test_data_t *new_test_data(const irop_t *); +static int is_enabled(const irop_t *); int verbose = 0; unsigned num_random_tests; @@ -44,6 +45,10 @@ unsigned num_random_tests; int main(int argc, char *argv[]) { +// FIXME: temporarily until ppc,amd64,x86 have been fixed +#if !defined(__s390x__) + return 0; +#endif assert(sizeof(long long) == 8); srand48(42L); @@ -76,6 +81,8 @@ main(int argc, char *argv[]) for (unsigned i = 0; i < NUM_EL(irops); ++i) { const irop_t *op = irops +i; + if (! is_enabled(op)) continue; + if (verbose) printf("Testing operator %s\n", op->name); @@ -130,7 +137,8 @@ new_test_data(const irop_t *op) memset(data, 0x0, sizeof *data); // initialise - data->result.type = op->result_type; + data->result_fold.type = op->result_type; + data->result_nofold.type = op->result_type; data->opnds[0].type = op->opnd1_type; if (op->num_opnds > 1) @@ -138,3 +146,69 @@ new_test_data(const irop_t *op) return data; } + + +static int +is_enabled(const irop_t *op) +{ + /* For convenience of specification in irops.tab a zero value + means that the IROp is implemented. */ + if (op->enabled_arch == 0) return 1; + +#ifdef __x86_64__ + return op->enabled_arch & ARCH_amd64; +#endif +#ifdef __i386__ + return op->enabled_arch & ARCH_x86; +#endif +#ifdef __s390x__ + return op->enabled_arch & ARCH_s390; +#endif +#ifdef __powerpc__ /* defined for both 32-bit and 64-bit */ +#define MIN_POWER_ISA "../../../tests/min_power_isa" + int rc; + + switch (op->op) { + case Iop_DivS64E: + case Iop_DivU64E: + case Iop_DivU32E: + case Iop_DivS32E: + /* IROps require a processor that supports ISA 2.06 (Power 7) + or newer */ + rc = system(MIN_POWER_ISA " 2.06 ") / 256; + break; + + case Iop_DivU128: + case Iop_DivS128: + case Iop_DivU128E: + case Iop_DivS128E: + case Iop_ModU128: + case Iop_ModS128: + /* IROps require a processor that supports ISA 3.10 (Power 10) + or newer */ + rc = system(MIN_POWER_ISA " 3.1 ") / 256; + break; + + default: + rc = 0; + break; + } + + /* MIN_POWER_ISA returns 0 if the underlying HW supports the specified + ISA or newer. Returns 1 if the HW does not support the specified ISA. + Returns 2 on error. */ + switch (rc) { + case 0: +#ifdef __powerpc64__ + return op->enabled_arch & ARCH_ppc64; +#endif + return op->enabled_arch & ARCH_ppc32; + case 1: + return 0; + default: + panic("min_power_isa() return code is invalid.\n"); + } +#endif + + return 0; +} diff --git a/none/tests/iropt-test/valgrind.c b/none/tests/iropt-test/valgrind.c index 004c8a09a..d6ac5f222 100644 --- a/none/tests/iropt-test/valgrind.c +++ b/none/tests/iropt-test/valgrind.c @@ -26,6 +26,8 @@ #include "valgrind.h" // VALGRIND_VEX_INJECT_IR #include "vtest.h" +#define host_is_big_endian() ((*(short *)(&(int){ 0x11223344 })) == 0x1122) + static IRICB iricb; /* Return a completely initialised control block */ @@ -37,10 +39,11 @@ new_iricb(const irop_t *op, test_data_t *data) memset(&cb, 0x0, sizeof cb); cb.op = op->op; - cb.result = (HWord)&data->result.value; + cb.result_fold = (HWord)&data->result_fold.value; + cb.result_nofold = (HWord)&data->result_nofold.value; cb.opnd1 = (HWord)&data->opnds[0].value; cb.opnd2 = (HWord)&data->opnds[1].value; - cb.t_result = data->result.type; + cb.t_result = data->result_fold.type; cb.t_opnd1 = data->opnds[0].type; cb.t_opnd2 = data->opnds[1].type; @@ -80,39 +83,74 @@ valgrind_execute_test(const irop_t *op, test_data_t *data, uint64_t expected) for (unsigned i = 0; i < op->num_opnds; ++i) { const opnd_t *opnd = data->opnds + i; - printf("opnd %u: value = ", i); + printf("opnd %u: value = ", i); print_value(stdout, opnd->value, bitsof_irtype(opnd->type)); printf("\n"); } } + VALGRIND_CLO_CHANGE("--vex-iropt-fold-expr=yes"); + valgrind_vex_inject_ir(); + VALGRIND_CLO_CHANGE("--vex-iropt-fold-expr=no"); valgrind_vex_inject_ir(); - uint64_t result = data->result.value; - unsigned num_result_bits = bitsof_irtype(data->result.type); + uint64_t result_fold = data->result_fold.value; + uint64_t result_nofold = data->result_nofold.value; + unsigned num_result_bits = bitsof_irtype(data->result_fold.type); + +// printf("NOFOLD RESULT = %016lx\n", result_nofold); + + if (host_is_big_endian()) { + switch (num_result_bits) { + case 8: + result_fold >>= 56; + result_nofold >>= 56; + break; + case 16: + result_fold >>= 48; + result_nofold >>= 48; + break; + case 1: /* See comment in vbit-test/vbits.h */ + case 32: + result_fold >>= 32; + result_nofold >>= 32; + break; + case 64: + break; + default: + panic("%s: #bits = %u not handled\n", __func__, num_result_bits); + } + } + if (verbose > 1) { - printf("result: value = "); - print_value(stdout, result, num_result_bits); + printf("result fold: value = "); + print_value(stdout, result_fold, num_result_bits); + printf("\n"); + printf("result nofold: value = "); + print_value(stdout, result_nofold, num_result_bits); printf("\n"); - printf("expected: value = "); + printf("expected: value = "); print_value(stdout, expected, num_result_bits); printf("\n"); } /* Check result */ - if (result != expected) { + if (result_fold != result_nofold || result_fold != expected) { fprintf(stderr, "*** Incorrect result for operator %s\n", op->name); for (unsigned i = 0; i < op->num_opnds; ++i) { const opnd_t *opnd = data->opnds + i; - fprintf(stderr, " opnd %u: ", i); + fprintf(stderr, " opnd %u: ", i); print_value(stderr, opnd->value, bitsof_irtype(opnd->type)); fprintf(stderr, "\n"); } - fprintf(stderr, " result: "); - print_value(stderr, result, num_result_bits); + fprintf(stderr, " result fold: "); + print_value(stderr, result_fold, num_result_bits); + fprintf(stderr, "\n"); + fprintf(stderr, " result nofold: "); + print_value(stderr, result_nofold, num_result_bits); fprintf(stderr, "\n"); - fprintf(stderr, " expect: "); + fprintf(stderr, " result expected: "); print_value(stderr, expected, num_result_bits); fprintf(stderr, "\n"); } diff --git a/none/tests/iropt-test/vtest.h b/none/tests/iropt-test/vtest.h index f31f3c3ce..cee5ddacb 100644 --- a/none/tests/iropt-test/vtest.h +++ b/none/tests/iropt-test/vtest.h @@ -39,6 +39,7 @@ typedef struct { unsigned num_opnds; IRType opnd1_type; IRType opnd2_type; + unsigned enabled_arch; } irop_t; @@ -55,7 +56,8 @@ typedef struct { /* Carries the data needed to execute and evaluate a test. I.e. inputs and result. */ typedef struct { - opnd_t result; + opnd_t result_fold; + opnd_t result_nofold; opnd_t opnds[MAX_OPERANDS]; } test_data_t; -- 2.47.2