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 */
9IRICB
10new_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. */
39static void
40valgrind_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
58static void
59valgrind_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 */
73void
74valgrind_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). */
82static void
83valgrind_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... */
91void
92valgrind_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