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)
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
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)
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_attrib_x]);
242      break;
243   }
244}
245
246static void
247print_mul(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
248          unsigned cur_dest_index)
249{
250   switch (instr->mul_op) {
251   case gpir_codegen_mul_op_mul:
252   case gpir_codegen_mul_op_complex2:
253      if (instr->mul0_src0 != gpir_codegen_src_unused &&
254          instr->mul0_src1 != gpir_codegen_src_unused) {
255         if (instr->mul0_src1 == gpir_codegen_src_ident &&
256             !instr->mul0_neg) {
257            printf("mov ");
258            print_dest(instr, unit_mul_0, cur_dest_index);
259            printf(" ");
260            print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
261                      cur_dest_index);
262         } else {
263            if (instr->mul_op == gpir_codegen_mul_op_complex2)
264               printf("complex2 ");
265            else
266               printf("mul ");
267
268            print_dest(instr, unit_mul_0, cur_dest_index);
269            printf(" ");
270            print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
271                      cur_dest_index);
272            printf(" ");
273            if (instr->mul0_neg)
274               printf("-");
275            print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
276                      cur_dest_index);
277         }
278
279         printf(", ");
280      }
281
282      if (instr->mul1_src0 != gpir_codegen_src_unused &&
283          instr->mul1_src1 != gpir_codegen_src_unused) {
284         if (instr->mul1_src1 == gpir_codegen_src_ident &&
285             !instr->mul1_neg) {
286            printf("mov ");
287            print_dest(instr, unit_mul_1, cur_dest_index);
288            printf(" ");
289            print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
290                      cur_dest_index);
291         } else {
292            printf("mul ");
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            printf(" ");
298            if (instr->mul1_neg)
299               printf("-");
300            print_src(instr->mul1_src1, unit_mul_0, 1, instr, prev_instr,
301                      cur_dest_index);
302         }
303      }
304
305      break;
306   case gpir_codegen_mul_op_complex1:
307      printf("complex1 ");
308      print_dest(instr, unit_mul_0, cur_dest_index);
309      printf(" ");
310      print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
311                cur_dest_index);
312      printf(" ");
313      print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
314                cur_dest_index);
315      printf(" ");
316      print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
317                cur_dest_index);
318      printf(" ");
319      print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
320                cur_dest_index);
321      break;
322
323   case gpir_codegen_mul_op_select:
324      printf("sel ");
325      print_dest(instr, unit_mul_0, cur_dest_index);
326      printf(" ");
327      print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
328                cur_dest_index);
329      printf(" ");
330      print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
331                cur_dest_index);
332      printf(" ");
333      print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
334                cur_dest_index);
335      break;
336
337   default:
338      printf("unknown%u ", instr->mul_op);
339      print_dest(instr, unit_mul_0, cur_dest_index);
340      printf(" ");
341      print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr,
342                cur_dest_index);
343      printf(" ");
344      print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr,
345                cur_dest_index);
346      printf(" ");
347      print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr,
348                cur_dest_index);
349      printf(" ");
350      print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr,
351                cur_dest_index);
352      break;
353   }
354
355   printf(", ");
356}
357
358typedef struct {
359   const char *name;
360   unsigned srcs;
361} acc_op_info;
362
363#define CASE(_name, _srcs) \
364   [gpir_codegen_acc_op_##_name] = { \
365      .name = #_name, \
366      .srcs = _srcs \
367   }
368
369static const acc_op_info acc_op_infos[8] = {
370   CASE(add, 2),
371   CASE(floor, 1),
372   CASE(sign, 1),
373   CASE(ge, 2),
374   CASE(lt, 2),
375   CASE(min, 2),
376   CASE(max, 2),
377};
378
379#undef CASE
380
381static void
382print_acc(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
383          unsigned cur_dest_index)
384{
385   const acc_op_info op = acc_op_infos[instr->acc_op];
386
387   if (instr->acc0_src0 != gpir_codegen_src_unused &&
388       instr->acc0_src1 != gpir_codegen_src_unused) {
389      acc_op_info acc0_op = op;
390      if (instr->acc0_src1 == gpir_codegen_src_ident &&
391          instr->acc0_src1_neg) {
392         /* add x, -0 -> mov x */
393         acc0_op.name = "mov";
394         acc0_op.srcs = 1;
395      }
396
397      if (acc0_op.name)
398         printf("%s ", acc0_op.name);
399      else
400         printf("op%u ", instr->acc_op);
401
402      print_dest(instr, unit_acc_0, cur_dest_index);
403      printf(" ");
404      if (instr->acc0_src0_neg)
405         printf("-");
406      print_src(instr->acc0_src0, unit_acc_0, 0, instr, prev_instr,
407                cur_dest_index);
408      if (acc0_op.srcs > 1) {
409         printf(" ");
410         if (instr->acc0_src1_neg)
411            printf("-");
412         print_src(instr->acc0_src1, unit_acc_0, 1, instr, prev_instr,
413                   cur_dest_index);
414      }
415
416      printf(", ");
417   }
418
419   if (instr->acc1_src0 != gpir_codegen_src_unused &&
420       instr->acc1_src1 != gpir_codegen_src_unused) {
421      acc_op_info acc1_op = op;
422      if (instr->acc1_src1 == gpir_codegen_src_ident &&
423          instr->acc1_src1_neg) {
424         /* add x, -0 -> mov x */
425         acc1_op.name = "mov";
426         acc1_op.srcs = 1;
427      }
428
429      if (acc1_op.name)
430         printf("%s ", acc1_op.name);
431      else
432         printf("op%u ", instr->acc_op);
433
434      print_dest(instr, unit_acc_1, cur_dest_index);
435      printf(" ");
436      if (instr->acc1_src0_neg)
437         printf("-");
438      print_src(instr->acc1_src0, unit_acc_1, 0, instr, prev_instr,
439                cur_dest_index);
440      if (acc1_op.srcs > 1) {
441         printf(" ");
442         if (instr->acc1_src1_neg)
443            printf("-");
444         print_src(instr->acc1_src1, unit_acc_1, 1, instr, prev_instr,
445                   cur_dest_index);
446      }
447
448      printf(", ");
449   }
450}
451
452static void
453print_pass(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
454           unsigned cur_dest_index)
455{
456   if (instr->pass_src == gpir_codegen_src_unused)
457      return;
458
459   switch (instr->pass_op) {
460   case gpir_codegen_pass_op_pass:
461      printf("mov ");
462      break;
463   case gpir_codegen_pass_op_preexp2:
464      printf("preexp2 ");
465      break;
466   case gpir_codegen_pass_op_postlog2:
467      printf("postlog2 ");
468      break;
469   case gpir_codegen_pass_op_clamp:
470      printf("clamp ");
471      break;
472   default:
473      printf("unk%u ", instr->pass_op);
474   }
475
476   print_dest(instr, unit_pass, cur_dest_index);
477   printf(" ");
478   print_src(instr->pass_src, unit_pass, 0, instr, prev_instr,
479             cur_dest_index);
480
481   if (instr->pass_op == gpir_codegen_pass_op_clamp) {
482      printf(" ");
483      print_src(gpir_codegen_src_load_x, unit_pass, 1, instr, prev_instr,
484                cur_dest_index);
485      printf(" ");
486      print_src(gpir_codegen_src_load_y, unit_pass, 2, instr, prev_instr,
487                cur_dest_index);
488   }
489
490   printf(", ");
491}
492
493static void
494print_complex(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
495              unsigned cur_dest_index)
496{
497   if (instr->complex_src == gpir_codegen_src_unused)
498      return;
499
500   switch (instr->complex_op) {
501   case gpir_codegen_complex_op_nop:
502      return;
503
504   case gpir_codegen_complex_op_exp2:
505      printf("exp2 ");
506      break;
507   case gpir_codegen_complex_op_log2:
508      printf("log2 ");
509      break;
510   case gpir_codegen_complex_op_rsqrt:
511      printf("rsqrt ");
512      break;
513   case gpir_codegen_complex_op_rcp:
514      printf("rcp ");
515      break;
516   case gpir_codegen_complex_op_pass:
517   case gpir_codegen_complex_op_temp_store_addr:
518   case gpir_codegen_complex_op_temp_load_addr_0:
519   case gpir_codegen_complex_op_temp_load_addr_1:
520   case gpir_codegen_complex_op_temp_load_addr_2:
521      printf("mov ");
522      break;
523   default:
524      printf("unk%u ", instr->complex_op);
525   }
526
527   print_dest(instr, unit_complex, cur_dest_index);
528   printf(" ");
529   print_src(instr->complex_src, unit_complex, 0, instr, prev_instr,
530             cur_dest_index);
531   printf(", ");
532}
533
534static void
535print_instr(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr,
536            unsigned instr_number, unsigned cur_dest_index)
537{
538   printf("%03d: ", instr_number);
539   print_mul(instr, prev_instr, cur_dest_index);
540   print_acc(instr, prev_instr, cur_dest_index);
541   print_complex(instr, prev_instr, cur_dest_index);
542   print_pass(instr, prev_instr, cur_dest_index);
543
544   if (instr->branch) {
545      /* The branch condition is taken from the current pass unit result */
546      printf("branch ^%d %03d, ", cur_dest_index + unit_pass,
547             instr->branch_target + (instr->branch_target_lo ? 0 : 0x100));
548   }
549
550   if (instr->unknown_1 != 0)
551      printf("unknown_1 %u", instr->unknown_1);
552
553   printf("\n");
554}
555
556void
557gpir_disassemble_program(gpir_codegen_instr *code, unsigned num_instr)
558{
559   printf("=======disassembly:=======\n");
560
561   unsigned cur_dest_index = 0;
562   unsigned cur_instr = 0;
563   for (gpir_codegen_instr *instr = code; cur_instr < num_instr;
564        instr++, cur_instr++, cur_dest_index += num_units) {
565      print_instr(instr, instr - 1, cur_instr, cur_dest_index);
566   }
567}
568
569