From: Carl Love Date: Tue, 3 Nov 2015 17:48:04 +0000 (+0000) Subject: Add ISA 2.07 vbit test support X-Git-Tag: svn/VALGRIND_3_12_0~303 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79c80505d388c8556ca1de4d15aed0d5cb01c98f;p=thirdparty%2Fvalgrind.git Add ISA 2.07 vbit test support The ISA 2.07 support adds new Iops as well as support for some existing Iops. None of these Iops have been enabled in the vbit tester. This commit adds the needed support to the files in memcheck/tests/vbit-test. These changes add support for additional immediate operands and additional undefined bit checking functions. There are additional changes to files VEX/priv/ir_inject.c and VEX/pub/libvex.h that are in VEX commit 3202 Bugzilla 354797 was created for this issue. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15720 --- diff --git a/memcheck/tests/vbit-test/binary.c b/memcheck/tests/vbit-test/binary.c index b75e58f18e..5fc712dc3d 100644 --- a/memcheck/tests/vbit-test/binary.c +++ b/memcheck/tests/vbit-test/binary.c @@ -75,6 +75,7 @@ check_result_for_binary(const irop_t *op, const test_data_t *data) const opnd_t *result = &data->result; const opnd_t *opnd1 = &data->opnds[0]; const opnd_t *opnd2 = &data->opnds[1]; + opnd_t tmp; vbits_t expected_vbits; /* Only handle those undef-kinds that actually occur. */ @@ -84,6 +85,9 @@ check_result_for_binary(const irop_t *op, const test_data_t *data) break; case UNDEF_ALL: + /* Iop_ShlD64, Iop_ShrD64, Iop_ShlD128, Iop_ShrD128 have + * one immediate operand in operand 2. + */ expected_vbits = undefined_vbits(result->vbits.num_bits); break; @@ -187,6 +191,161 @@ check_result_for_binary(const irop_t *op, const test_data_t *data) opnd2->vbits.num_bits); break; + case UNDEF_ALL_64x2: + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(64, 2, + or_vbits(opnd1->vbits, opnd2->vbits)); + break; + + case UNDEF_ALL_32x4: + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(32, 4, + or_vbits(opnd1->vbits, opnd2->vbits)); + break; + + case UNDEF_ALL_16x8: + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(16, 8, + or_vbits(opnd1->vbits, opnd2->vbits)); + break; + + case UNDEF_ALL_8x16: + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(8, 16, + or_vbits(opnd1->vbits, opnd2->vbits)); + break; + + case UNDEF_ALL_32x4_EVEN: + /* Only even input bytes are used, result can be twice as wide */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(64, 2, + undefined_vbits_128_even_element(32, 4, + or_vbits(opnd1->vbits, opnd2->vbits))); + break; + + case UNDEF_ALL_16x8_EVEN: + /* Only even input bytes are used, result can be twice as wide */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(32, 4, + undefined_vbits_128_even_element(16, 8, + or_vbits(opnd1->vbits, opnd2->vbits))); + break; + + case UNDEF_ALL_8x16_EVEN: + /* Only even input bytes are used, result can be twice as wide */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = + undefined_vbits_BxE(16, 8, + undefined_vbits_128_even_element(8, 16, + or_vbits(opnd1->vbits, opnd2->vbits))); + break; + + case UNDEF_64x2_ROTATE: + /* Rotate left each element in opnd1 by the amount in the corresponding + * element of opnd2. + */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + /* Setup the tmp to match what the vbit tester seems to use. I can't + * use opnd2-value since valgrind doesn't think it has been set. + */ + tmp.value.u128[0] = -1; + tmp.value.u128[1] = -1; + /* Calculate expected for the first operand when it is shifted. + * If any of the vbits are set for the shift field of the second operand + * then the result of the expected result for that element is all 1's. + */ + expected_vbits = or_vbits(undefined_vbits_BxE_rotate(64, 2, opnd1->vbits, + tmp.value), + undefined_vbits_BxE(64, 2, opnd2->vbits)); + break; + + case UNDEF_32x4_ROTATE: + /* Rotate left each element in opnd1 by the amount in the corresponding + * element of opnd2. + */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = undefined_vbits_BxE_rotate(32, 4, opnd1->vbits, + opnd2->value); + break; + + case UNDEF_16x8_ROTATE: + /* Rotate left each element in opnd1 by the amount in the corresponding + * element of opnd2. + */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = undefined_vbits_BxE_rotate(16, 8, opnd1->vbits, + opnd2->value); + break; + + case UNDEF_8x16_ROTATE: + /* Rotate left each element in opnd1 by the amount in the corresponding + * element of opnd2. + */ + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + expected_vbits = undefined_vbits_BxE_rotate(16, 8, opnd1->vbits, + opnd2->value); + break; + + case UNDEF_SOME: + /* The result for the Iop_SHA256 and Iop_SHA256 is a secure hash. If + * one of the input bits is not defined there must be atleast one + * undefined bit in the output. Which bit and how many depends on + * which bit is undefined. Don't know the secure hash algorithm so + * we can only make sure at least one of the result bits is set. + * + * The Iop_SHA256, Iop_SHA512 iops have one immediate value in the + * second operand. + */ + expected_vbits.num_bits = result->vbits.num_bits; + + if ((result->vbits.bits.u128[0] != 0) || + (result->vbits.bits.u128[1] != 0)) { + expected_vbits.bits.u128[0] = result->vbits.bits.u128[0]; + expected_vbits.bits.u128[1] = result->vbits.bits.u128[1]; + + } else { + /* The input had at least one vbit set but the result doesn't have any + * bit set. Set them all so we will trigger the error on the call + * to complain(). + */ + expected_vbits.bits.u128[0] = ~0x0ULL; + expected_vbits.bits.u128[1] = ~0x0ULL; + } + break; + + case UNDEF_NARROW256_AtoB: + assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); + switch(op->op) { + case Iop_NarrowBin64to32x4: + expected_vbits = + undefined_vbits_Narrow256_AtoB(64, 32, opnd1->vbits, opnd1->value, + opnd2->vbits, opnd2->value, + False); + break; + case Iop_QNarrowBin64Sto32Sx4: + expected_vbits = + undefined_vbits_Narrow256_AtoB(64, 32, opnd1->vbits, opnd1->value, + opnd2->vbits, opnd2->value, + True); + break; + case Iop_QNarrowBin64Uto32Ux4: + expected_vbits = + undefined_vbits_Narrow256_AtoB(64, 32, opnd1->vbits, opnd1->value, + opnd2->vbits, opnd2->value, + True); + break; + default: + fprintf(stderr, "ERROR, unknown Iop for UNDEF_NARROW256_AtoB\n"); + panic(__func__); + } + break; + default: panic(__func__); } @@ -225,7 +384,7 @@ test_shift(const irop_t *op, test_data_t *data) // 2nd (right) operand /* If the operand is an immediate value, there are no v-bits to set. */ - if (op->shift_amount_is_immediate) return tests_done; + if (!op->immediate_index) return tests_done; num_input_bits = bitsof_irtype(opnds[1].type); @@ -462,9 +621,10 @@ test_binary_op(const irop_t *op, test_data_t *data) operand. */ for (i = 0; i < 2; ++i) { - /* If this is a shift op that requires an immediate shift amount, - do not iterate the v-bits of the 2nd operand */ - if (i == 1 && op->shift_amount_is_immediate) break; + /* If this is a Iop that requires an immediate amount, + do not iterate the v-bits of the operand */ + if (((i+1) == op->immediate_index) + && (op->immediate_index)) break; num_input_bits = bitsof_irtype(opnds[i].type); opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); @@ -486,8 +646,13 @@ test_binary_op(const irop_t *op, test_data_t *data) assert(sizeof xx.v1 == sizeof xx.v2.u64); assert(xx.v1 == xx.v2.u64); */ - if (op->shift_amount_is_immediate) + + if (op->immediate_index > 0) { + assert((op->immediate_type == Ity_I8) + || (op->immediate_type == Ity_I16) + || (op->immediate_type == Ity_I32)); opnds[1].value.u64 = 1; + } for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { opnds[i].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[i].type)); diff --git a/memcheck/tests/vbit-test/irops.c b/memcheck/tests/vbit-test/irops.c index 0395efec55..b45c326a6a 100644 --- a/memcheck/tests/vbit-test/irops.c +++ b/memcheck/tests/vbit-test/irops.c @@ -1,3 +1,4 @@ + /* -*- mode: C; c-basic-offset: 3; -*- */ /* @@ -729,12 +730,13 @@ static irop_t irops[] = { { DEFOP(Iop_MulHi32Ux4, UNDEF_UNKNOWN), }, { DEFOP(Iop_MulHi16Sx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_MulHi32Sx4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven8Ux16, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven16Ux8, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven32Ux4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven8Sx16, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven16Sx8, UNDEF_UNKNOWN), }, - { DEFOP(Iop_MullEven32Sx4, UNDEF_UNKNOWN), }, + /* Result of the Iop_MullEvenBxE is 2*BxE/2 */ + { DEFOP(Iop_MullEven8Ux16, UNDEF_ALL_8x16_EVEN), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_MullEven16Ux8, UNDEF_ALL_16x8_EVEN), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_MullEven32Ux4, UNDEF_ALL_32x4_EVEN), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_MullEven8Sx16, UNDEF_ALL_8x16_EVEN), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_MullEven16Sx8, UNDEF_ALL_16x8_EVEN), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_MullEven32Sx4, UNDEF_ALL_32x4_EVEN), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Mull8Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Mull8Sx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Mull16Ux4, UNDEF_UNKNOWN), }, @@ -772,19 +774,19 @@ static irop_t irops[] = { { DEFOP(Iop_Max8Sx16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Max16Sx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Max32Sx4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Max64Sx2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Max64Sx2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Max8Ux16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Max16Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Max32Ux4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Max64Ux2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Max64Ux2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Min8Sx16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Min16Sx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Min32Sx4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Min64Sx2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Min64Sx2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Min8Ux16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Min16Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Min32Ux4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Min64Ux2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Min64Ux2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_CmpEQ8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_CmpEQ16x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_CmpEQ32x4, UNDEF_UNKNOWN), }, @@ -796,12 +798,12 @@ static irop_t irops[] = { { DEFOP(Iop_CmpGT8Ux16, UNDEF_UNKNOWN), }, { DEFOP(Iop_CmpGT16Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_CmpGT32Ux4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_CmpGT64Ux2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_CmpGT64Ux2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Cnt8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Clz8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Clz16x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Clz32x4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Clz64x2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Clz64x2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_Cls8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Cls16x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Cls32x4, UNDEF_UNKNOWN), }, @@ -836,7 +838,7 @@ static irop_t irops[] = { { DEFOP(Iop_Rol8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_Rol16x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Rol32x4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_Rol64x2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_Rol64x2, UNDEF_64x2_ROTATE), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_QShl8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_QShl16x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_QShl32x4, UNDEF_UNKNOWN), }, @@ -917,18 +919,18 @@ static irop_t irops[] = { { DEFOP(Iop_QNarrowBin32Uto16Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_NarrowBin16to8x16, UNDEF_UNKNOWN), }, { DEFOP(Iop_NarrowBin32to16x8, UNDEF_UNKNOWN), }, - { DEFOP(Iop_NarrowBin64to32x4, UNDEF_UNKNOWN), }, + { DEFOP(Iop_NarrowBin64to32x4, UNDEF_NARROW256_AtoB), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_NarrowUn16to8x8, UNDEF_UNKNOWN), }, { DEFOP(Iop_NarrowUn32to16x4, UNDEF_UNKNOWN), }, { DEFOP(Iop_NarrowUn64to32x2, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn16Sto8Sx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn32Sto16Sx4, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn64Sto32Sx2, UNDEF_UNKNOWN), }, - { DEFOP(Iop_QNarrowBin64Sto32Sx4, UNDEF_UNKNOWN), }, + { DEFOP(Iop_QNarrowBin64Sto32Sx4, UNDEF_NARROW256_AtoB), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_QNarrowUn16Sto8Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn32Sto16Ux4, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn64Sto32Ux2, UNDEF_UNKNOWN), }, - { DEFOP(Iop_QNarrowBin64Uto32Ux4, UNDEF_UNKNOWN), }, + { DEFOP(Iop_QNarrowBin64Uto32Ux4, UNDEF_NARROW256_AtoB), .ppc64 = 1, .ppc32 = 1 }, { DEFOP(Iop_QNarrowUn16Uto8Ux8, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn32Uto16Ux4, UNDEF_UNKNOWN), }, { DEFOP(Iop_QNarrowUn64Uto32Ux2, UNDEF_UNKNOWN), }, @@ -1064,20 +1066,20 @@ static irop_t irops[] = { { DEFOP(Iop_Min32Fx8, UNDEF_UNKNOWN), }, { DEFOP(Iop_Max64Fx4, UNDEF_UNKNOWN), }, { DEFOP(Iop_Min64Fx4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_BCDAdd, UNDEF_UNKNOWN), }, - { DEFOP(Iop_BCDSub, UNDEF_UNKNOWN), }, - { DEFOP(Iop_PolynomialMulAdd8x16, UNDEF_UNKNOWN), }, - { DEFOP(Iop_PolynomialMulAdd16x8, UNDEF_UNKNOWN), }, - { DEFOP(Iop_PolynomialMulAdd32x4, UNDEF_UNKNOWN), }, - { DEFOP(Iop_PolynomialMulAdd64x2, UNDEF_UNKNOWN), }, - { DEFOP(Iop_CipherV128, UNDEF_UNKNOWN), }, - { DEFOP(Iop_CipherLV128, UNDEF_UNKNOWN), }, - { DEFOP(Iop_CipherSV128, UNDEF_UNKNOWN), }, - { DEFOP(Iop_NCipherV128, UNDEF_UNKNOWN), }, - { DEFOP(Iop_NCipherLV128, UNDEF_UNKNOWN), }, - { DEFOP(Iop_SHA512, UNDEF_UNKNOWN), }, - { DEFOP(Iop_SHA256, UNDEF_UNKNOWN), }, - { DEFOP(Iop_PwBitMtxXpose64x2, UNDEF_UNKNOWN), }, + { DEFOP(Iop_BCDAdd, UNDEF_SOME), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_BCDSub, UNDEF_SOME), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_PolynomialMulAdd8x16, UNDEF_ALL_8x16), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_PolynomialMulAdd16x8, UNDEF_ALL_16x8), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_PolynomialMulAdd32x4, UNDEF_ALL_32x4), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_PolynomialMulAdd64x2, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_CipherV128, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_CipherLV128, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_CipherSV128, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_NCipherV128, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_NCipherLV128, UNDEF_ALL_64x2), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_SHA512, UNDEF_SOME), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_SHA256, UNDEF_SOME), .ppc64 = 1, .ppc32 = 1 }, + { DEFOP(Iop_PwBitMtxXpose64x2, UNDEF_64x2_TRANSPOSE), .ppc64 = 1, .ppc32 = 1 }, }; /* Force compile time failure in case libvex_ir.h::IROp was updated @@ -1090,6 +1092,7 @@ STATIC_ASSERT \ irop_t * get_irop(IROp op) { + int rc; unsigned i; for (i = 0; i < sizeof irops / sizeof *irops; ++i) { @@ -1122,7 +1125,6 @@ get_irop(IROp op) case Iop_F64toI64U: case Iop_F128toI32U: case Iop_F128toI64U: { - int rc; /* These IROps require the floating point extension facility */ rc = system(S390X_FEATURES " s390x-fpext"); // s390x_features returns 1 if feature does not exist @@ -1180,8 +1182,7 @@ get_irop(IROp op) case Iop_I64UtoF64: case Iop_I64UtoF32: case Iop_I64StoD64: { - int rc; - /* IROps require a processor that supports ISA 2.06 or newer */ + /* IROps require a processor that supports ISA 2.06 (Power 7) or newer */ rc = system(MIN_POWER_ISA " 2.06 "); rc /= 256; /* MIN_POWER_ISA returns 0 if underlying HW supports the @@ -1189,6 +1190,48 @@ get_irop(IROp op) * the specified ISA. Returns 2 on error. */ if (rc == 1) return NULL; + if (rc > 2) { + panic(" ERROR, min_power_isa() return code is invalid.\n"); + } + } + case Iop_PwBitMtxXpose64x2: + case Iop_Clz64x2: + case Iop_BCDAdd: + case Iop_BCDSub: + case Iop_PolynomialMulAdd8x16: + case Iop_PolynomialMulAdd16x8: + case Iop_PolynomialMulAdd32x4: + case Iop_PolynomialMulAdd64x2: + case Iop_CipherV128: + case Iop_CipherLV128: + case Iop_CipherSV128: + case Iop_NCipherV128: + case Iop_NCipherLV128: + case Iop_SHA512: + case Iop_SHA256: + case Iop_MullEven8Ux16: + case Iop_MullEven16Ux8: + case Iop_MullEven32Ux4: + case Iop_MullEven8Sx16: + case Iop_MullEven16Sx8: + case Iop_MullEven32Sx4: + case Iop_Max64Sx2: + case Iop_Max64Ux2: + case Iop_Min64Sx2: + case Iop_Min64Ux2: + case Iop_CmpGT64Ux2: + case Iop_Rol64x2: + case Iop_QNarrowBin64Sto32Sx4: + case Iop_QNarrowBin64Uto32Ux4: + case Iop_NarrowBin64to32x4: { + /* IROps require a processor that supports ISA 2.07 (Power 8) or newer */ + rc = system(MIN_POWER_ISA " 2.07 "); + rc /= 256; + /* MIN_POWER_ISA returns 0 if underlying HW supports the + * specified ISA or newer. Returns 1 if the HW does not support + * the specified ISA. Returns 2 on error. + */ + if (rc == 1) return NULL; if (rc > 2) { panic(" ERROR, min_power_isa() return code is invalid.\n"); } diff --git a/memcheck/tests/vbit-test/main.c b/memcheck/tests/vbit-test/main.c index 45f431bb25..0cac780f7d 100644 --- a/memcheck/tests/vbit-test/main.c +++ b/memcheck/tests/vbit-test/main.c @@ -80,10 +80,57 @@ static void fixup_irops(void) { #ifdef __powerpc__ - get_irop(Iop_ShlD64)->shift_amount_is_immediate = 1; - get_irop(Iop_ShrD64)->shift_amount_is_immediate = 1; - get_irop(Iop_ShlD128)->shift_amount_is_immediate = 1; - get_irop(Iop_ShrD128)->shift_amount_is_immediate = 1; + irop_t* tmp; + + /* Iops with immediate shift value */ + tmp = get_irop(Iop_ShlD64); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_ShrD64); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_ShlD128); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_ShrD128); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + /* Iops with immediate value that controls PPC instruction behavior */ + tmp = get_irop(Iop_SHA256); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_SHA512); + if (tmp) { + tmp->immediate_index = 2; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_BCDAdd); + if (tmp) { + tmp->immediate_index = 3; + tmp->immediate_type = Ity_I8; + } + + tmp = get_irop(Iop_BCDSub); + if (tmp) { + tmp->immediate_index = 3; + tmp->immediate_type = Ity_I8; + } #endif } diff --git a/memcheck/tests/vbit-test/qernary.c b/memcheck/tests/vbit-test/qernary.c index 001a543b18..fbe2eaa0a5 100644 --- a/memcheck/tests/vbit-test/qernary.c +++ b/memcheck/tests/vbit-test/qernary.c @@ -67,6 +67,9 @@ test_qernary_op(const irop_t *op, test_data_t *data) opnd_t *opnds = data->opnds; int tests_done = 0; + /* Immediate operands are currently not supported here */ + assert(op->immediate_index == 0); + /* For each operand, set a single bit to undefined and observe how that propagates to the output. Do this for all bits in each operand. */ diff --git a/memcheck/tests/vbit-test/ternary.c b/memcheck/tests/vbit-test/ternary.c index f7aa8fe390..b9061a4161 100644 --- a/memcheck/tests/vbit-test/ternary.c +++ b/memcheck/tests/vbit-test/ternary.c @@ -50,6 +50,34 @@ check_result_for_ternary(const irop_t *op, const test_data_t *data) opnd3->vbits); break; + case UNDEF_SOME: + /* The result of the Iop_BCDAdd and the Iop_BCDSub has some result + * vbits set. Not sure how the vbit propagation works on these Iops. + * for now, just make sure there are some vbits set in the result. + * + * The Iop_BCDAdd and Iop_BCDSub iops have one immediate value in the + * third operand. + * + * TODO, figure out details of vbit propagation for these Iops. + */ + expected_vbits.num_bits = result->vbits.num_bits; + + if ((result->vbits.bits.u128[0] != 0) || + (result->vbits.bits.u128[1] != 0)) { + expected_vbits.bits.u128[0] = result->vbits.bits.u128[0]; + expected_vbits.bits.u128[1] = result->vbits.bits.u128[1]; + + } else { + /* The input had at least one vbit set but the result doesn't have any + * bit set. Set them all so we will trigger the error on the call + * to complain(). + */ + expected_vbits.bits.u128[0] = ~0x0ULL; + expected_vbits.bits.u128[1] = ~0x0ULL; + } + + break; + default: panic(__func__); } diff --git a/memcheck/tests/vbit-test/unary.c b/memcheck/tests/vbit-test/unary.c index 29c7ed5a47..d47cc8af97 100644 --- a/memcheck/tests/vbit-test/unary.c +++ b/memcheck/tests/vbit-test/unary.c @@ -68,6 +68,31 @@ check_result_for_unary(const irop_t *op, const test_data_t *data) expected_vbits = zextend_vbits(opnd->vbits, num_bits); break; + case UNDEF_ALL_64x2: + assert(num_bits == 128); + expected_vbits = undefined_vbits_BxE(64, 2, opnd->vbits); + break; + + case UNDEF_ALL_32x4: + assert(num_bits == 128); + expected_vbits = undefined_vbits_BxE(32, 4, opnd->vbits); + break; + + case UNDEF_ALL_16x8: + assert(num_bits == 128); + expected_vbits = undefined_vbits_BxE(16, 8, opnd->vbits); + break; + + case UNDEF_ALL_8x16: + assert(num_bits == 128); + expected_vbits = undefined_vbits_BxE(8, 16, opnd->vbits); + break; + + case UNDEF_64x2_TRANSPOSE: + assert(num_bits == 128); + expected_vbits = undefined_vbits_64x2_transpose(opnd->vbits); + break; + default: panic(__func__); } @@ -83,6 +108,9 @@ test_unary_op(const irop_t *op, test_data_t *data) unsigned num_input_bits, bitpos; int tests_done = 0; + /* Immediate operands are currently not supported here */ + assert(op->immediate_index == 0); + num_input_bits = bitsof_irtype(data->opnds[0].type); for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { diff --git a/memcheck/tests/vbit-test/valgrind.c b/memcheck/tests/vbit-test/valgrind.c index f9b052ab97..7786f11f5d 100644 --- a/memcheck/tests/vbit-test/valgrind.c +++ b/memcheck/tests/vbit-test/valgrind.c @@ -51,7 +51,8 @@ new_iricb(const irop_t *op, test_data_t *data) cb.num_operands = get_num_operands(op->op); - cb.shift_amount_is_immediate = op->shift_amount_is_immediate; + cb.immediate_index = op->immediate_index; + cb.immediate_type = op->immediate_type; return cb; } diff --git a/memcheck/tests/vbit-test/vbits.c b/memcheck/tests/vbit-test/vbits.c index d8e5df6ec5..47eabdbdb6 100644 --- a/memcheck/tests/vbit-test/vbits.c +++ b/memcheck/tests/vbit-test/vbits.c @@ -128,6 +128,278 @@ undefined_vbits(unsigned num_bits) return new; } +/* The following routines named undefined_vbits_BxE() return a 128-bit + * vector with E elements each of size bits. If any of the bits in an + * element is undefined, then return a value where all bits in that + * element are undefined. + */ +vbits_t +undefined_vbits_BxE(unsigned int bits, unsigned int elements, vbits_t v) +{ + vbits_t new = { .num_bits = v.num_bits }; + uint64_t mask = ~0ull >> (64 - bits); + int i, j; + + assert ((elements % 2) == 0); + assert (bits <= 64); + + for (i = 0; i<2; i++) { + new.bits.u128[i] = 0ull; + + for (j = 0; j> (64 - bits); + uint64_t const shift_mask = 0xFF; + uint64_t element; + int i, j; + signed char shift; + assert ((elements % 2) == 0); + assert (bits <= 64); + + for (i = 0; i<2; i++) { + new.bits.u128[i] = 0ull; + + for (j = 0; j> (j*bits)) & mask; + shift = (int)((val.u128[i] >> (j*bits)) & shift_mask); + + if (shift < 0) { + /* right shift */ + new.bits.u128[i] = element >> -shift; + + /* OR in the bits shifted out into the top of the element */ + new.bits.u128[i] |= element << (bits + shift); + } else { + /* left shift */ + /* upper bits from shift */ + new.bits.u128[i] = element << shift; + + /* OR in the bits shifted out into the bottom of the element */ + new.bits.u128[i] |= element >> (bits - shift); + } + } + } + return new; +} + +/* Only the even elements of the input are used by the Iop*/ +vbits_t +undefined_vbits_128_even_element(unsigned int bits, unsigned int elements, + vbits_t v) +{ + int i; + uint64_t mask; + unsigned int const element_width = 128/elements; + vbits_t new = { .num_bits = v.num_bits }; + + assert ((elements % 2) == 0); + assert (bits <= 64); + + /* Create a 128-bit mask with the bits in the even numbered + * elements are all ones. + */ + mask = ~0ull >> (64 - bits); + + for (i = 2; i < elements/2; i=i+2) { + mask |= mask << (i * element_width); + } + + new.bits.u128[0] = mask & v.bits.u128[0]; + new.bits.u128[1] = mask & v.bits.u128[1]; + + return new; +} + +/* Concatenate bit i from each byte j. Place concatenated 8 bit value into + * byte i of the result. Do for all i from 0 to 7 and j from 0 to 7 of each + * 64-bit element. + */ +vbits_t +undefined_vbits_64x2_transpose(vbits_t v) +{ + vbits_t new = { .num_bits = v.num_bits }; + unsigned int bit, byte, element; + uint64_t value, new_value, select_bit; + + for (element = 0; element < 2; element++) { + value = v.bits.u128[element]; + new_value = 0; + for (byte = 0; byte < 8; byte++) { + for (bit = 0; bit < 8; bit++) { + select_bit = 1ULL & (value >> (bit + 8*byte)); + new_value |= select_bit << (bit*8 + byte); + } + } + new.bits.u128[element] = new_value; + } + return new; +} + +/* The routine takes a 256-bit vector value stored across the two 128-bit + * source operands src1 and src2. The size of each element in the input is + * src_num_bits. The elements are narrowed to result_num_bits and packed + * into the result. If saturate is True, then the all the result bits are + * set to 1 if the source element can not be represented in result_num_bits. + */ +vbits_t +undefined_vbits_Narrow256_AtoB(unsigned int src_num_bits, + unsigned int result_num_bits, + vbits_t src1_v, value_t src1_value, + vbits_t src2_v, value_t src2_value, + bool saturate) +{ + + vbits_t new = { .num_bits = src1_v.num_bits }; + unsigned int i; + uint64_t vbits, new_value; + uint64_t const src_mask = ~0x0ULL >> (64 - src_num_bits); + uint64_t const result_mask = ~0x0ULL >> (64 - result_num_bits); + unsigned int num_elements_per_64_bits = src_num_bits/64; + unsigned int shift; + + /* + * NOTE: POWER PPC + * the saturated value is 0xFFFF for the vbit is in one of the lower + * 32-bits of the source. The saturated result is 0xFFFF0000 if the + * vbit is in the upper 32-bits of the source. Not sure what + * the saturated result is in general for a B-bit result. + * + * ONLY TESTED FOR 64 bit input, 32 bit result + */ + uint64_t const saturated_result = 0xFFFFULL; + + /* Source elements are split between the two source operands */ + + assert(src_num_bits <= 64); + assert(result_num_bits < 64); + assert(result_num_bits < src_num_bits); + + /* Narrow the elements from src1 to the upper 64-bits of result. + * Do each of the 64 bit values that make up a u128 + */ + new_value = 0; + for (i = 0; i < num_elements_per_64_bits; i++) { + vbits = src1_v.bits.u128[0] >> (i * src_num_bits); + vbits &= src_mask; + + shift = result_num_bits * i; + if (vbits) { + if (saturate) { + /* Value will not fit in B-bits, saturate the result as needed. */ + if (vbits >> (src_num_bits/2)) + /* vbit is upper half of the source */ + new_value |= saturated_result << ( shift + result_num_bits/2); + else + new_value |= saturated_result << shift; + } else { + new_value |= (vbits & result_mask) << shift; + } + } + } + + for (i = 0; i < num_elements_per_64_bits; i++) { + vbits = src1_v.bits.u128[1] >> (i * src_num_bits); + vbits &= src_mask; + + shift = result_num_bits * i + (num_elements_per_64_bits + * result_num_bits); + if (vbits) { + if (saturate) { + /* Value will not fit in result_num_bits, saturate the result + * as needed. + */ + if (vbits >> (src_num_bits/2)) + /* vbit is upper half of the source */ + new_value |= saturated_result << (shift + result_num_bits/2); + + else + new_value |= saturated_result << shift; + + } else { + new_value |= (vbits & result_mask) << shift; + } + } + } + if (__BYTE_ORDER == __LITTLE_ENDIAN) + new.bits.u128[1] = new_value; + else + /* Big endian, swap the upper and lower 32-bits of new_value */ + new.bits.u128[0] = (new_value << 32) | (new_value >> 32); + + new_value = 0; + /* Narrow the elements from src2 to the lower 64-bits of result. + * Do each of the 64 bit values that make up a u128 + */ + for (i = 0; i < num_elements_per_64_bits; i++) { + vbits = src2_v.bits.u128[0] >> (i * src_num_bits); + vbits &= src_mask; + + shift = result_num_bits * i; + if (vbits) { + if (saturate) { + /* Value will not fit in result, saturate the result as needed. */ + if (vbits >> (src_num_bits/2)) + /* vbit is upper half of the source */ + new_value |= saturated_result << (shift + result_num_bits/2); + else + new_value |= saturated_result << shift; + } else { + new_value |= (vbits & result_mask) << shift; + } + } + } + + for (i = 0; i < num_elements_per_64_bits; i++) { + vbits = src2_v.bits.u128[1] >> (i * src_num_bits); + vbits &= src_mask; + + if (vbits) { + if (saturate) { + /* Value will not fit in result_num_bits, saturate the result + * as needed. + */ + if (vbits >> (src_num_bits/2)) + /* vbit is upper half of the source */ + new_value |= saturated_result << (result_num_bits * i + + result_num_bits/2 + + (num_elements_per_64_bits + * result_num_bits)); + else + new_value |= saturated_result << (result_num_bits * i + + (num_elements_per_64_bits + * result_num_bits)); + + } else { + new_value |= (vbits & result_mask) << (result_num_bits * i + + (num_elements_per_64_bits + * result_num_bits)); + } + } + } + if (__BYTE_ORDER == __LITTLE_ENDIAN) + new.bits.u128[0] = new_value; + else + /* Big endian, swap the upper and lower 32-bits of new_value */ + new.bits.u128[1] = (new_value << 32) | (new_value >> 32); + + return new; +} /* Return a value where all bits are set to defined. */ vbits_t diff --git a/memcheck/tests/vbit-test/vbits.h b/memcheck/tests/vbit-test/vbits.h index eda2e94fb4..c6f754063d 100644 --- a/memcheck/tests/vbit-test/vbits.h +++ b/memcheck/tests/vbit-test/vbits.h @@ -29,6 +29,7 @@ #include #include +#include typedef uint64_t uint128_t[2]; typedef uint64_t uint256_t[4]; @@ -62,6 +63,19 @@ typedef union { void print_vbits(FILE *, vbits_t); vbits_t undefined_vbits(unsigned num_bits); +vbits_t undefined_vbits_BxE(unsigned int bits, unsigned int elements, + vbits_t v); +vbits_t undefined_vbits_BxE_rotate(unsigned int bits, unsigned int elements, + vbits_t vbits, + value_t value); +vbits_t undefined_vbits_128_even_element(unsigned int bits, + unsigned int elements, vbits_t v); +vbits_t undefined_vbits_64x2_transpose(vbits_t v); +vbits_t undefined_vbits_Narrow256_AtoB(unsigned int src_num_bits, + unsigned int result_num_bits, + vbits_t src1_v, value_t src1_value, + vbits_t src2_v, value_t src2_value, + bool sataurate); vbits_t defined_vbits(unsigned num_bits); int equal_vbits(vbits_t, vbits_t); vbits_t truncate_vbits(vbits_t, unsigned num_bits); diff --git a/memcheck/tests/vbit-test/vtest.h b/memcheck/tests/vbit-test/vtest.h index a1f445ac7a..7831b51806 100644 --- a/memcheck/tests/vbit-test/vtest.h +++ b/memcheck/tests/vbit-test/vtest.h @@ -79,6 +79,81 @@ typedef enum { UNDEF_ORD, // Iop_CmpORD compare + /* For each of the following UNDEF_ALL_BxE, E is the number of + * elements and B is the number of bits in the element. + * + * If any bits in one of the E elements is not defined, then the + * return value has all bits in the corresponding element set to 1. + */ + UNDEF_ALL_64x2, // 128-bit vector, two 64-bit elements + UNDEF_ALL_32x4, // 128-bit vector, four 32-bit elements + UNDEF_ALL_16x8, // 128-bit vector, eight 16-bit elements + UNDEF_ALL_8x16, // 128-bit vector, sixteen 8-bit elements + + /* For each of the following UNDEF_ALL_BxE_EVEN, E is the number of + * elements and B is the number of bits in the element. Elements are + * numbered from right to left starting with element number 0. + * + * If any bits in one of the even numbered elements is not defined, then + * the return value has all bits in the corresponding element set to 1. + * The bits in the odd numbered elements are not checked + */ + UNDEF_ALL_32x4_EVEN, // 128-bit vector, four 32-bit elements + UNDEF_ALL_16x8_EVEN, // 128-bit vector, eight 16-bit elements + UNDEF_ALL_8x16_EVEN, // 128-bit vector, sixteen 8-bit elements + + /* For each of the following UNDEF_BxE_TRANSPOSE, E is the number of + * elements and B is the number of bits in the element. + * + * Concatenate bit i from each byte j. Place concatenated 8 bit value + * into byte i of the result. Do for each bit i from 0 to 7 and + * byte j from 0 to 7 of each 64-bit element. + */ + UNDEF_64x2_TRANSPOSE, + + /* For each of the following UNDEF_BxE_ROTATE, E is the number of + * elements and B is the number of bits in the element. + * + * The result is the undefined bits in each element rotated by the + * specified amount. Bits rotated out of the element are discarded. + * No additional bits are set to undefined. + */ + UNDEF_64x2_ROTATE, /* 128-bit vector, two 64-bit elements, rotate + * elements left. + */ + UNDEF_32x4_ROTATE, /* 128-bit vector, four 32-bit elements, rotate + * elements left. + */ + UNDEF_16x8_ROTATE, /* 128-bit vector, eight 16-bit elements, rotate + * elements left. + */ + UNDEF_8x16_ROTATE, /* 128-bit vector, sixteen 8-bit elements, rotate + * elements left. + */ + + /* If the input had some vbits set, the result will have one or more + * vbits set. Minimal test when the vbit propagation can not be easily + * calculated. + */ + UNDEF_SOME, + + /* For UNDEF_NARROW256_AtoB, narrow the elements of size A-bits in + * the 256-bit source (stored in two 128-bit values) to a 128-bit + * result with elements of size B-bits. + * + * If the source element will fit into the corresponding destination + * element, then only the undefined bits in the source element are + * undefined in the corresponding bit position of the destination element. + * + * If the source element will not fit into the destination element, then + * only the lower B undefined bits of the source element will be + * undefined in the corresponding result element unless the saturate + * flag is true. If the saturate flag is true and the element in the + * source will not fit into the corresponding destination element, then + * all of the bits in the corresponding destination element are set to one. + */ + UNDEF_NARROW256_AtoB, + // For IROps I don't know anything about UNDEF_UNKNOWN } undef_t; @@ -89,7 +164,15 @@ typedef struct { IROp op; const char *name; undef_t undef_kind; - int shift_amount_is_immediate; + /* The following two members describe if this operand has immediate + * operands. There are a few restrictions: + * (1) An operator can have at most one immediate operand. + * (2) If there is an immediate operand, it is the right-most operand. + * An immediate_index of 0 means there is no immediate operand. + */ + unsigned immediate_index; + unsigned immediate_type; + // Indicate whether IROp can be tested on a particular architecture unsigned s390x : 1; unsigned amd64 : 1;