Home | History | Annotate | Download | only in vbit-test
      1 /* -*- mode: C; c-basic-offset: 3; -*- */
      2 
      3 /*
      4    This file is part of MemCheck, a heavyweight Valgrind tool for
      5    detecting memory errors.
      6 
      7    Copyright (C) 2012-2015  Florian Krohm
      8 
      9    This program is free software; you can redistribute it and/or
     10    modify it under the terms of the GNU General Public License as
     11    published by the Free Software Foundation; either version 2 of the
     12    License, or (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful, but
     15    WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17    General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program; if not, write to the Free Software
     21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     22    02111-1307, USA.
     23 
     24    The GNU General Public License is contained in the file COPYING.
     25 */
     26 
     27 #include <assert.h>
     28 #include <string.h>  // memset
     29 #include "vtest.h"
     30 
     31 
     32 /* A convenience function to compute either v1 & ~v2 & val2  or
     33    v1 & ~v2 & ~val2  depending on INVERT_VAL2. */
     34 static vbits_t
     35 and_combine(vbits_t v1, vbits_t v2, value_t val2, int invert_val2)
     36 {
     37    assert(v1.num_bits == v2.num_bits);
     38 
     39    vbits_t new = { .num_bits = v2.num_bits };
     40 
     41    if (invert_val2) {
     42       switch (v2.num_bits) {
     43       case 8:  val2.u8  = ~val2.u8  & 0xff;   break;
     44       case 16: val2.u16 = ~val2.u16 & 0xffff; break;
     45       case 32: val2.u32 = ~val2.u32;          break;
     46       case 64: val2.u64 = ~val2.u64;          break;
     47       default:
     48          panic(__func__);
     49       }
     50    }
     51 
     52    switch (v2.num_bits) {
     53    case 8:
     54       new.bits.u8  = (v1.bits.u8 & ~v2.bits.u8  & val2.u8)  & 0xff;
     55       break;
     56    case 16:
     57       new.bits.u16 = (v1.bits.u16 & ~v2.bits.u16 & val2.u16) & 0xffff;
     58       break;
     59    case 32:
     60       new.bits.u32 = (v1.bits.u32 & ~v2.bits.u32 & val2.u32);
     61       break;
     62    case 64:
     63       new.bits.u64 = (v1.bits.u64 & ~v2.bits.u64 & val2.u64);
     64       break;
     65    default:
     66       panic(__func__);
     67    }
     68    return new;
     69 }
     70 
     71 /* Check the result of a binary operation. */
     72 static void
     73 check_result_for_binary(const irop_t *op, const test_data_t *data)
     74 {
     75    const opnd_t *result = &data->result;
     76    const opnd_t *opnd1  = &data->opnds[0];
     77    const opnd_t *opnd2  = &data->opnds[1];
     78    vbits_t expected_vbits;
     79 
     80    /* Only handle those undef-kinds that actually occur. */
     81    switch (op->undef_kind) {
     82    case UNDEF_NONE:
     83       expected_vbits = defined_vbits(result->vbits.num_bits);
     84       break;
     85 
     86    case UNDEF_ALL:
     87       expected_vbits = undefined_vbits(result->vbits.num_bits);
     88       break;
     89 
     90    case UNDEF_LEFT:
     91       // LEFT with respect to the leftmost 1-bit in both operands
     92       expected_vbits = left_vbits(or_vbits(opnd1->vbits, opnd2->vbits),
     93                                   result->vbits.num_bits);
     94       break;
     95 
     96    case UNDEF_SAME:
     97       assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits);
     98       assert(opnd1->vbits.num_bits == result->vbits.num_bits);
     99 
    100       // SAME with respect to the 1-bits in both operands
    101       expected_vbits = or_vbits(opnd1->vbits, opnd2->vbits);
    102       break;
    103 
    104    case UNDEF_CONCAT:
    105       assert(opnd1->vbits.num_bits == opnd2->vbits.num_bits);
    106       assert(result->vbits.num_bits == 2 * opnd1->vbits.num_bits);
    107       expected_vbits = concat_vbits(opnd1->vbits, opnd2->vbits);
    108       break;
    109 
    110    case UNDEF_SHL:
    111       /* If any bit in the 2nd operand is undefined, so are all bits
    112          of the result. */
    113       if (! completely_defined_vbits(opnd2->vbits)) {
    114          expected_vbits = undefined_vbits(result->vbits.num_bits);
    115       } else {
    116          assert(opnd2->vbits.num_bits == 8);
    117          unsigned shift_amount = opnd2->value.u8;
    118 
    119          expected_vbits = shl_vbits(opnd1->vbits, shift_amount);
    120       }
    121       break;
    122 
    123    case UNDEF_SHR:
    124       /* If any bit in the 2nd operand is undefined, so are all bits
    125          of the result. */
    126       if (! completely_defined_vbits(opnd2->vbits)) {
    127          expected_vbits = undefined_vbits(result->vbits.num_bits);
    128       } else {
    129          assert(opnd2->vbits.num_bits == 8);
    130          unsigned shift_amount = opnd2->value.u8;
    131 
    132          expected_vbits = shr_vbits(opnd1->vbits, shift_amount);
    133       }
    134       break;
    135 
    136    case UNDEF_SAR:
    137       /* If any bit in the 2nd operand is undefined, so are all bits
    138          of the result. */
    139       if (! completely_defined_vbits(opnd2->vbits)) {
    140          expected_vbits = undefined_vbits(result->vbits.num_bits);
    141       } else {
    142          assert(opnd2->vbits.num_bits == 8);
    143          unsigned shift_amount = opnd2->value.u8;
    144 
    145          expected_vbits = sar_vbits(opnd1->vbits, shift_amount);
    146       }
    147       break;
    148 
    149    case UNDEF_AND: {
    150       /* Let v1, v2 be the V-bits of the 1st and 2nd operand, respectively
    151          Let b1, b2 be the actual value of the 1st and 2nd operand, respect.
    152          And output bit is undefined (i.e. its V-bit == 1), iff
    153          (1) (v1 == 1) && (v2 == 1)   OR
    154          (2) (v1 == 1) && (v2 == 0 && b2 == 1) OR
    155          (3) (v2 == 1) && (v1 == 0 && b1 == 1)
    156       */
    157       vbits_t term1, term2, term3;
    158       term1 = and_vbits(opnd1->vbits, opnd2->vbits);
    159       term2 = and_combine(opnd1->vbits, opnd2->vbits, opnd2->value, 0);
    160       term3 = and_combine(opnd2->vbits, opnd1->vbits, opnd1->value, 0);
    161       expected_vbits = or_vbits(term1, or_vbits(term2, term3));
    162       break;
    163    }
    164 
    165    case UNDEF_OR: {
    166       /* Let v1, v2 be the V-bits of the 1st and 2nd operand, respectively
    167          Let b1, b2 be the actual value of the 1st and 2nd operand, respect.
    168          And output bit is undefined (i.e. its V-bit == 1), iff
    169          (1) (v1 == 1) && (v2 == 1)   OR
    170          (2) (v1 == 1) && (v2 == 0 && b2 == 0) OR
    171          (3) (v2 == 1) && (v1 == 0 && b1 == 0)
    172       */
    173       vbits_t term1, term2, term3;
    174       term1 = and_vbits(opnd1->vbits, opnd2->vbits);
    175       term2 = and_combine(opnd1->vbits, opnd2->vbits, opnd2->value, 1);
    176       term3 = and_combine(opnd2->vbits, opnd1->vbits, opnd1->value, 1);
    177       expected_vbits = or_vbits(term1, or_vbits(term2, term3));
    178       break;
    179    }
    180 
    181    case UNDEF_ORD:
    182       /* Set expected_vbits for the Iop_CmpORD category of iops.
    183        * If any of the input bits is undefined the least significant
    184        * three bits in the result will be set, i.e. 0xe.
    185        */
    186       expected_vbits = cmpord_vbits(opnd1->vbits.num_bits,
    187                                     opnd2->vbits.num_bits);
    188       break;
    189 
    190    default:
    191       panic(__func__);
    192    }
    193 
    194    if (! equal_vbits(result->vbits, expected_vbits))
    195       complain(op, data, expected_vbits);
    196 }
    197 
    198 
    199 static int
    200 test_shift(const irop_t *op, test_data_t *data)
    201 {
    202    unsigned num_input_bits, i;
    203    opnd_t *opnds = data->opnds;
    204    int tests_done = 0;
    205 
    206    /* When testing the 1st operand's undefinedness propagation,
    207       do so with all possible shift amnounts */
    208    for (unsigned amount = 0; amount < bitsof_irtype(opnds[0].type); ++amount) {
    209       opnds[1].value.u8 = amount;
    210 
    211       // 1st (left) operand
    212       num_input_bits = bitsof_irtype(opnds[0].type);
    213 
    214       for (i = 0; i < num_input_bits; ++i) {
    215          opnds[0].vbits = onehot_vbits(i, bitsof_irtype(opnds[0].type));
    216          opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    217 
    218          valgrind_execute_test(op, data);
    219 
    220          check_result_for_binary(op, data);
    221          tests_done++;
    222       }
    223    }
    224 
    225    // 2nd (right) operand
    226 
    227    /* If the operand is an immediate value, there are no v-bits to set. */
    228    if (op->shift_amount_is_immediate) return tests_done;
    229 
    230    num_input_bits = bitsof_irtype(opnds[1].type);
    231 
    232    for (i = 0; i < num_input_bits; ++i) {
    233       opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    234       opnds[1].vbits = onehot_vbits(i, bitsof_irtype(opnds[1].type));
    235 
    236       valgrind_execute_test(op, data);
    237 
    238       check_result_for_binary(op, data);
    239 
    240       tests_done++;
    241    }
    242    return tests_done;
    243 }
    244 
    245 
    246 static value_t
    247 all_bits_zero_value(unsigned num_bits)
    248 {
    249    value_t val;
    250 
    251    switch (num_bits) {
    252    case 8:  val.u8  = 0; break;
    253    case 16: val.u16 = 0; break;
    254    case 32: val.u32 = 0; break;
    255    case 64: val.u64 = 0; break;
    256    default:
    257       panic(__func__);
    258    }
    259    return val;
    260 }
    261 
    262 
    263 static value_t
    264 all_bits_one_value(unsigned num_bits)
    265 {
    266    value_t val;
    267 
    268    switch (num_bits) {
    269    case 8:  val.u8  = 0xff;   break;
    270    case 16: val.u16 = 0xffff; break;
    271    case 32: val.u32 = ~0u;    break;
    272    case 64: val.u64 = ~0ull;  break;
    273    default:
    274       panic(__func__);
    275    }
    276    return val;
    277 }
    278 
    279 
    280 static int
    281 test_and(const irop_t *op, test_data_t *data)
    282 {
    283    unsigned num_input_bits, bitpos;
    284    opnd_t *opnds = data->opnds;
    285    int tests_done = 0;
    286 
    287    /* Undefinedness does not propagate if the other operand is 0.
    288       Use an all-bits-zero operand and test the other operand in
    289       the usual way (one bit undefined at a time). */
    290 
    291    // 1st (left) operand variable, 2nd operand all-bits-zero
    292    num_input_bits = bitsof_irtype(opnds[0].type);
    293 
    294    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    295       opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type));
    296       opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    297       opnds[1].value = all_bits_zero_value(bitsof_irtype(opnds[1].type));
    298 
    299       valgrind_execute_test(op, data);
    300 
    301       check_result_for_binary(op, data);
    302       tests_done++;
    303    }
    304 
    305    // 2nd (right) operand variable, 1st operand all-bits-zero
    306    num_input_bits = bitsof_irtype(opnds[1].type);
    307 
    308    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    309       opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type));
    310       opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    311       opnds[0].value = all_bits_zero_value(bitsof_irtype(opnds[0].type));
    312 
    313       valgrind_execute_test(op, data);
    314 
    315       check_result_for_binary(op, data);
    316       tests_done++;
    317    }
    318 
    319    /* Undefinedness propagates if the other operand is 1.
    320       Use an all-bits-one operand and test the other operand in
    321       the usual way (one bit undefined at a time). */
    322 
    323    // 1st (left) operand variable, 2nd operand all-bits-one
    324    num_input_bits = bitsof_irtype(opnds[0].type);
    325 
    326    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    327       opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type));
    328       opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    329       opnds[1].value = all_bits_one_value(bitsof_irtype(opnds[1].type));
    330 
    331       valgrind_execute_test(op, data);
    332 
    333       check_result_for_binary(op, data);
    334       tests_done++;
    335    }
    336 
    337    // 2nd (right) operand variable, 1st operand all-bits-one
    338    num_input_bits = bitsof_irtype(opnds[1].type);
    339 
    340    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    341       opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type));
    342       opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    343       opnds[0].value = all_bits_one_value(bitsof_irtype(opnds[0].type));
    344 
    345       valgrind_execute_test(op, data);
    346 
    347       check_result_for_binary(op, data);
    348       tests_done++;
    349    }
    350    return tests_done;
    351 }
    352 
    353 
    354 static int
    355 test_or(const irop_t *op, test_data_t *data)
    356 {
    357    unsigned num_input_bits, bitpos;
    358    opnd_t *opnds = data->opnds;
    359    int tests_done = 0;
    360 
    361    /* Undefinedness does not propagate if the other operand is 1.
    362       Use an all-bits-one operand and test the other operand in
    363       the usual way (one bit undefined at a time). */
    364 
    365    // 1st (left) operand variable, 2nd operand all-bits-one
    366    num_input_bits = bitsof_irtype(opnds[0].type);
    367 
    368    opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    369    opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    370    opnds[1].value = all_bits_one_value(bitsof_irtype(opnds[1].type));
    371 
    372    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    373       opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type));
    374 
    375       valgrind_execute_test(op, data);
    376 
    377       check_result_for_binary(op, data);
    378       tests_done++;
    379    }
    380 
    381    // 2nd (right) operand variable, 1st operand all-bits-one
    382    num_input_bits = bitsof_irtype(opnds[1].type);
    383 
    384    opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    385    opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    386    opnds[0].value = all_bits_one_value(bitsof_irtype(opnds[0].type));
    387 
    388    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    389       opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type));
    390 
    391       valgrind_execute_test(op, data);
    392 
    393       check_result_for_binary(op, data);
    394       tests_done++;
    395    }
    396 
    397    /* Undefinedness propagates if the other operand is 0.
    398       Use an all-bits-zero operand and test the other operand in
    399       the usual way (one bit undefined at a time). */
    400 
    401    // 1st (left) operand variable, 2nd operand all-bits-zero
    402    num_input_bits = bitsof_irtype(opnds[0].type);
    403 
    404    opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    405    opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    406    opnds[1].value = all_bits_zero_value(bitsof_irtype(opnds[1].type));
    407 
    408    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    409       opnds[0].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[0].type));
    410 
    411       valgrind_execute_test(op, data);
    412 
    413       check_result_for_binary(op, data);
    414       tests_done++;
    415    }
    416 
    417    // 2nd (right) operand variable, 1st operand all-bits-zero
    418    num_input_bits = bitsof_irtype(opnds[1].type);
    419 
    420    opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    421    opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    422    opnds[0].value = all_bits_zero_value(bitsof_irtype(opnds[0].type));
    423 
    424    for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    425       opnds[1].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[1].type));
    426 
    427       valgrind_execute_test(op, data);
    428 
    429       check_result_for_binary(op, data);
    430       tests_done++;
    431    }
    432    return tests_done;
    433 }
    434 
    435 
    436 int
    437 test_binary_op(const irop_t *op, test_data_t *data)
    438 {
    439    unsigned num_input_bits, i, bitpos;
    440    opnd_t *opnds = data->opnds;
    441    int tests_done = 0;
    442 
    443    /* Handle special cases upfront */
    444    switch (op->undef_kind) {
    445    case UNDEF_SHL:
    446    case UNDEF_SHR:
    447    case UNDEF_SAR:
    448       return test_shift(op, data);
    449 
    450    case UNDEF_AND:
    451       return test_and(op, data);
    452 
    453    case UNDEF_OR:
    454       return test_or(op, data);
    455 
    456    default:
    457       break;
    458    }
    459 
    460    /* For each operand, set a single bit to undefined and observe how
    461       that propagates to the output. Do this for all bits in each
    462       operand. */
    463    for (i = 0; i < 2; ++i) {
    464 
    465       /* If this is a shift op that requires an immediate shift amount,
    466          do not iterate the v-bits of the 2nd operand */
    467       if (i == 1 && op->shift_amount_is_immediate) break;
    468 
    469       num_input_bits = bitsof_irtype(opnds[i].type);
    470       opnds[0].vbits = defined_vbits(bitsof_irtype(opnds[0].type));
    471       opnds[1].vbits = defined_vbits(bitsof_irtype(opnds[1].type));
    472 
    473       /* Set the value of the 2nd operand to something != 0. So division
    474          won't crash. */
    475       memset(&opnds[1].value, 0xff, sizeof opnds[1].value);
    476 
    477       /* For immediate shift amounts choose a value of '1'. That value should
    478          not cause a problem. Note: we always assign to the u64 member here.
    479          The reason is that in ir_inject.c the value_t type is not visible.
    480          The value is picked up there by interpreting the memory as an
    481          ULong value. So, we rely on
    482          union {
    483            ULong   v1;   // value picked up in ir_inject.c
    484            value_t v2;   // value assigned here
    485          } xx;
    486          assert(sizeof xx.v1 == sizeof xx.v2.u64);
    487          assert(xx.v1 == xx.v2.u64);
    488       */
    489       if (op->shift_amount_is_immediate)
    490          opnds[1].value.u64 = 1;
    491 
    492       for (bitpos = 0; bitpos < num_input_bits; ++bitpos) {
    493          opnds[i].vbits = onehot_vbits(bitpos, bitsof_irtype(opnds[i].type));
    494 
    495          valgrind_execute_test(op, data);
    496 
    497          check_result_for_binary(op, data);
    498 
    499          tests_done++;
    500       }
    501    }
    502    return tests_done;
    503 }
    504