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
30typedef 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
40static 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
49static void
50print_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
117static void
118print_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
246static bool
247print_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
371typedef 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
382static 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
394static bool
395print_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
470static bool
471print_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
515static bool
516print_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
560static void
561print_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
587void
588gpir_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