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