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,FILE * fp)50 print_dest(gpir_codegen_instr *instr, gp_unit unit, unsigned cur_dest_index, FILE *fp)
51 {
52 fprintf(fp, "^%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 fprintf(fp, "/t[addr0]");
63 } else {
64 if (instr->store0_varying)
65 fprintf(fp, "/v");
66 else
67 fprintf(fp, "/$");
68 fprintf(fp, "%u", instr->store0_addr);
69 }
70
71 fprintf(fp, ".");
72 if (instr->store0_src_x == src)
73 fprintf(fp, "x");
74 if (instr->store0_src_y == src)
75 fprintf(fp, "y");
76 }
77
78 if (instr->store1_src_z == src ||
79 instr->store1_src_w == src) {
80 if (instr->store1_temporary) {
81 fprintf(fp, "/t[addr0]");
82 } else {
83 if (instr->store1_varying)
84 fprintf(fp, "/v");
85 else
86 fprintf(fp, "/$");
87 fprintf(fp, "%u", instr->store1_addr);
88 }
89
90 fprintf(fp, ".");
91 if (instr->store1_src_z == src)
92 fprintf(fp, "z");
93 if (instr->store1_src_w == src)
94 fprintf(fp, "w");
95 }
96
97 if (unit == unit_complex) {
98 switch (instr->complex_op) {
99 case gpir_codegen_complex_op_temp_store_addr:
100 fprintf(fp, "/addr0");
101 break;
102 case gpir_codegen_complex_op_temp_load_addr_0:
103 fprintf(fp, "/addr1");
104 break;
105 case gpir_codegen_complex_op_temp_load_addr_1:
106 fprintf(fp, "/addr2");
107 break;
108 case gpir_codegen_complex_op_temp_load_addr_2:
109 fprintf(fp, "/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,FILE * fp)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, FILE *fp)
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 fprintf(fp, "%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 fprintf(fp, "$%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 fprintf(fp, "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 fprintf(fp, "t[%d", instr->load_addr);
151 switch (instr->load_offset) {
152 case gpir_codegen_load_off_ld_addr_0:
153 fprintf(fp, "+addr1");
154 break;
155 case gpir_codegen_load_off_ld_addr_1:
156 fprintf(fp, "+addr2");
157 break;
158 case gpir_codegen_load_off_ld_addr_2:
159 fprintf(fp, "+addr3");
160 break;
161 case gpir_codegen_load_off_none:
162 break;
163 default:
164 fprintf(fp, "+unk%d", instr->load_offset);
165 }
166 fprintf(fp, "].%c", "xyzw"[src - gpir_codegen_src_load_x]);
167 break;
168
169 case gpir_codegen_src_p1_acc_0:
170 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_acc_0);
171 break;
172
173 case gpir_codegen_src_p1_acc_1:
174 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_acc_1);
175 break;
176
177 case gpir_codegen_src_p1_mul_0:
178 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_mul_0);
179 break;
180
181 case gpir_codegen_src_p1_mul_1:
182 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_mul_1);
183 break;
184
185 case gpir_codegen_src_p1_pass:
186 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_pass);
187 break;
188
189 case gpir_codegen_src_unused:
190 fprintf(fp, "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 fprintf(fp, "0");
199 return;
200 }
201 break;
202 case unit_mul_0:
203 case unit_mul_1:
204 if (unit_src_num == 1) {
205 fprintf(fp, "1");
206 return;
207 }
208 break;
209 default:
210 break;
211 }
212 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_complex);
213 break;
214
215 case gpir_codegen_src_p2_pass:
216 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_pass);
217 break;
218
219 case gpir_codegen_src_p2_acc_0:
220 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_acc_0);
221 break;
222
223 case gpir_codegen_src_p2_acc_1:
224 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_acc_1);
225 break;
226
227 case gpir_codegen_src_p2_mul_0:
228 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_mul_0);
229 break;
230
231 case gpir_codegen_src_p2_mul_1:
232 fprintf(fp, "^%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 fprintf(fp, "%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,FILE * fp)247 print_mul(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
248 unsigned cur_dest_index, FILE *fp)
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 fprintf(fp, "\t");
259 if (instr->mul0_src1 == gpir_codegen_src_ident &&
260 !instr->mul0_neg) {
261 fprintf(fp, "mov.m0 ");
262 print_dest(instr, unit_mul_0, cur_dest_index, fp);
263 fprintf(fp, " ");
264 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
265 cur_dest_index, fp);
266 } else {
267 if (instr->mul_op == gpir_codegen_mul_op_complex2)
268 fprintf(fp, "complex2.m0 ");
269 else
270 fprintf(fp, "mul.m0 ");
271
272 print_dest(instr, unit_mul_0, cur_dest_index, fp);
273 fprintf(fp, " ");
274 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
275 cur_dest_index, fp);
276 fprintf(fp, " ");
277 if (instr->mul0_neg)
278 fprintf(fp, "-");
279 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
280 cur_dest_index, fp);
281 }
282
283 fprintf(fp, "\n");
284 }
285
286 if (instr->mul1_src0 != gpir_codegen_src_unused &&
287 instr->mul1_src1 != gpir_codegen_src_unused) {
288 printed = true;
289 fprintf(fp, "\t");
290 if (instr->mul1_src1 == gpir_codegen_src_ident &&
291 !instr->mul1_neg) {
292 fprintf(fp, "mov.m1 ");
293 print_dest(instr, unit_mul_1, cur_dest_index, fp);
294 fprintf(fp, " ");
295 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
296 cur_dest_index, fp);
297 } else {
298 fprintf(fp, "mul.m1 ");
299 print_dest(instr, unit_mul_1, cur_dest_index, fp);
300 fprintf(fp, " ");
301 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
302 cur_dest_index, fp);
303 fprintf(fp, " ");
304 if (instr->mul1_neg)
305 fprintf(fp, "-");
306 print_src(instr->mul1_src1, unit_mul_0, 1, instr, prev_instr,
307 cur_dest_index, fp);
308 }
309 fprintf(fp, "\n");
310 }
311
312 break;
313 case gpir_codegen_mul_op_complex1:
314 printed = true;
315 fprintf(fp, "\tcomplex1.m01 ");
316 print_dest(instr, unit_mul_0, cur_dest_index, fp);
317 fprintf(fp, " ");
318 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
319 cur_dest_index, fp);
320 fprintf(fp, " ");
321 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
322 cur_dest_index, fp);
323 fprintf(fp, " ");
324 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
325 cur_dest_index, fp);
326 fprintf(fp, " ");
327 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
328 cur_dest_index, fp);
329 fprintf(fp, "\n");
330 break;
331
332 case gpir_codegen_mul_op_select:
333 printed = true;
334 fprintf(fp, "\tsel.m01 ");
335 print_dest(instr, unit_mul_0, cur_dest_index, fp);
336 fprintf(fp, " ");
337 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
338 cur_dest_index, fp);
339 fprintf(fp, " ");
340 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
341 cur_dest_index, fp);
342 fprintf(fp, " ");
343 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
344 cur_dest_index, fp);
345 fprintf(fp, "\n");
346 break;
347
348 default:
349 printed = true;
350 fprintf(fp, "\tunknown%u.m01 ", instr->mul_op);
351 print_dest(instr, unit_mul_0, cur_dest_index, fp);
352 fprintf(fp, " ");
353 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
354 cur_dest_index, fp);
355 fprintf(fp, " ");
356 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
357 cur_dest_index, fp);
358 fprintf(fp, " ");
359 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
360 cur_dest_index, fp);
361 fprintf(fp, " ");
362 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
363 cur_dest_index, fp);
364 fprintf(fp, "\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,FILE * fp)395 print_acc(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
396 unsigned cur_dest_index, FILE *fp)
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 fprintf(fp, "\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 fprintf(fp, "%s.a0 ", acc0_op.name);
414 else
415 fprintf(fp, "op%u.a0 ", instr->acc_op);
416
417 print_dest(instr, unit_acc_0, cur_dest_index, fp);
418 fprintf(fp, " ");
419 if (instr->acc0_src0_neg)
420 fprintf(fp, "-");
421 print_src(instr->acc0_src0, unit_acc_0, 0, instr, prev_instr,
422 cur_dest_index, fp);
423 if (acc0_op.srcs > 1) {
424 fprintf(fp, " ");
425 if (instr->acc0_src1_neg)
426 fprintf(fp, "-");
427 print_src(instr->acc0_src1, unit_acc_0, 1, instr, prev_instr,
428 cur_dest_index, fp);
429 }
430
431 fprintf(fp, "\n");
432 }
433
434 if (instr->acc1_src0 != gpir_codegen_src_unused) {
435 printed = true;
436 fprintf(fp, "\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 fprintf(fp, "%s.a1 ", acc1_op.name);
447 else
448 fprintf(fp, "op%u.a1 ", instr->acc_op);
449
450 print_dest(instr, unit_acc_1, cur_dest_index, fp);
451 fprintf(fp, " ");
452 if (instr->acc1_src0_neg)
453 fprintf(fp, "-");
454 print_src(instr->acc1_src0, unit_acc_1, 0, instr, prev_instr,
455 cur_dest_index, fp);
456 if (acc1_op.srcs > 1) {
457 fprintf(fp, " ");
458 if (instr->acc1_src1_neg)
459 fprintf(fp, "-");
460 print_src(instr->acc1_src1, unit_acc_1, 1, instr, prev_instr,
461 cur_dest_index, fp);
462 }
463
464 fprintf(fp, "\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,FILE * fp)471 print_pass(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
472 unsigned cur_dest_index, FILE *fp)
473 {
474 if (instr->pass_src == gpir_codegen_src_unused)
475 return false;
476
477 fprintf(fp, "\t");
478
479 switch (instr->pass_op) {
480 case gpir_codegen_pass_op_pass:
481 fprintf(fp, "mov.p ");
482 break;
483 case gpir_codegen_pass_op_preexp2:
484 fprintf(fp, "preexp2.p ");
485 break;
486 case gpir_codegen_pass_op_postlog2:
487 fprintf(fp, "postlog2.p ");
488 break;
489 case gpir_codegen_pass_op_clamp:
490 fprintf(fp, "clamp.p ");
491 break;
492 default:
493 fprintf(fp, "unk%u.p ", instr->pass_op);
494 }
495
496 print_dest(instr, unit_pass, cur_dest_index, fp);
497 fprintf(fp, " ");
498 print_src(instr->pass_src, unit_pass, 0, instr, prev_instr,
499 cur_dest_index, fp);
500
501 if (instr->pass_op == gpir_codegen_pass_op_clamp) {
502 fprintf(fp, " ");
503 print_src(gpir_codegen_src_load_x, unit_pass, 1, instr, prev_instr,
504 cur_dest_index, fp);
505 fprintf(fp, " ");
506 print_src(gpir_codegen_src_load_y, unit_pass, 2, instr, prev_instr,
507 cur_dest_index, fp);
508 }
509
510 fprintf(fp, "\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,FILE * fp)516 print_complex(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
517 unsigned cur_dest_index, FILE *fp)
518 {
519 if (instr->complex_src == gpir_codegen_src_unused)
520 return false;
521
522 fprintf(fp, "\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 fprintf(fp, "exp2.c ");
530 break;
531 case gpir_codegen_complex_op_log2:
532 fprintf(fp, "log2.c ");
533 break;
534 case gpir_codegen_complex_op_rsqrt:
535 fprintf(fp, "rsqrt.c ");
536 break;
537 case gpir_codegen_complex_op_rcp:
538 fprintf(fp, "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 fprintf(fp, "mov.c ");
546 break;
547 default:
548 fprintf(fp, "unk%u.c ", instr->complex_op);
549 }
550
551 print_dest(instr, unit_complex, cur_dest_index, fp);
552 fprintf(fp, " ");
553 print_src(instr->complex_src, unit_complex, 0, instr, prev_instr,
554 cur_dest_index, fp);
555 fprintf(fp, "\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,FILE * fp)561 print_instr(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
562 unsigned instr_number, unsigned cur_dest_index, FILE *fp)
563 {
564 bool printed = false;
565 fprintf(fp, "%03d:", instr_number);
566 printed |= print_acc(instr, prev_instr, cur_dest_index, fp);
567 printed |= print_mul(instr, prev_instr, cur_dest_index, fp);
568 printed |= print_complex(instr, prev_instr, cur_dest_index, fp);
569 printed |= print_pass(instr, prev_instr, cur_dest_index, fp);
570
571 if (instr->branch) {
572 printed = true;
573 /* The branch condition is taken from the current pass unit result */
574 fprintf(fp, "\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 fprintf(fp, "\tunknown_1 %u\n", instr->unknown_1);
581 }
582
583 if (!printed)
584 fprintf(fp, "\tnop\n");
585 }
586
587 void
gpir_disassemble_program(gpir_codegen_instr * code,unsigned num_instr,FILE * fp)588 gpir_disassemble_program(gpir_codegen_instr *code, unsigned num_instr, FILE *fp)
589 {
590 unsigned cur_dest_index = 0;
591 unsigned cur_instr = 0;
592 for (gpir_codegen_instr *instr = code; cur_instr < num_instr;
593 instr++, cur_instr++, cur_dest_index += num_units) {
594 print_instr(instr, instr - 1, cur_instr, cur_dest_index, fp);
595 }
596 }
597
598