1 /*
2 * Copyright (c) 2018 Lima Project
3 *
4 * Copyright (c) 2013 Codethink (http://www.codethink.co.uk)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 */
26
27 #include "gpir.h"
28 #include "codegen.h"
29
30 typedef enum {
31 unit_acc_0,
32 unit_acc_1,
33 unit_mul_0,
34 unit_mul_1,
35 unit_pass,
36 unit_complex,
37 num_units
38 } gp_unit;
39
40 static const gpir_codegen_store_src gp_unit_to_store_src[num_units] = {
41 [unit_acc_0] = gpir_codegen_store_src_acc_0,
42 [unit_acc_1] = gpir_codegen_store_src_acc_1,
43 [unit_mul_0] = gpir_codegen_store_src_mul_0,
44 [unit_mul_1] = gpir_codegen_store_src_mul_1,
45 [unit_pass] = gpir_codegen_store_src_pass,
46 [unit_complex] = gpir_codegen_store_src_complex,
47 };
48
49 static void
print_dest(gpir_codegen_instr * instr,gp_unit unit,unsigned cur_dest_index)50 print_dest(gpir_codegen_instr *instr, gp_unit unit, unsigned cur_dest_index)
51 {
52 printf("^%u", cur_dest_index + unit);
53
54 gpir_codegen_store_src src = gp_unit_to_store_src[unit];
55
56 if (instr->store0_src_x == src ||
57 instr->store0_src_y == src) {
58 if (instr->store0_temporary) {
59 /* Temporary stores ignore the address, and always use whatever's
60 * stored in address register 0.
61 */
62 printf("/t[addr0]");
63 } else {
64 if (instr->store0_varying)
65 printf("/v");
66 else
67 printf("/$");
68 printf("%u", instr->store0_addr);
69 }
70
71 printf(".");
72 if (instr->store0_src_x == src)
73 printf("x");
74 if (instr->store0_src_y == src)
75 printf("y");
76 }
77
78 if (instr->store1_src_z == src ||
79 instr->store1_src_w == src) {
80 if (instr->store1_temporary) {
81 printf("/t[addr0]");
82 } else {
83 if (instr->store1_varying)
84 printf("/v");
85 else
86 printf("/$");
87 printf("%u", instr->store1_addr);
88 }
89
90 printf(".");
91 if (instr->store1_src_z == src)
92 printf("z");
93 if (instr->store1_src_w == src)
94 printf("w");
95 }
96
97 if (unit == unit_complex) {
98 switch (instr->complex_op) {
99 case gpir_codegen_complex_op_temp_store_addr:
100 printf("/addr0");
101 break;
102 case gpir_codegen_complex_op_temp_load_addr_0:
103 printf("/addr1");
104 break;
105 case gpir_codegen_complex_op_temp_load_addr_1:
106 printf("/addr2");
107 break;
108 case gpir_codegen_complex_op_temp_load_addr_2:
109 printf("/addr3");
110 break;
111 default:
112 break;
113 }
114 }
115 }
116
117 static void
print_src(gpir_codegen_src src,gp_unit unit,unsigned unit_src_num,gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned cur_dest_index)118 print_src(gpir_codegen_src src, gp_unit unit, unsigned unit_src_num,
119 gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
120 unsigned cur_dest_index)
121 {
122 switch (src) {
123 case gpir_codegen_src_attrib_x:
124 case gpir_codegen_src_attrib_y:
125 case gpir_codegen_src_attrib_z:
126 case gpir_codegen_src_attrib_w:
127 printf("%c%d.%c", instr->register0_attribute ? 'a' : '$',
128 instr->register0_addr, "xyzw"[src - gpir_codegen_src_attrib_x]);
129 break;
130
131 case gpir_codegen_src_register_x:
132 case gpir_codegen_src_register_y:
133 case gpir_codegen_src_register_z:
134 case gpir_codegen_src_register_w:
135 printf("$%d.%c", instr->register1_addr,
136 "xyzw"[src - gpir_codegen_src_register_x]);
137 break;
138
139 case gpir_codegen_src_unknown_0:
140 case gpir_codegen_src_unknown_1:
141 case gpir_codegen_src_unknown_2:
142 case gpir_codegen_src_unknown_3:
143 printf("unknown%d", src - gpir_codegen_src_unknown_0);
144 break;
145
146 case gpir_codegen_src_load_x:
147 case gpir_codegen_src_load_y:
148 case gpir_codegen_src_load_z:
149 case gpir_codegen_src_load_w:
150 printf("t[%d", instr->load_addr);
151 switch (instr->load_offset) {
152 case gpir_codegen_load_off_ld_addr_0:
153 printf("+addr1");
154 break;
155 case gpir_codegen_load_off_ld_addr_1:
156 printf("+addr2");
157 break;
158 case gpir_codegen_load_off_ld_addr_2:
159 printf("+addr3");
160 break;
161 case gpir_codegen_load_off_none:
162 break;
163 default:
164 printf("+unk%d", instr->load_offset);
165 }
166 printf("].%c", "xyzw"[src - gpir_codegen_src_load_x]);
167 break;
168
169 case gpir_codegen_src_p1_acc_0:
170 printf("^%d", cur_dest_index - 1 * num_units + unit_acc_0);
171 break;
172
173 case gpir_codegen_src_p1_acc_1:
174 printf("^%d", cur_dest_index - 1 * num_units + unit_acc_1);
175 break;
176
177 case gpir_codegen_src_p1_mul_0:
178 printf("^%d", cur_dest_index - 1 * num_units + unit_mul_0);
179 break;
180
181 case gpir_codegen_src_p1_mul_1:
182 printf("^%d", cur_dest_index - 1 * num_units + unit_mul_1);
183 break;
184
185 case gpir_codegen_src_p1_pass:
186 printf("^%d", cur_dest_index - 1 * num_units + unit_pass);
187 break;
188
189 case gpir_codegen_src_unused:
190 printf("unused");
191 break;
192
193 case gpir_codegen_src_p1_complex: /* Also ident */
194 switch (unit) {
195 case unit_acc_0:
196 case unit_acc_1:
197 if (unit_src_num == 1) {
198 printf("0");
199 return;
200 }
201 break;
202 case unit_mul_0:
203 case unit_mul_1:
204 if (unit_src_num == 1) {
205 printf("1");
206 return;
207 }
208 break;
209 default:
210 break;
211 }
212 printf("^%d", cur_dest_index - 1 * num_units + unit_complex);
213 break;
214
215 case gpir_codegen_src_p2_pass:
216 printf("^%d", cur_dest_index - 2 * num_units + unit_pass);
217 break;
218
219 case gpir_codegen_src_p2_acc_0:
220 printf("^%d", cur_dest_index - 2 * num_units + unit_acc_0);
221 break;
222
223 case gpir_codegen_src_p2_acc_1:
224 printf("^%d", cur_dest_index - 2 * num_units + unit_acc_1);
225 break;
226
227 case gpir_codegen_src_p2_mul_0:
228 printf("^%d", cur_dest_index - 2 * num_units + unit_mul_0);
229 break;
230
231 case gpir_codegen_src_p2_mul_1:
232 printf("^%d", cur_dest_index - 2 * num_units + unit_mul_1);
233 break;
234
235 case gpir_codegen_src_p1_attrib_x:
236 case gpir_codegen_src_p1_attrib_y:
237 case gpir_codegen_src_p1_attrib_z:
238 case gpir_codegen_src_p1_attrib_w:
239 printf("%c%d.%c", prev_instr->register0_attribute ? 'a' : '$',
240 prev_instr->register0_addr,
241 "xyzw"[src - gpir_codegen_src_p1_attrib_x]);
242 break;
243 }
244 }
245
246 static bool
print_mul(gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned cur_dest_index)247 print_mul(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
248 unsigned cur_dest_index)
249 {
250 bool printed = false;
251
252 switch (instr->mul_op) {
253 case gpir_codegen_mul_op_mul:
254 case gpir_codegen_mul_op_complex2:
255 if (instr->mul0_src0 != gpir_codegen_src_unused &&
256 instr->mul0_src1 != gpir_codegen_src_unused) {
257 printed = true;
258 printf("\t");
259 if (instr->mul0_src1 == gpir_codegen_src_ident &&
260 !instr->mul0_neg) {
261 printf("mov.m0 ");
262 print_dest(instr, unit_mul_0, cur_dest_index);
263 printf(" ");
264 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
265 cur_dest_index);
266 } else {
267 if (instr->mul_op == gpir_codegen_mul_op_complex2)
268 printf("complex2.m0 ");
269 else
270 printf("mul.m0 ");
271
272 print_dest(instr, unit_mul_0, cur_dest_index);
273 printf(" ");
274 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
275 cur_dest_index);
276 printf(" ");
277 if (instr->mul0_neg)
278 printf("-");
279 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
280 cur_dest_index);
281 }
282
283 printf("\n");
284 }
285
286 if (instr->mul1_src0 != gpir_codegen_src_unused &&
287 instr->mul1_src1 != gpir_codegen_src_unused) {
288 printed = true;
289 printf("\t");
290 if (instr->mul1_src1 == gpir_codegen_src_ident &&
291 !instr->mul1_neg) {
292 printf("mov.m1 ");
293 print_dest(instr, unit_mul_1, cur_dest_index);
294 printf(" ");
295 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
296 cur_dest_index);
297 } else {
298 printf("mul.m1 ");
299 print_dest(instr, unit_mul_1, cur_dest_index);
300 printf(" ");
301 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
302 cur_dest_index);
303 printf(" ");
304 if (instr->mul1_neg)
305 printf("-");
306 print_src(instr->mul1_src1, unit_mul_0, 1, instr, prev_instr,
307 cur_dest_index);
308 }
309 printf("\n");
310 }
311
312 break;
313 case gpir_codegen_mul_op_complex1:
314 printed = true;
315 printf("\tcomplex1.m01 ");
316 print_dest(instr, unit_mul_0, cur_dest_index);
317 printf(" ");
318 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
319 cur_dest_index);
320 printf(" ");
321 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
322 cur_dest_index);
323 printf(" ");
324 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
325 cur_dest_index);
326 printf(" ");
327 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
328 cur_dest_index);
329 printf("\n");
330 break;
331
332 case gpir_codegen_mul_op_select:
333 printed = true;
334 printf("\tsel.m01 ");
335 print_dest(instr, unit_mul_0, cur_dest_index);
336 printf(" ");
337 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
338 cur_dest_index);
339 printf(" ");
340 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
341 cur_dest_index);
342 printf(" ");
343 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
344 cur_dest_index);
345 printf("\n");
346 break;
347
348 default:
349 printed = true;
350 printf("\tunknown%u.m01 ", instr->mul_op);
351 print_dest(instr, unit_mul_0, cur_dest_index);
352 printf(" ");
353 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
354 cur_dest_index);
355 printf(" ");
356 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
357 cur_dest_index);
358 printf(" ");
359 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
360 cur_dest_index);
361 printf(" ");
362 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
363 cur_dest_index);
364 printf("\n");
365 break;
366 }
367
368 return printed;
369 }
370
371 typedef struct {
372 const char *name;
373 unsigned srcs;
374 } acc_op_info;
375
376 #define CASE(_name, _srcs) \
377 [gpir_codegen_acc_op_##_name] = { \
378 .name = #_name, \
379 .srcs = _srcs \
380 }
381
382 static const acc_op_info acc_op_infos[8] = {
383 CASE(add, 2),
384 CASE(floor, 1),
385 CASE(sign, 1),
386 CASE(ge, 2),
387 CASE(lt, 2),
388 CASE(min, 2),
389 CASE(max, 2),
390 };
391
392 #undef CASE
393
394 static bool
print_acc(gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned cur_dest_index)395 print_acc(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
396 unsigned cur_dest_index)
397 {
398 bool printed = false;
399 const acc_op_info op = acc_op_infos[instr->acc_op];
400
401 if (instr->acc0_src0 != gpir_codegen_src_unused) {
402 printed = true;
403 printf("\t");
404 acc_op_info acc0_op = op;
405 if (instr->acc0_src1 == gpir_codegen_src_ident &&
406 instr->acc0_src1_neg) {
407 /* add x, -0 -> mov x */
408 acc0_op.name = "mov";
409 acc0_op.srcs = 1;
410 }
411
412 if (acc0_op.name)
413 printf("%s.a0 ", acc0_op.name);
414 else
415 printf("op%u.a0 ", instr->acc_op);
416
417 print_dest(instr, unit_acc_0, cur_dest_index);
418 printf(" ");
419 if (instr->acc0_src0_neg)
420 printf("-");
421 print_src(instr->acc0_src0, unit_acc_0, 0, instr, prev_instr,
422 cur_dest_index);
423 if (acc0_op.srcs > 1) {
424 printf(" ");
425 if (instr->acc0_src1_neg)
426 printf("-");
427 print_src(instr->acc0_src1, unit_acc_0, 1, instr, prev_instr,
428 cur_dest_index);
429 }
430
431 printf("\n");
432 }
433
434 if (instr->acc1_src0 != gpir_codegen_src_unused) {
435 printed = true;
436 printf("\t");
437 acc_op_info acc1_op = op;
438 if (instr->acc1_src1 == gpir_codegen_src_ident &&
439 instr->acc1_src1_neg) {
440 /* add x, -0 -> mov x */
441 acc1_op.name = "mov";
442 acc1_op.srcs = 1;
443 }
444
445 if (acc1_op.name)
446 printf("%s.a1 ", acc1_op.name);
447 else
448 printf("op%u.a1 ", instr->acc_op);
449
450 print_dest(instr, unit_acc_1, cur_dest_index);
451 printf(" ");
452 if (instr->acc1_src0_neg)
453 printf("-");
454 print_src(instr->acc1_src0, unit_acc_1, 0, instr, prev_instr,
455 cur_dest_index);
456 if (acc1_op.srcs > 1) {
457 printf(" ");
458 if (instr->acc1_src1_neg)
459 printf("-");
460 print_src(instr->acc1_src1, unit_acc_1, 1, instr, prev_instr,
461 cur_dest_index);
462 }
463
464 printf("\n");
465 }
466
467 return printed;
468 }
469
470 static bool
print_pass(gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned cur_dest_index)471 print_pass(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
472 unsigned cur_dest_index)
473 {
474 if (instr->pass_src == gpir_codegen_src_unused)
475 return false;
476
477 printf("\t");
478
479 switch (instr->pass_op) {
480 case gpir_codegen_pass_op_pass:
481 printf("mov.p ");
482 break;
483 case gpir_codegen_pass_op_preexp2:
484 printf("preexp2.p ");
485 break;
486 case gpir_codegen_pass_op_postlog2:
487 printf("postlog2.p ");
488 break;
489 case gpir_codegen_pass_op_clamp:
490 printf("clamp.p ");
491 break;
492 default:
493 printf("unk%u.p ", instr->pass_op);
494 }
495
496 print_dest(instr, unit_pass, cur_dest_index);
497 printf(" ");
498 print_src(instr->pass_src, unit_pass, 0, instr, prev_instr,
499 cur_dest_index);
500
501 if (instr->pass_op == gpir_codegen_pass_op_clamp) {
502 printf(" ");
503 print_src(gpir_codegen_src_load_x, unit_pass, 1, instr, prev_instr,
504 cur_dest_index);
505 printf(" ");
506 print_src(gpir_codegen_src_load_y, unit_pass, 2, instr, prev_instr,
507 cur_dest_index);
508 }
509
510 printf("\n");
511
512 return true;
513 }
514
515 static bool
print_complex(gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned cur_dest_index)516 print_complex(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
517 unsigned cur_dest_index)
518 {
519 if (instr->complex_src == gpir_codegen_src_unused)
520 return false;
521
522 printf("\t");
523
524 switch (instr->complex_op) {
525 case gpir_codegen_complex_op_nop:
526 return false;
527
528 case gpir_codegen_complex_op_exp2:
529 printf("exp2.c ");
530 break;
531 case gpir_codegen_complex_op_log2:
532 printf("log2.c ");
533 break;
534 case gpir_codegen_complex_op_rsqrt:
535 printf("rsqrt.c ");
536 break;
537 case gpir_codegen_complex_op_rcp:
538 printf("rcp.c ");
539 break;
540 case gpir_codegen_complex_op_pass:
541 case gpir_codegen_complex_op_temp_store_addr:
542 case gpir_codegen_complex_op_temp_load_addr_0:
543 case gpir_codegen_complex_op_temp_load_addr_1:
544 case gpir_codegen_complex_op_temp_load_addr_2:
545 printf("mov.c ");
546 break;
547 default:
548 printf("unk%u.c ", instr->complex_op);
549 }
550
551 print_dest(instr, unit_complex, cur_dest_index);
552 printf(" ");
553 print_src(instr->complex_src, unit_complex, 0, instr, prev_instr,
554 cur_dest_index);
555 printf("\n");
556
557 return true;
558 }
559
560 static void
print_instr(gpir_codegen_instr * instr,gpir_codegen_instr * prev_instr,unsigned instr_number,unsigned cur_dest_index)561 print_instr(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
562 unsigned instr_number, unsigned cur_dest_index)
563 {
564 bool printed = false;
565 printf("%03d:", instr_number);
566 printed |= print_acc(instr, prev_instr, cur_dest_index);
567 printed |= print_mul(instr, prev_instr, cur_dest_index);
568 printed |= print_complex(instr, prev_instr, cur_dest_index);
569 printed |= print_pass(instr, prev_instr, cur_dest_index);
570
571 if (instr->branch) {
572 printed = true;
573 /* The branch condition is taken from the current pass unit result */
574 printf("\tbranch ^%d %03d\n", cur_dest_index + unit_pass,
575 instr->branch_target + (instr->branch_target_lo ? 0 : 0x100));
576 }
577
578 if (instr->unknown_1 != 0) {
579 printed = true;
580 printf("\tunknown_1 %u\n", instr->unknown_1);
581 }
582
583 if (!printed)
584 printf("\tnop\n");
585 }
586
587 void
gpir_disassemble_program(gpir_codegen_instr * code,unsigned num_instr)588 gpir_disassemble_program(gpir_codegen_instr *code, unsigned num_instr)
589 {
590 printf("=======disassembly:=======\n");
591
592 unsigned cur_dest_index = 0;
593 unsigned cur_instr = 0;
594 for (gpir_codegen_instr *instr = code; cur_instr < num_instr;
595 instr++, cur_instr++, cur_dest_index += num_units) {
596 print_instr(instr, instr - 1, cur_instr, cur_dest_index);
597 }
598 }
599
600