• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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