1 /*
2 * Copyright © 2012 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdbool.h>
27 #include "util/ralloc.h"
28 #include "elk_disasm.h"
29 #include "elk_eu.h"
30
31 #include <gtest/gtest.h>
32
33 struct CompactParams {
34 unsigned verx10;
35 unsigned align;
36 };
37
38 std::string
get_compact_params_name(const testing::TestParamInfo<CompactParams> p)39 get_compact_params_name(const testing::TestParamInfo<CompactParams> p)
40 {
41 CompactParams params = p.param;
42 std::stringstream ss;
43 ss << params.verx10 << "_";
44 switch (params.align) {
45 case ELK_ALIGN_1:
46 ss << "Align_1";
47 break;
48 case ELK_ALIGN_16:
49 ss << "Align_16";
50 break;
51 default:
52 unreachable("invalid align");
53 }
54 return ss.str();
55 }
56
57 static bool
test_compact_instruction(struct elk_codegen * p,elk_inst src)58 test_compact_instruction(struct elk_codegen *p, elk_inst src)
59 {
60 elk_compact_inst dst;
61 memset(&dst, 0xd0, sizeof(dst));
62
63 if (elk_try_compact_instruction(p->isa, &dst, &src)) {
64 elk_inst uncompacted;
65
66 elk_uncompact_instruction(p->isa, &uncompacted, &dst);
67 if (memcmp(&uncompacted, &src, sizeof(src))) {
68 elk_debug_compact_uncompact(p->isa, &src, &uncompacted);
69 return false;
70 }
71 } else {
72 elk_compact_inst unchanged;
73 memset(&unchanged, 0xd0, sizeof(unchanged));
74 /* It's not supposed to change dst unless it compacted. */
75 if (memcmp(&unchanged, &dst, sizeof(dst))) {
76 fprintf(stderr, "Failed to compact, but dst changed\n");
77 fprintf(stderr, " Instruction: ");
78 elk_disassemble_inst(stderr, p->isa, &src, false, 0, NULL);
79 return false;
80 }
81 }
82
83 return true;
84 }
85
86 /**
87 * When doing fuzz testing, pad bits won't round-trip.
88 *
89 * This sort of a superset of skip_bit, which is testing for changing bits that
90 * aren't worth testing for fuzzing. We also just want to clear bits that
91 * become meaningless once fuzzing twiddles a related bit.
92 */
93 static void
clear_pad_bits(const struct elk_isa_info * isa,elk_inst * inst)94 clear_pad_bits(const struct elk_isa_info *isa, elk_inst *inst)
95 {
96 const struct intel_device_info *devinfo = isa->devinfo;
97
98 if (elk_inst_opcode(isa, inst) != ELK_OPCODE_SEND &&
99 elk_inst_opcode(isa, inst) != ELK_OPCODE_SENDC &&
100 elk_inst_src0_reg_file(devinfo, inst) != ELK_IMMEDIATE_VALUE &&
101 elk_inst_src1_reg_file(devinfo, inst) != ELK_IMMEDIATE_VALUE) {
102 elk_inst_set_bits(inst, 127, 111, 0);
103 }
104
105 if (devinfo->ver == 8 && devinfo->platform != INTEL_PLATFORM_CHV &&
106 elk_is_3src(isa, elk_inst_opcode(isa, inst))) {
107 elk_inst_set_bits(inst, 105, 105, 0);
108 elk_inst_set_bits(inst, 84, 84, 0);
109 elk_inst_set_bits(inst, 36, 35, 0);
110 }
111 }
112
113 static bool
skip_bit(const struct elk_isa_info * isa,elk_inst * src,int bit)114 skip_bit(const struct elk_isa_info *isa, elk_inst *src, int bit)
115 {
116 const struct intel_device_info *devinfo = isa->devinfo;
117
118 /* pad bit */
119 if (bit == 7)
120 return true;
121
122 /* The compact bit -- uncompacted can't have it set. */
123 if (bit == 29)
124 return true;
125
126 if (elk_is_3src(isa, elk_inst_opcode(isa, src))) {
127 if (devinfo->platform == INTEL_PLATFORM_CHV) {
128 if (bit == 127)
129 return true;
130 } else {
131 if (bit >= 126 && bit <= 127)
132 return true;
133
134 if (bit == 105)
135 return true;
136
137 if (bit == 84)
138 return true;
139
140 if (bit >= 35 && bit <= 36)
141 return true;
142 }
143 } else {
144 if (bit == 47)
145 return true;
146
147 if (devinfo->ver >= 8) {
148 if (bit == 11)
149 return true;
150
151 if (bit == 95)
152 return true;
153 } else {
154 if (devinfo->ver < 7 && bit == 90)
155 return true;
156
157 if (bit >= 91 && bit <= 95)
158 return true;
159 }
160 }
161
162 /* sometimes these are pad bits. */
163 if (elk_inst_opcode(isa, src) != ELK_OPCODE_SEND &&
164 elk_inst_opcode(isa, src) != ELK_OPCODE_SENDC &&
165 elk_inst_src0_reg_file(devinfo, src) != ELK_IMMEDIATE_VALUE &&
166 elk_inst_src1_reg_file(devinfo, src) != ELK_IMMEDIATE_VALUE &&
167 bit >= 121) {
168 return true;
169 }
170
171 return false;
172 }
173
174 static bool
test_fuzz_compact_instruction(struct elk_codegen * p,elk_inst src)175 test_fuzz_compact_instruction(struct elk_codegen *p, elk_inst src)
176 {
177 for (int bit0 = 0; bit0 < 128; bit0++) {
178 if (skip_bit(p->isa, &src, bit0))
179 continue;
180
181 for (int bit1 = 0; bit1 < 128; bit1++) {
182 elk_inst instr = src;
183 uint64_t *bits = instr.data;
184
185 if (skip_bit(p->isa, &src, bit1))
186 continue;
187
188 bits[bit0 / 64] ^= (1ull << (bit0 & 63));
189 bits[bit1 / 64] ^= (1ull << (bit1 & 63));
190
191 clear_pad_bits(p->isa, &instr);
192
193 if (!elk_validate_instruction(p->isa, &instr, 0, sizeof(elk_inst), NULL))
194 continue;
195
196 if (!test_compact_instruction(p, instr)) {
197 printf(" twiddled bits for fuzzing %d, %d\n", bit0, bit1);
198 return false;
199 }
200 }
201 }
202
203 return true;
204 }
205
206 class CompactTestFixture : public testing::TestWithParam<CompactParams> {
207 protected:
SetUp()208 virtual void SetUp() {
209 CompactParams params = GetParam();
210 mem_ctx = ralloc_context(NULL);
211 devinfo = rzalloc(mem_ctx, intel_device_info);
212 p = rzalloc(mem_ctx, elk_codegen);
213
214 devinfo->verx10 = params.verx10;
215 devinfo->ver = devinfo->verx10 / 10;
216
217 elk_init_isa_info(&isa, devinfo);
218 elk_init_codegen(&isa, p, p);
219 elk_set_default_predicate_control(p, ELK_PREDICATE_NONE);
220 elk_set_default_access_mode(p, params.align);
221 };
222
TearDown()223 virtual void TearDown() {
224 EXPECT_EQ(p->nr_insn, 1);
225 EXPECT_TRUE(test_compact_instruction(p, p->store[0]));
226 EXPECT_TRUE(test_fuzz_compact_instruction(p, p->store[0]));
227
228 ralloc_free(mem_ctx);
229 };
230
231 void *mem_ctx;
232 struct elk_isa_info isa;
233 intel_device_info *devinfo;
234 elk_codegen *p;
235 };
236
237 class Instructions : public CompactTestFixture {};
238
239 INSTANTIATE_TEST_SUITE_P(
240 CompactTest,
241 Instructions,
242 testing::Values(
243 CompactParams{ 50, ELK_ALIGN_1 }, CompactParams{ 50, ELK_ALIGN_16 },
244 CompactParams{ 60, ELK_ALIGN_1 }, CompactParams{ 60, ELK_ALIGN_16 },
245 CompactParams{ 70, ELK_ALIGN_1 }, CompactParams{ 70, ELK_ALIGN_16 },
246 CompactParams{ 75, ELK_ALIGN_1 }, CompactParams{ 75, ELK_ALIGN_16 },
247 CompactParams{ 80, ELK_ALIGN_1 }, CompactParams{ 80, ELK_ALIGN_16 }
248 ),
249 get_compact_params_name);
250
251 class InstructionsBeforeIvyBridge : public CompactTestFixture {};
252
253 INSTANTIATE_TEST_SUITE_P(
254 CompactTest,
255 InstructionsBeforeIvyBridge,
256 testing::Values(
257 CompactParams{ 50, ELK_ALIGN_1 }, CompactParams{ 50, ELK_ALIGN_16 },
258 CompactParams{ 60, ELK_ALIGN_1 }, CompactParams{ 60, ELK_ALIGN_16 }
259 ),
260 get_compact_params_name);
261
262
TEST_P(Instructions,ADD_GRF_GRF_GRF)263 TEST_P(Instructions, ADD_GRF_GRF_GRF)
264 {
265 struct elk_reg g0 = elk_vec8_grf(0, 0);
266 struct elk_reg g2 = elk_vec8_grf(2, 0);
267 struct elk_reg g4 = elk_vec8_grf(4, 0);
268
269 elk_ADD(p, g0, g2, g4);
270 }
271
TEST_P(Instructions,ADD_GRF_GRF_IMM)272 TEST_P(Instructions, ADD_GRF_GRF_IMM)
273 {
274 struct elk_reg g0 = elk_vec8_grf(0, 0);
275 struct elk_reg g2 = elk_vec8_grf(2, 0);
276
277 elk_ADD(p, g0, g2, elk_imm_f(1.0));
278 }
279
TEST_P(Instructions,ADD_GRF_GRF_IMM_d)280 TEST_P(Instructions, ADD_GRF_GRF_IMM_d)
281 {
282 struct elk_reg g0 = retype(elk_vec8_grf(0, 0), ELK_REGISTER_TYPE_D);
283 struct elk_reg g2 = retype(elk_vec8_grf(2, 0), ELK_REGISTER_TYPE_D);
284
285 elk_ADD(p, g0, g2, elk_imm_d(1));
286 }
287
TEST_P(Instructions,MOV_GRF_GRF)288 TEST_P(Instructions, MOV_GRF_GRF)
289 {
290 struct elk_reg g0 = elk_vec8_grf(0, 0);
291 struct elk_reg g2 = elk_vec8_grf(2, 0);
292
293 elk_MOV(p, g0, g2);
294 }
295
TEST_P(InstructionsBeforeIvyBridge,ADD_MRF_GRF_GRF)296 TEST_P(InstructionsBeforeIvyBridge, ADD_MRF_GRF_GRF)
297 {
298 struct elk_reg m6 = elk_vec8_reg(ELK_MESSAGE_REGISTER_FILE, 6, 0);
299 struct elk_reg g2 = elk_vec8_grf(2, 0);
300 struct elk_reg g4 = elk_vec8_grf(4, 0);
301
302 elk_ADD(p, m6, g2, g4);
303 }
304
TEST_P(Instructions,ADD_vec1_GRF_GRF_GRF)305 TEST_P(Instructions, ADD_vec1_GRF_GRF_GRF)
306 {
307 struct elk_reg g0 = elk_vec1_grf(0, 0);
308 struct elk_reg g2 = elk_vec1_grf(2, 0);
309 struct elk_reg g4 = elk_vec1_grf(4, 0);
310
311 elk_ADD(p, g0, g2, g4);
312 }
313
TEST_P(InstructionsBeforeIvyBridge,PLN_MRF_GRF_GRF)314 TEST_P(InstructionsBeforeIvyBridge, PLN_MRF_GRF_GRF)
315 {
316 struct elk_reg m6 = elk_vec8_reg(ELK_MESSAGE_REGISTER_FILE, 6, 0);
317 struct elk_reg interp = elk_vec1_grf(2, 0);
318 struct elk_reg g4 = elk_vec8_grf(4, 0);
319
320 elk_PLN(p, m6, interp, g4);
321 }
322
TEST_P(Instructions,f0_0_MOV_GRF_GRF)323 TEST_P(Instructions, f0_0_MOV_GRF_GRF)
324 {
325 struct elk_reg g0 = elk_vec8_grf(0, 0);
326 struct elk_reg g2 = elk_vec8_grf(2, 0);
327
328 elk_push_insn_state(p);
329 elk_set_default_predicate_control(p, ELK_PREDICATE_NORMAL);
330 elk_MOV(p, g0, g2);
331 elk_pop_insn_state(p);
332 }
333
334 /* The handling of f0.1 vs f0.0 changes between gfx6 and gfx7. Explicitly test
335 * it, so that we run the fuzzing can run over all the other bits that might
336 * interact with it.
337 */
TEST_P(Instructions,f0_1_MOV_GRF_GRF)338 TEST_P(Instructions, f0_1_MOV_GRF_GRF)
339 {
340 struct elk_reg g0 = elk_vec8_grf(0, 0);
341 struct elk_reg g2 = elk_vec8_grf(2, 0);
342
343 elk_push_insn_state(p);
344 elk_set_default_predicate_control(p, ELK_PREDICATE_NORMAL);
345 elk_inst *mov = elk_MOV(p, g0, g2);
346 elk_inst_set_flag_subreg_nr(p->devinfo, mov, 1);
347 elk_pop_insn_state(p);
348 }
349