florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 1 | /* -*- mode: C; c-basic-offset: 3; -*- */ |
| 2 | |
florian | 5aa9d1e | 2015-09-22 07:21:50 +0000 | [diff] [blame] | 3 | /* |
| 4 | This file is part of MemCheck, a heavyweight Valgrind tool for |
| 5 | detecting memory errors. |
| 6 | |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 7 | Copyright (C) 2012-2017 Florian Krohm |
florian | 5aa9d1e | 2015-09-22 07:21:50 +0000 | [diff] [blame] | 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 | |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 27 | #include <assert.h> // assert |
| 28 | #include <stdio.h> // printf |
| 29 | #include <stdlib.h> // malloc |
| 30 | #include <string.h> // memset |
| 31 | #include "valgrind.h" // RUNNING_ON_VALGRIND |
| 32 | #include "vtest.h" |
| 33 | |
| 34 | |
| 35 | static test_data_t * |
| 36 | new_test_data(const irop_t *op) |
| 37 | { |
| 38 | test_data_t *data = malloc(sizeof *data); |
| 39 | |
| 40 | memset(data, 0x0, sizeof *data); // initialise |
| 41 | |
| 42 | /* Obtain the operand types and set them */ |
| 43 | IRType t_dst, t1, t2, t3, t4; |
| 44 | |
| 45 | typeof_primop(op->op, &t_dst, &t1, &t2, &t3, &t4); |
| 46 | assert(t_dst != Ity_INVALID); |
| 47 | assert(t1 != Ity_INVALID); |
| 48 | |
| 49 | data->result.type = t_dst; |
| 50 | if (is_floating_point_op_with_rounding_mode(op->op)) { |
| 51 | data->opnds[0].type = t2; |
| 52 | data->opnds[1].type = t3; |
| 53 | data->opnds[2].type = t4; |
| 54 | data->opnds[3].type = Ity_INVALID; |
| 55 | } else { |
| 56 | data->opnds[0].type = t1; |
| 57 | data->opnds[1].type = t2; |
| 58 | data->opnds[2].type = t3; |
| 59 | data->opnds[3].type = t4; |
| 60 | } |
| 61 | |
| 62 | /* Set the rounding mode if the operation requires one. |
| 63 | FIXME: We should iterate over all rounding modes. For that need |
| 64 | FIXME: to distinguish between binary and decimal floating point */ |
| 65 | if (is_floating_point_op_with_rounding_mode(op->op)) { |
| 66 | // for now just pick one |
| 67 | data->rounding_mode = Irrm_NEAREST; // same as Irrm_DFP_NEAREST |
| 68 | } else { |
| 69 | data->rounding_mode = NO_ROUNDING_MODE; |
| 70 | } |
| 71 | |
| 72 | return data; |
| 73 | } |
| 74 | |
| 75 | int verbose = 0; |
| 76 | |
florian | f74f542 | 2012-09-13 19:41:12 +0000 | [diff] [blame] | 77 | |
| 78 | /* Certain IROps require special handling. */ |
| 79 | static void |
| 80 | fixup_irops(void) |
| 81 | { |
| 82 | #ifdef __powerpc__ |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame] | 83 | irop_t* tmp; |
| 84 | |
| 85 | /* Iops with immediate shift value */ |
| 86 | tmp = get_irop(Iop_ShlD64); |
| 87 | if (tmp) { |
| 88 | tmp->immediate_index = 2; |
| 89 | tmp->immediate_type = Ity_I8; |
| 90 | } |
| 91 | |
| 92 | tmp = get_irop(Iop_ShrD64); |
| 93 | if (tmp) { |
| 94 | tmp->immediate_index = 2; |
| 95 | tmp->immediate_type = Ity_I8; |
| 96 | } |
| 97 | |
| 98 | tmp = get_irop(Iop_ShlD128); |
| 99 | if (tmp) { |
| 100 | tmp->immediate_index = 2; |
| 101 | tmp->immediate_type = Ity_I8; |
| 102 | } |
| 103 | |
| 104 | tmp = get_irop(Iop_ShrD128); |
| 105 | if (tmp) { |
| 106 | tmp->immediate_index = 2; |
| 107 | tmp->immediate_type = Ity_I8; |
| 108 | } |
| 109 | |
| 110 | /* Iops with immediate value that controls PPC instruction behavior */ |
| 111 | tmp = get_irop(Iop_SHA256); |
| 112 | if (tmp) { |
| 113 | tmp->immediate_index = 2; |
| 114 | tmp->immediate_type = Ity_I8; |
| 115 | } |
| 116 | |
| 117 | tmp = get_irop(Iop_SHA512); |
| 118 | if (tmp) { |
| 119 | tmp->immediate_index = 2; |
| 120 | tmp->immediate_type = Ity_I8; |
| 121 | } |
florian | f74f542 | 2012-09-13 19:41:12 +0000 | [diff] [blame] | 122 | #endif |
| 123 | } |
| 124 | |
| 125 | |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 126 | int |
| 127 | main(int argc, char *argv[]) |
| 128 | { |
| 129 | assert(sizeof(long long) == 8); |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 130 | int num_unary_tests = 0, num_binary_tests = 0; |
| 131 | int num_ternary_tests = 0, num_qernary_tests = 0; |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 132 | |
| 133 | for (int i = 1; i < argc; ++i) { |
| 134 | if (strcmp(argv[i], "-v") == 0) ++verbose; |
| 135 | else if (strcmp(argv[i], "--help") == 0) { |
| 136 | printf("\nvbit-test [ -v | --help ]\n"); |
florian | dc01f93 | 2015-09-22 07:03:38 +0000 | [diff] [blame] | 137 | printf("\n\t-v verbose mode; show number of tests\n"); |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 138 | printf("\n\t-v -v verbose mode; shows IROps being tested\n"); |
| 139 | printf("\n\t-v -v -v verbose mode, extreme edition\n\n"); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 140 | return 0; |
| 141 | } else { |
| 142 | printf("%s ? Nothing happens.\n", argv[i]); |
| 143 | return 1; |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | if (! RUNNING_ON_VALGRIND) { |
| 148 | fprintf(stderr, "*** This program needs to run under memcheck.\n"); |
| 149 | return 1; |
| 150 | } |
| 151 | |
| 152 | setbuf(stdout, NULL); // make stdout unbuffered |
| 153 | |
florian | f74f542 | 2012-09-13 19:41:12 +0000 | [diff] [blame] | 154 | fixup_irops(); // determine need for special handling |
| 155 | |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 156 | // Iterate over all primops |
| 157 | IROp first = Iop_INVALID + 1; |
| 158 | IROp last = Iop_LAST; |
| 159 | IROp opkind; |
| 160 | |
| 161 | if (0) { // overwrite for debugging |
| 162 | first = Iop_CasCmpEQ8; last = first + 1; |
| 163 | } |
| 164 | |
| 165 | // Iterate over all IROps in the enum type. That is the only way to |
| 166 | // make sure the operator is tested on at least one platform. |
| 167 | |
| 168 | // Loop assumes no holes in the enumerator values |
| 169 | for (opkind = first; opkind < last; ++opkind) { |
| 170 | |
| 171 | const irop_t *op = get_irop(opkind); |
| 172 | if (op == NULL) continue; |
| 173 | |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 174 | if (op->undef_kind == UNDEF_UNKNOWN) { |
| 175 | fprintf(stderr, "...skipping %s; unknown undef propagation\n", |
| 176 | op->name); |
| 177 | continue; |
| 178 | } |
| 179 | |
florian | 95fba4c | 2015-09-22 11:06:42 +0000 | [diff] [blame] | 180 | test_data_t *data = new_test_data(op); |
| 181 | |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 182 | if (verbose > 1) printf("Testing operator %s\n", op->name); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 183 | |
| 184 | IRICB iricb = new_iricb(op, data); |
| 185 | |
| 186 | valgrind_vex_init_for_iri(&iricb); |
| 187 | |
| 188 | switch (iricb.num_operands) { |
| 189 | case 1: |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 190 | num_unary_tests += test_unary_op(op, data); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 191 | break; |
| 192 | |
| 193 | case 2: |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 194 | num_binary_tests += test_binary_op(op, data); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 195 | break; |
| 196 | |
| 197 | case 3: |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 198 | num_ternary_tests += test_ternary_op(op, data); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 199 | break; |
| 200 | |
| 201 | case 4: |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 202 | num_qernary_tests += test_qernary_op(op, data); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 203 | break; |
| 204 | |
| 205 | default: |
| 206 | panic("operator not handled"); |
| 207 | } |
florian | 1201479 | 2012-10-21 19:58:04 +0000 | [diff] [blame] | 208 | |
| 209 | free(data); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 210 | } |
| 211 | |
carll | 24c9e7f | 2012-11-16 19:41:21 +0000 | [diff] [blame] | 212 | if (verbose) |
florian | dc01f93 | 2015-09-22 07:03:38 +0000 | [diff] [blame] | 213 | printf("\nvbit-test ran %d unary, %d binary, %d ternary and" |
| 214 | " %d qernary tests.\n\n", |
| 215 | num_unary_tests, num_binary_tests, num_ternary_tests, |
| 216 | num_qernary_tests); |
florian | bb913cd | 2012-08-28 16:50:39 +0000 | [diff] [blame] | 217 | return 0; |
| 218 | } |