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