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 "brw_eu.h"
29 #include "brw_gen_enum.h"
30 
31 static bool
test_compact_instruction(struct brw_codegen * p,brw_inst src)32 test_compact_instruction(struct brw_codegen *p, brw_inst src)
33 {
34    brw_compact_inst dst;
35    memset(&dst, 0xd0, sizeof(dst));
36 
37    if (brw_try_compact_instruction(p->devinfo, &dst, &src)) {
38       brw_inst uncompacted;
39 
40       brw_uncompact_instruction(p->devinfo, &uncompacted, &dst);
41       if (memcmp(&uncompacted, &src, sizeof(src))) {
42 	 brw_debug_compact_uncompact(p->devinfo, &src, &uncompacted);
43 	 return false;
44       }
45    } else {
46       brw_compact_inst unchanged;
47       memset(&unchanged, 0xd0, sizeof(unchanged));
48       /* It's not supposed to change dst unless it compacted. */
49       if (memcmp(&unchanged, &dst, sizeof(dst))) {
50 	 fprintf(stderr, "Failed to compact, but dst changed\n");
51 	 fprintf(stderr, "  Instruction: ");
52 	 brw_disassemble_inst(stderr, p->devinfo, &src, false, 0, NULL);
53 	 return false;
54       }
55    }
56 
57    return true;
58 }
59 
60 /**
61  * When doing fuzz testing, pad bits won't round-trip.
62  *
63  * This sort of a superset of skip_bit, which is testing for changing bits that
64  * aren't worth testing for fuzzing.  We also just want to clear bits that
65  * become meaningless once fuzzing twiddles a related bit.
66  */
67 static void
clear_pad_bits(const struct gen_device_info * devinfo,brw_inst * inst)68 clear_pad_bits(const struct gen_device_info *devinfo, brw_inst *inst)
69 {
70    if (brw_inst_opcode(devinfo, inst) != BRW_OPCODE_SEND &&
71        brw_inst_opcode(devinfo, inst) != BRW_OPCODE_SENDC &&
72        brw_inst_src0_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE &&
73        brw_inst_src1_reg_file(devinfo, inst) != BRW_IMMEDIATE_VALUE) {
74       brw_inst_set_bits(inst, 127, 111, 0);
75    }
76 
77    if (devinfo->gen == 8 && !devinfo->is_cherryview &&
78        is_3src(devinfo, brw_inst_opcode(devinfo, inst))) {
79       brw_inst_set_bits(inst, 105, 105, 0);
80       brw_inst_set_bits(inst, 84, 84, 0);
81       brw_inst_set_bits(inst, 36, 35, 0);
82    }
83 }
84 
85 static bool
skip_bit(const struct gen_device_info * devinfo,brw_inst * src,int bit)86 skip_bit(const struct gen_device_info *devinfo, brw_inst *src, int bit)
87 {
88    /* pad bit */
89    if (bit == 7)
90       return true;
91 
92    /* The compact bit -- uncompacted can't have it set. */
93    if (bit == 29)
94       return true;
95 
96    if (is_3src(devinfo, brw_inst_opcode(devinfo, src))) {
97       if (devinfo->gen >= 9 || devinfo->is_cherryview) {
98          if (bit == 127)
99             return true;
100       } else {
101          if (bit >= 126 && bit <= 127)
102             return true;
103 
104          if (bit == 105)
105             return true;
106 
107          if (bit == 84)
108             return true;
109 
110          if (bit >= 35 && bit <= 36)
111             return true;
112       }
113    } else {
114       if (bit == 47)
115          return true;
116 
117       if (devinfo->gen >= 8) {
118          if (bit == 11)
119             return true;
120 
121          if (bit == 95)
122             return true;
123       } else {
124          if (devinfo->gen < 7 && bit == 90)
125             return true;
126 
127          if (bit >= 91 && bit <= 95)
128             return true;
129       }
130    }
131 
132    /* sometimes these are pad bits. */
133    if (brw_inst_opcode(devinfo, src) != BRW_OPCODE_SEND &&
134        brw_inst_opcode(devinfo, src) != BRW_OPCODE_SENDC &&
135        brw_inst_src0_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE &&
136        brw_inst_src1_reg_file(devinfo, src) != BRW_IMMEDIATE_VALUE &&
137        bit >= 121) {
138       return true;
139    }
140 
141    return false;
142 }
143 
144 static bool
test_fuzz_compact_instruction(struct brw_codegen * p,brw_inst src)145 test_fuzz_compact_instruction(struct brw_codegen *p, brw_inst src)
146 {
147    for (int bit0 = 0; bit0 < 128; bit0++) {
148       if (skip_bit(p->devinfo, &src, bit0))
149 	 continue;
150 
151       for (int bit1 = 0; bit1 < 128; bit1++) {
152          brw_inst instr = src;
153 	 uint64_t *bits = instr.data;
154 
155          if (skip_bit(p->devinfo, &src, bit1))
156 	    continue;
157 
158 	 bits[bit0 / 64] ^= (1ull << (bit0 & 63));
159 	 bits[bit1 / 64] ^= (1ull << (bit1 & 63));
160 
161          clear_pad_bits(p->devinfo, &instr);
162 
163          if (!brw_validate_instruction(p->devinfo, &instr, 0, NULL))
164             continue;
165 
166 	 if (!test_compact_instruction(p, instr)) {
167 	    printf("  twiddled bits for fuzzing %d, %d\n", bit0, bit1);
168 	    return false;
169 	 }
170       }
171    }
172 
173    return true;
174 }
175 
176 static void
gen_ADD_GRF_GRF_GRF(struct brw_codegen * p)177 gen_ADD_GRF_GRF_GRF(struct brw_codegen *p)
178 {
179    struct brw_reg g0 = brw_vec8_grf(0, 0);
180    struct brw_reg g2 = brw_vec8_grf(2, 0);
181    struct brw_reg g4 = brw_vec8_grf(4, 0);
182 
183    brw_ADD(p, g0, g2, g4);
184 }
185 
186 static void
gen_ADD_GRF_GRF_IMM(struct brw_codegen * p)187 gen_ADD_GRF_GRF_IMM(struct brw_codegen *p)
188 {
189    struct brw_reg g0 = brw_vec8_grf(0, 0);
190    struct brw_reg g2 = brw_vec8_grf(2, 0);
191 
192    brw_ADD(p, g0, g2, brw_imm_f(1.0));
193 }
194 
195 static void
gen_ADD_GRF_GRF_IMM_d(struct brw_codegen * p)196 gen_ADD_GRF_GRF_IMM_d(struct brw_codegen *p)
197 {
198    struct brw_reg g0 = retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_D);
199    struct brw_reg g2 = retype(brw_vec8_grf(2, 0), BRW_REGISTER_TYPE_D);
200 
201    brw_ADD(p, g0, g2, brw_imm_d(1));
202 }
203 
204 static void
gen_MOV_GRF_GRF(struct brw_codegen * p)205 gen_MOV_GRF_GRF(struct brw_codegen *p)
206 {
207    struct brw_reg g0 = brw_vec8_grf(0, 0);
208    struct brw_reg g2 = brw_vec8_grf(2, 0);
209 
210    brw_MOV(p, g0, g2);
211 }
212 
213 static void
gen_ADD_MRF_GRF_GRF(struct brw_codegen * p)214 gen_ADD_MRF_GRF_GRF(struct brw_codegen *p)
215 {
216    struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0);
217    struct brw_reg g2 = brw_vec8_grf(2, 0);
218    struct brw_reg g4 = brw_vec8_grf(4, 0);
219 
220    brw_ADD(p, m6, g2, g4);
221 }
222 
223 static void
gen_ADD_vec1_GRF_GRF_GRF(struct brw_codegen * p)224 gen_ADD_vec1_GRF_GRF_GRF(struct brw_codegen *p)
225 {
226    struct brw_reg g0 = brw_vec1_grf(0, 0);
227    struct brw_reg g2 = brw_vec1_grf(2, 0);
228    struct brw_reg g4 = brw_vec1_grf(4, 0);
229 
230    brw_ADD(p, g0, g2, g4);
231 }
232 
233 static void
gen_PLN_MRF_GRF_GRF(struct brw_codegen * p)234 gen_PLN_MRF_GRF_GRF(struct brw_codegen *p)
235 {
236    struct brw_reg m6 = brw_vec8_reg(BRW_MESSAGE_REGISTER_FILE, 6, 0);
237    struct brw_reg interp = brw_vec1_grf(2, 0);
238    struct brw_reg g4 = brw_vec8_grf(4, 0);
239 
240    brw_PLN(p, m6, interp, g4);
241 }
242 
243 static void
gen_f0_0_MOV_GRF_GRF(struct brw_codegen * p)244 gen_f0_0_MOV_GRF_GRF(struct brw_codegen *p)
245 {
246    struct brw_reg g0 = brw_vec8_grf(0, 0);
247    struct brw_reg g2 = brw_vec8_grf(2, 0);
248 
249    brw_push_insn_state(p);
250    brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL);
251    brw_MOV(p, g0, g2);
252    brw_pop_insn_state(p);
253 }
254 
255 /* The handling of f0.1 vs f0.0 changes between gen6 and gen7.  Explicitly test
256  * it, so that we run the fuzzing can run over all the other bits that might
257  * interact with it.
258  */
259 static void
gen_f0_1_MOV_GRF_GRF(struct brw_codegen * p)260 gen_f0_1_MOV_GRF_GRF(struct brw_codegen *p)
261 {
262    struct brw_reg g0 = brw_vec8_grf(0, 0);
263    struct brw_reg g2 = brw_vec8_grf(2, 0);
264 
265    brw_push_insn_state(p);
266    brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL);
267    brw_inst *mov = brw_MOV(p, g0, g2);
268    brw_inst_set_flag_subreg_nr(p->devinfo, mov, 1);
269    brw_pop_insn_state(p);
270 }
271 
272 struct {
273    void (*func)(struct brw_codegen *p);
274    int gens;
275 } tests[] = {
276    { gen_MOV_GRF_GRF,          GEN_ALL      },
277    { gen_ADD_GRF_GRF_GRF,      GEN_ALL      },
278    { gen_ADD_GRF_GRF_IMM,      GEN_ALL      },
279    { gen_ADD_GRF_GRF_IMM_d,    GEN_ALL      },
280    { gen_ADD_MRF_GRF_GRF,      GEN_LE(GEN6) },
281    { gen_ADD_vec1_GRF_GRF_GRF, GEN_ALL      },
282    { gen_PLN_MRF_GRF_GRF,      GEN_LE(GEN6) },
283    { gen_f0_0_MOV_GRF_GRF,     GEN_ALL      },
284    { gen_f0_1_MOV_GRF_GRF,     GEN_ALL      },
285 };
286 
287 static bool
run_tests(const struct gen_device_info * devinfo)288 run_tests(const struct gen_device_info *devinfo)
289 {
290    bool fail = false;
291 
292    for (unsigned i = 0; i < ARRAY_SIZE(tests); i++) {
293       if ((tests[i].gens & gen_from_devinfo(devinfo)) == 0)
294          continue;
295 
296       for (int align_16 = 0; align_16 <= 1; align_16++) {
297          /* Align16 support is not present on Gen11+ */
298          if (devinfo->gen >= 11 && align_16)
299             continue;
300 
301 	 struct brw_codegen *p = rzalloc(NULL, struct brw_codegen);
302 	 brw_init_codegen(devinfo, p, p);
303 
304 	 brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
305 	 if (align_16)
306 	    brw_set_default_access_mode(p, BRW_ALIGN_16);
307 	 else
308 	    brw_set_default_access_mode(p, BRW_ALIGN_1);
309 
310 	 tests[i].func(p);
311 	 assert(p->nr_insn == 1);
312 
313 	 if (!test_compact_instruction(p, p->store[0])) {
314 	    fail = true;
315 	    continue;
316 	 }
317 
318 	 if (!test_fuzz_compact_instruction(p, p->store[0])) {
319 	    fail = true;
320 	    continue;
321 	 }
322 
323 	 ralloc_free(p);
324       }
325    }
326 
327    return fail;
328 }
329 
330 int
main(UNUSED int argc,UNUSED char ** argv)331 main(UNUSED int argc, UNUSED char **argv)
332 {
333    struct gen_device_info *devinfo = (struct gen_device_info *)calloc(1, sizeof(*devinfo));
334    bool fail = false;
335 
336    for (devinfo->gen = 5; devinfo->gen <= 12; devinfo->gen++) {
337       if (devinfo->gen == 10)
338          continue;
339 
340       fail |= run_tests(devinfo);
341    }
342 
343    return fail;
344 }
345