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