• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-basic-offset: 3; -*- */
2 
3 #include <assert.h>
4 #include "memcheck.h"  // VALGRIND_SET_VBITS
5 #include "vtest.h"
6 
7 
8 /* Return a completely initialised control block */
9 IRICB
new_iricb(const irop_t * op,test_data_t * data)10 new_iricb(const irop_t *op, test_data_t *data)
11 {
12    IRICB cb;
13 
14    cb.op = op->op;
15    cb.result = (HWord)&data->result.value;
16    cb.opnd1  = (HWord)&data->opnds[0].value;
17    cb.opnd2  = (HWord)&data->opnds[1].value;
18    cb.opnd3  = (HWord)&data->opnds[2].value;
19    cb.opnd4  = (HWord)&data->opnds[3].value;
20    cb.t_result = data->result.type;
21    cb.t_opnd1  = data->opnds[0].type;
22    cb.t_opnd2  = data->opnds[1].type;
23    cb.t_opnd3  = data->opnds[2].type;
24    cb.t_opnd4  = data->opnds[3].type;
25 
26    cb.rounding_mode = data->rounding_mode;
27 
28    cb.num_operands = get_num_operands(op->op);
29 
30    cb.shift_amount_is_immediate = op->shift_amount_is_immediate;
31 
32    return cb;
33 }
34 
35 
36 /* Ity_I1 values cannot be stored or loaded. So vex_inject_ir will load/store
37    such a value from/to a 4-byte container. It uses 32to1 and 1Uto32,
38    respectively. */
39 static void
valgrind_set_vbits(opnd_t * opnd)40 valgrind_set_vbits(opnd_t *opnd)
41 {
42    unsigned rc, num_bytes;
43 
44    /* 1-bit wide values cannot be read. So we read a 4 bytes here */
45    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
46    rc = VALGRIND_SET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
47    assert(rc == 1);
48 
49    // Make sure the v-bits were set correctly
50    vbits_t actual = { .num_bits = opnd->vbits.num_bits };
51    rc = VALGRIND_GET_VBITS(&opnd->value, &actual.bits, num_bytes);
52    assert(rc == 1);
53 
54    assert(equal_vbits(opnd->vbits, actual));
55 }
56 
57 
58 static void
valgrind_get_vbits(opnd_t * opnd)59 valgrind_get_vbits(opnd_t *opnd)
60 {
61    unsigned rc, num_bytes;
62 
63    /* 1-bit wide values cannot be stored. So we store them by writing a
64       single byte */
65    num_bytes = opnd->type == Ity_I1 ? 4 : sizeof_irtype(opnd->type);
66    opnd->vbits.num_bits = bitsof_irtype(opnd->type);
67    rc = VALGRIND_GET_VBITS(&opnd->value, &opnd->vbits.bits, num_bytes);
68    assert(rc == 1);
69 }
70 
71 
72 /* Insert a client request that will initialize VEX for IR injection */
73 void
valgrind_vex_init_for_iri(IRICB * cb)74 valgrind_vex_init_for_iri(IRICB *cb)
75 {
76    VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__VEX_INIT_FOR_IRI, cb, 0,0,0,0);
77 }
78 
79 
80 /* Insert a special opcode that will cause VEX to inject an IR stmt based
81    on the information passed in the IRICB (in valgrind_vex_init_for_iri). */
82 static void
valgrind_vex_inject_ir(void)83 valgrind_vex_inject_ir(void)
84 {
85    VALGRIND_VEX_INJECT_IR();
86 }
87 
88 
89 /* Execute the test under valgrind. Well, yes, we're not really executing
90    it here, just preparing for it... */
91 void
valgrind_execute_test(const irop_t * op,test_data_t * data)92 valgrind_execute_test(const irop_t *op, test_data_t *data)
93 {
94    unsigned i, num_operands;
95 
96    if (verbose > 2) printf("---------- Running a test\n");
97    num_operands = get_num_operands(op->op);
98 
99    for (i = 0; i < num_operands; ++i) {
100       valgrind_set_vbits(&data->opnds[i]);
101       if (verbose > 2) {
102          printf("opnd #%u:  ", i);
103          print_opnd(stdout, &data->opnds[i]);
104          printf("\n");
105       }
106    }
107    if (verbose > 2)
108       if (data->rounding_mode != NO_ROUNDING_MODE)
109          printf("rounding mode %u\n", data->rounding_mode);
110 
111    valgrind_vex_inject_ir();
112    valgrind_get_vbits(&data->result);
113    if (verbose > 2) {
114       printf("result:   ");
115       print_opnd(stdout, &data->result);
116       printf("\n");
117    }
118 }
119