| /* -*- mode: C; c-basic-offset: 3; -*- */ |
| |
| /* |
| This file is part of MemCheck, a heavyweight Valgrind tool for |
| detecting memory errors. |
| |
| Copyright (C) 2012-2015 Florian Krohm |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 2 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| The GNU General Public License is contained in the file COPYING. |
| */ |
| |
| #include <assert.h> |
| #include <string.h> // memset |
| #include "vtest.h" |
| |
| |
| /* A convenience function to compute either v1 & ~v2 & val2 or |
| v1 & ~v2 & ~val2 depending on INVERT_VAL2. */ |
| static vbits_t |
| and_combine(vbits_t v1, vbits_t v2, value_t val2, int invert_val2) |
| { |
| assert(v1.num_bits == v2.num_bits); |
| |
| vbits_t new = { .num_bits = v2.num_bits }; |
| |
| if (invert_val2) { |
| switch (v2.num_bits) { |
| case 8: val2.u8 = ~val2.u8 & 0xff; break; |
| case 16: val2.u16 = ~val2.u16 & 0xffff; break; |
| case 32: val2.u32 = ~val2.u32; break; |
| case 64: val2.u64 = ~val2.u64; break; |
| default: |
| panic(__func__); |
| } |
| } |
| |
| switch (v2.num_bits) { |
| case 8: |
| new.bits.u8 = (v1.bits.u8 & ~v2.bits.u8 & val2.u8) & 0xff; |
| break; |
| case 16: |
| new.bits.u16 = (v1.bits.u16 & ~v2.bits.u16 & val2.u16) & 0xffff; |
| break; |
| case 32: |
| new.bits.u32 = (v1.bits.u32 & ~v2.bits.u32 & val2.u32); |
| break; |
| case 64: |
| new.bits.u64 = (v1.bits.u64 & ~v2.bits.u64 & val2.u64); |
| break; |
| default: |
| panic(__func__); |
| } |
| return new; |
| } |
| |
| /* Check the result of a binary operation. */ |
| static void |
| 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. */ |
| switch (op->undef_kind) { |
| case UNDEF_NONE: |
| expected_vbits = defined_vbits(result->vbits.num_bits); |
| 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; |
| |
| case UNDEF_LEFT: |
| // LEFT with respect to the leftmost 1-bit in both operands |
| expected_vbits = left_vbits(or_vbits(opnd1->vbits, opnd2->vbits), |
| result->vbits.num_bits); |
| break; |
| |
| case UNDEF_SAME: |
| assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); |
| assert(opnd1->vbits.num_bits == result->vbits.num_bits); |
| |
| // SAME with respect to the 1-bits in both operands |
| expected_vbits = or_vbits(opnd1->vbits, opnd2->vbits); |
| break; |
| |
| case UNDEF_CONCAT: |
| assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits); |
| assert(result->vbits.num_bits == 2 * opnd1->vbits.num_bits); |
| expected_vbits = concat_vbits(opnd1->vbits, opnd2->vbits); |
| break; |
| |
| case UNDEF_SHL: |
| /* If any bit in the 2nd operand is undefined, so are all bits |
| of the result. */ |
| if (! completely_defined_vbits(opnd2->vbits)) { |
| expected_vbits = undefined_vbits(result->vbits.num_bits); |
| } else { |
| assert(opnd2->vbits.num_bits == 8); |
| unsigned shift_amount = opnd2->value.u8; |
| |
| expected_vbits = shl_vbits(opnd1->vbits, shift_amount); |
| } |
| break; |
| |
| case UNDEF_SHR: |
| /* If any bit in the 2nd operand is undefined, so are all bits |
| of the result. */ |
| if (! completely_defined_vbits(opnd2->vbits)) { |
| expected_vbits = undefined_vbits(result->vbits.num_bits); |
| } else { |
| assert(opnd2->vbits.num_bits == 8); |
| unsigned shift_amount = opnd2->value.u8; |
| |
| expected_vbits = shr_vbits(opnd1->vbits, shift_amount); |
| } |
| break; |
| |
| case UNDEF_SAR: |
| /* If any bit in the 2nd operand is undefined, so are all bits |
| of the result. */ |
| if (! completely_defined_vbits(opnd2->vbits)) { |
| expected_vbits = undefined_vbits(result->vbits.num_bits); |
| } else { |
| assert(opnd2->vbits.num_bits == 8); |
| unsigned shift_amount = opnd2->value.u8; |
| |
| expected_vbits = sar_vbits(opnd1->vbits, shift_amount); |
| } |
| break; |
| |
| case UNDEF_AND: { |
| /* Let v1, v2 be the V-bits of the 1st and 2nd operand, respectively |
| Let b1, b2 be the actual value of the 1st and 2nd operand, respect. |
| And output bit is undefined (i.e. its V-bit == 1), iff |
| (1) (v1 == 1) && (v2 == 1) OR |
| (2) (v1 == 1) && (v2 == 0 && b2 == 1) OR |
| (3) (v2 == 1) && (v1 == 0 && b1 == 1) |
| */ |
| vbits_t term1, term2, term3; |
| term1 = and_vbits(opnd1->vbits, opnd2->vbits); |
| term2 = and_combine(opnd1->vbits, opnd2->vbits, opnd2->value, 0); |
| term3 = and_combine(opnd2->vbits, opnd1->vbits, opnd1->value, 0); |
| expected_vbits = or_vbits(term1, or_vbits(term2, term3)); |
| break; |
| } |
| |
| case UNDEF_OR: { |
| /* Let v1, v2 be the V-bits of the 1st and 2nd operand, respectively |
| Let b1, b2 be the actual value of the 1st and 2nd operand, respect. |
| And output bit is undefined (i.e. its V-bit == 1), iff |
| (1) (v1 == 1) && (v2 == 1) OR |
| (2) (v1 == 1) && (v2 == 0 && b2 == 0) OR |
| (3) (v2 == 1) && (v1 == 0 && b1 == 0) |
| */ |
| vbits_t term1, term2, term3; |
| term1 = and_vbits(opnd1->vbits, opnd2->vbits); |
| term2 = and_combine(opnd1->vbits, opnd2->vbits, opnd2->value, 1); |
| term3 = and_combine(opnd2->vbits, opnd1->vbits, opnd1->value, 1); |
| expected_vbits = or_vbits(term1, or_vbits(term2, term3)); |
| break; |
| } |
| |
| case UNDEF_ORD: |
| /* Set expected_vbits for the Iop_CmpORD category of iops. |
| * If any of the input bits is undefined the least significant |
| * three bits in the result will be set, i.e. 0xe. |
| */ |
| expected_vbits = cmpord_vbits(opnd1->vbits.num_bits, |
| 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__); |
| } |
| |
| if (! equal_vbits(result->vbits, expected_vbits)) |
| complain(op, data, expected_vbits); |
| } |
| |
| |
| static int |
| test_shift(const irop_t *op, test_data_t *data) |
| { |
| unsigned num_input_bits, i; |
| opnd_t *opnds = data->opnds; |
| int tests_done = 0; |
| |
| /* When testing the 1st operand's undefinedness propagation, |
| do so with all possible shift amnounts */ |
| for (unsigned amount = 0; amount < bitsof_irtype(opnds[0].type); ++amount) { |
| opnds[1].value.u8 = amount; |
| |
| // 1st (left) operand |
| num_input_bits = bitsof_irtype(opnds[0].type); |
| |
| for (i = 0; i < num_input_bits; ++i) { |
| opnds[0].vbits = onehot_vbits(i, bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| } |
| |
| // 2nd (right) operand |
| |
| /* If the operand is an immediate value, there are no v-bits to set. */ |
| if (!op->immediate_index) return tests_done; |
| |
| num_input_bits = bitsof_irtype(opnds[1].type); |
| |
| for (i = 0; i < num_input_bits; ++i) { |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = onehot_vbits(i, bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| |
| tests_done++; |
| } |
| return tests_done; |
| } |
| |
| |
| static value_t |
| all_bits_zero_value(unsigned num_bits) |
| { |
| value_t val; |
| |
| switch (num_bits) { |
| case 8: val.u8 = 0; break; |
| case 16: val.u16 = 0; break; |
| case 32: val.u32 = 0; break; |
| case 64: val.u64 = 0; break; |
| default: |
| panic(__func__); |
| } |
| return val; |
| } |
| |
| |
| static value_t |
| all_bits_one_value(unsigned num_bits) |
| { |
| value_t val; |
| |
| switch (num_bits) { |
| case 8: val.u8 = 0xff; break; |
| case 16: val.u16 = 0xffff; break; |
| case 32: val.u32 = ~0u; break; |
| case 64: val.u64 = ~0ull; break; |
| default: |
| panic(__func__); |
| } |
| return val; |
| } |
| |
| |
| static int |
| test_and(const irop_t *op, test_data_t *data) |
| { |
| unsigned num_input_bits, bitpos; |
| opnd_t *opnds = data->opnds; |
| int tests_done = 0; |
| |
| /* Undefinedness does not propagate if the other operand is 0. |
| Use an all-bits-zero operand and test the other operand in |
| the usual way (one bit undefined at a time). */ |
| |
| // 1st (left) operand variable, 2nd operand all-bits-zero |
| num_input_bits = bitsof_irtype(opnds[0].type); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[1].value = all_bits_zero_value(bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| // 2nd (right) operand variable, 1st operand all-bits-zero |
| num_input_bits = bitsof_irtype(opnds[1].type); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type)); |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[0].value = all_bits_zero_value(bitsof_irtype(opnds[0].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| /* Undefinedness propagates if the other operand is 1. |
| Use an all-bits-one operand and test the other operand in |
| the usual way (one bit undefined at a time). */ |
| |
| // 1st (left) operand variable, 2nd operand all-bits-one |
| num_input_bits = bitsof_irtype(opnds[0].type); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[1].value = all_bits_one_value(bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| // 2nd (right) operand variable, 1st operand all-bits-one |
| num_input_bits = bitsof_irtype(opnds[1].type); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type)); |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[0].value = all_bits_one_value(bitsof_irtype(opnds[0].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| return tests_done; |
| } |
| |
| |
| static int |
| test_or(const irop_t *op, test_data_t *data) |
| { |
| unsigned num_input_bits, bitpos; |
| opnd_t *opnds = data->opnds; |
| int tests_done = 0; |
| |
| /* Undefinedness does not propagate if the other operand is 1. |
| Use an all-bits-one operand and test the other operand in |
| the usual way (one bit undefined at a time). */ |
| |
| // 1st (left) operand variable, 2nd operand all-bits-one |
| num_input_bits = bitsof_irtype(opnds[0].type); |
| |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[1].value = all_bits_one_value(bitsof_irtype(opnds[1].type)); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| // 2nd (right) operand variable, 1st operand all-bits-one |
| num_input_bits = bitsof_irtype(opnds[1].type); |
| |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[0].value = all_bits_one_value(bitsof_irtype(opnds[0].type)); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| /* Undefinedness propagates if the other operand is 0. |
| Use an all-bits-zero operand and test the other operand in |
| the usual way (one bit undefined at a time). */ |
| |
| // 1st (left) operand variable, 2nd operand all-bits-zero |
| num_input_bits = bitsof_irtype(opnds[0].type); |
| |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[1].value = all_bits_zero_value(bitsof_irtype(opnds[1].type)); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| |
| // 2nd (right) operand variable, 1st operand all-bits-zero |
| num_input_bits = bitsof_irtype(opnds[1].type); |
| |
| opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| opnds[0].value = all_bits_zero_value(bitsof_irtype(opnds[0].type)); |
| |
| for (bitpos = 0; bitpos < num_input_bits; ++bitpos) { |
| opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| tests_done++; |
| } |
| return tests_done; |
| } |
| |
| |
| int |
| test_binary_op(const irop_t *op, test_data_t *data) |
| { |
| unsigned num_input_bits, i, bitpos; |
| opnd_t *opnds = data->opnds; |
| int tests_done = 0; |
| |
| /* Handle special cases upfront */ |
| switch (op->undef_kind) { |
| case UNDEF_SHL: |
| case UNDEF_SHR: |
| case UNDEF_SAR: |
| return test_shift(op, data); |
| |
| case UNDEF_AND: |
| return test_and(op, data); |
| |
| case UNDEF_OR: |
| return test_or(op, data); |
| |
| default: |
| break; |
| } |
| |
| /* 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. */ |
| for (i = 0; i < 2; ++i) { |
| |
| /* 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)); |
| opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type)); |
| |
| /* Set the value of the 2nd operand to something != 0. So division |
| won't crash. */ |
| memset(&opnds[1].value, 0xff, sizeof opnds[1].value); |
| |
| /* For immediate shift amounts choose a value of '1'. That value should |
| not cause a problem. Note: we always assign to the u64 member here. |
| The reason is that in ir_inject.c the value_t type is not visible. |
| The value is picked up there by interpreting the memory as an |
| ULong value. So, we rely on |
| union { |
| ULong v1; // value picked up in ir_inject.c |
| value_t v2; // value assigned here |
| } xx; |
| assert(sizeof xx.v1 == sizeof xx.v2.u64); |
| assert(xx.v1 == xx.v2.u64); |
| */ |
| |
| 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)); |
| |
| valgrind_execute_test(op, data); |
| |
| check_result_for_binary(op, data); |
| |
| tests_done++; |
| } |
| } |
| return tests_done; |
| } |