1/*
2 * Copyright (c) 2017 Lima Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#include "util/ralloc.h"
26
27#include "gpir.h"
28#include "codegen.h"
29#include "lima_context.h"
30
31static gpir_codegen_src gpir_get_alu_input(gpir_node *parent, gpir_node *child)
32{
33   static const int slot_to_src[GPIR_INSTR_SLOT_NUM][3] = {
34      [GPIR_INSTR_SLOT_MUL0] = {
35         gpir_codegen_src_unused, gpir_codegen_src_p1_mul_0, gpir_codegen_src_p2_mul_0 },
36      [GPIR_INSTR_SLOT_MUL1] = {
37         gpir_codegen_src_unused, gpir_codegen_src_p1_mul_1, gpir_codegen_src_p2_mul_1 },
38
39      [GPIR_INSTR_SLOT_ADD0] = {
40         gpir_codegen_src_unused, gpir_codegen_src_p1_acc_0, gpir_codegen_src_p2_acc_0 },
41      [GPIR_INSTR_SLOT_ADD1] = {
42         gpir_codegen_src_unused, gpir_codegen_src_p1_acc_1, gpir_codegen_src_p2_acc_1 },
43
44      [GPIR_INSTR_SLOT_COMPLEX] = {
45         gpir_codegen_src_unused, gpir_codegen_src_p1_complex, gpir_codegen_src_unused },
46      [GPIR_INSTR_SLOT_PASS] = {
47         gpir_codegen_src_unused, gpir_codegen_src_p1_pass, gpir_codegen_src_p2_pass },
48
49      [GPIR_INSTR_SLOT_REG0_LOAD0] = {
50         gpir_codegen_src_attrib_x, gpir_codegen_src_p1_attrib_x, gpir_codegen_src_unused },
51      [GPIR_INSTR_SLOT_REG0_LOAD1] = {
52         gpir_codegen_src_attrib_y, gpir_codegen_src_p1_attrib_y, gpir_codegen_src_unused },
53      [GPIR_INSTR_SLOT_REG0_LOAD2] = {
54         gpir_codegen_src_attrib_z, gpir_codegen_src_p1_attrib_z, gpir_codegen_src_unused },
55      [GPIR_INSTR_SLOT_REG0_LOAD3] = {
56         gpir_codegen_src_attrib_w, gpir_codegen_src_p1_attrib_w, gpir_codegen_src_unused },
57
58      [GPIR_INSTR_SLOT_REG1_LOAD0] = {
59         gpir_codegen_src_register_x, gpir_codegen_src_unused, gpir_codegen_src_unused},
60      [GPIR_INSTR_SLOT_REG1_LOAD1] = {
61         gpir_codegen_src_register_y, gpir_codegen_src_unused, gpir_codegen_src_unused},
62      [GPIR_INSTR_SLOT_REG1_LOAD2] = {
63         gpir_codegen_src_register_z, gpir_codegen_src_unused, gpir_codegen_src_unused},
64      [GPIR_INSTR_SLOT_REG1_LOAD3] = {
65         gpir_codegen_src_register_w, gpir_codegen_src_unused, gpir_codegen_src_unused},
66
67      [GPIR_INSTR_SLOT_MEM_LOAD0] = {
68         gpir_codegen_src_load_x, gpir_codegen_src_unused, gpir_codegen_src_unused },
69      [GPIR_INSTR_SLOT_MEM_LOAD1] = {
70         gpir_codegen_src_load_y, gpir_codegen_src_unused, gpir_codegen_src_unused },
71      [GPIR_INSTR_SLOT_MEM_LOAD2] = {
72         gpir_codegen_src_load_z, gpir_codegen_src_unused, gpir_codegen_src_unused },
73      [GPIR_INSTR_SLOT_MEM_LOAD3] = {
74         gpir_codegen_src_load_w, gpir_codegen_src_unused, gpir_codegen_src_unused },
75   };
76
77   int diff = child->sched.instr->index - parent->sched.instr->index;
78   assert(diff < 3);
79   assert(diff >= 0);
80
81   int src = slot_to_src[child->sched.pos][diff];
82   assert(src != gpir_codegen_src_unused);
83   return src;
84}
85
86static void gpir_codegen_mul0_slot(gpir_codegen_instr *code, gpir_instr *instr)
87{
88   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_MUL0];
89
90   if (!node) {
91      code->mul0_src0 = gpir_codegen_src_unused;
92      code->mul0_src1 = gpir_codegen_src_unused;
93      return;
94   }
95
96   gpir_alu_node *alu = gpir_node_to_alu(node);
97
98   switch (node->op) {
99   case gpir_op_mul:
100      code->mul0_src0 = gpir_get_alu_input(node, alu->children[0]);
101      code->mul0_src1 = gpir_get_alu_input(node, alu->children[1]);
102      if (code->mul0_src1 == gpir_codegen_src_p1_complex) {
103         /* Will get confused with gpir_codegen_src_ident, so need to swap inputs */
104         code->mul0_src1 = code->mul0_src0;
105         code->mul0_src0 = gpir_codegen_src_p1_complex;
106      }
107
108      code->mul0_neg = alu->dest_negate;
109      if (alu->children_negate[0])
110         code->mul0_neg = !code->mul0_neg;
111      if (alu->children_negate[1])
112         code->mul0_neg = !code->mul0_neg;
113      break;
114
115   case gpir_op_neg:
116      code->mul0_neg = true;
117      FALLTHROUGH;
118   case gpir_op_mov:
119      code->mul0_src0 = gpir_get_alu_input(node, alu->children[0]);
120      code->mul0_src1 = gpir_codegen_src_ident;
121      break;
122
123   case gpir_op_complex1:
124      code->mul0_src0 = gpir_get_alu_input(node, alu->children[0]);
125      code->mul0_src1 = gpir_get_alu_input(node, alu->children[1]);
126      code->mul_op = gpir_codegen_mul_op_complex1;
127      break;
128
129   case gpir_op_complex2:
130      code->mul0_src0 = gpir_get_alu_input(node, alu->children[0]);
131      code->mul0_src1 = code->mul0_src0;
132      code->mul_op = gpir_codegen_mul_op_complex2;
133      break;
134
135   case gpir_op_select:
136      code->mul0_src0 = gpir_get_alu_input(node, alu->children[2]);
137      code->mul0_src1 = gpir_get_alu_input(node, alu->children[0]);
138      code->mul_op = gpir_codegen_mul_op_select;
139      break;
140
141   default:
142      assert(0);
143   }
144}
145
146static void gpir_codegen_mul1_slot(gpir_codegen_instr *code, gpir_instr *instr)
147{
148   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_MUL1];
149
150   if (!node) {
151      code->mul1_src0 = gpir_codegen_src_unused;
152      code->mul1_src1 = gpir_codegen_src_unused;
153      return;
154   }
155
156   gpir_alu_node *alu = gpir_node_to_alu(node);
157
158   switch (node->op) {
159   case gpir_op_mul:
160      code->mul1_src0 = gpir_get_alu_input(node, alu->children[0]);
161      code->mul1_src1 = gpir_get_alu_input(node, alu->children[1]);
162      if (code->mul1_src1 == gpir_codegen_src_p1_complex) {
163         /* Will get confused with gpir_codegen_src_ident, so need to swap inputs */
164         code->mul1_src1 = code->mul1_src0;
165         code->mul1_src0 = gpir_codegen_src_p1_complex;
166      }
167
168      code->mul1_neg = alu->dest_negate;
169      if (alu->children_negate[0])
170         code->mul1_neg = !code->mul1_neg;
171      if (alu->children_negate[1])
172         code->mul1_neg = !code->mul1_neg;
173      break;
174
175   case gpir_op_neg:
176      code->mul1_neg = true;
177      FALLTHROUGH;
178   case gpir_op_mov:
179      code->mul1_src0 = gpir_get_alu_input(node, alu->children[0]);
180      code->mul1_src1 = gpir_codegen_src_ident;
181      break;
182
183   case gpir_op_complex1:
184      code->mul1_src0 = gpir_get_alu_input(node, alu->children[0]);
185      code->mul1_src1 = gpir_get_alu_input(node, alu->children[2]);
186      break;
187
188   case gpir_op_select:
189      code->mul1_src0 = gpir_get_alu_input(node, alu->children[1]);
190      code->mul1_src1 = gpir_codegen_src_unused;
191      break;
192
193   default:
194      assert(0);
195   }
196}
197
198static void gpir_codegen_add0_slot(gpir_codegen_instr *code, gpir_instr *instr)
199{
200   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_ADD0];
201
202   if (!node) {
203      code->acc0_src0 = gpir_codegen_src_unused;
204      code->acc0_src1 = gpir_codegen_src_unused;
205      return;
206   }
207
208   gpir_alu_node *alu = gpir_node_to_alu(node);
209
210   switch (node->op) {
211   case gpir_op_add:
212   case gpir_op_min:
213   case gpir_op_max:
214   case gpir_op_lt:
215   case gpir_op_ge:
216      code->acc0_src0 = gpir_get_alu_input(node, alu->children[0]);
217      code->acc0_src1 = gpir_get_alu_input(node, alu->children[1]);
218
219      code->acc0_src0_neg = alu->children_negate[0];
220      code->acc0_src1_neg = alu->children_negate[1];
221
222      switch (node->op) {
223      case gpir_op_add:
224         code->acc_op = gpir_codegen_acc_op_add;
225         if (code->acc0_src1 == gpir_codegen_src_p1_complex) {
226            code->acc0_src1 = code->acc0_src0;
227            code->acc0_src0 = gpir_codegen_src_p1_complex;
228
229            bool tmp = code->acc0_src0_neg;
230            code->acc0_src0_neg = code->acc0_src1_neg;
231            code->acc0_src1_neg = tmp;
232         }
233         break;
234      case gpir_op_min:
235         code->acc_op = gpir_codegen_acc_op_min;
236         break;
237      case gpir_op_max:
238         code->acc_op = gpir_codegen_acc_op_max;
239         break;
240      case gpir_op_lt:
241         code->acc_op = gpir_codegen_acc_op_lt;
242         break;
243      case gpir_op_ge:
244         code->acc_op = gpir_codegen_acc_op_ge;
245         break;
246      default:
247         assert(0);
248      }
249
250      break;
251
252   case gpir_op_floor:
253   case gpir_op_sign:
254      code->acc0_src0 = gpir_get_alu_input(node, alu->children[0]);
255      code->acc0_src0_neg = alu->children_negate[0];
256      switch (node->op) {
257      case gpir_op_floor:
258         code->acc_op = gpir_codegen_acc_op_floor;
259         break;
260      case gpir_op_sign:
261         code->acc_op = gpir_codegen_acc_op_sign;
262         break;
263      default:
264         assert(0);
265      }
266      break;
267
268   case gpir_op_neg:
269      code->acc0_src0_neg = true;
270      FALLTHROUGH;
271   case gpir_op_mov:
272      code->acc_op = gpir_codegen_acc_op_add;
273      code->acc0_src0 = gpir_get_alu_input(node, alu->children[0]);
274      code->acc0_src1 = gpir_codegen_src_ident;
275      code->acc0_src1_neg = true;
276      break;
277
278   default:
279      assert(0);
280   }
281}
282
283static void gpir_codegen_add1_slot(gpir_codegen_instr *code, gpir_instr *instr)
284{
285   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_ADD1];
286
287   if (!node) {
288      code->acc1_src0 = gpir_codegen_src_unused;
289      code->acc1_src1 = gpir_codegen_src_unused;
290      return;
291   }
292
293   gpir_alu_node *alu = gpir_node_to_alu(node);
294
295   switch (node->op) {
296   case gpir_op_add:
297   case gpir_op_min:
298   case gpir_op_max:
299   case gpir_op_lt:
300   case gpir_op_ge:
301      code->acc1_src0 = gpir_get_alu_input(node, alu->children[0]);
302      code->acc1_src1 = gpir_get_alu_input(node, alu->children[1]);
303
304      code->acc1_src0_neg = alu->children_negate[0];
305      code->acc1_src1_neg = alu->children_negate[1];
306
307      switch (node->op) {
308      case gpir_op_add:
309         code->acc_op = gpir_codegen_acc_op_add;
310         if (code->acc1_src1 == gpir_codegen_src_p1_complex) {
311            code->acc1_src1 = code->acc1_src0;
312            code->acc1_src0 = gpir_codegen_src_p1_complex;
313
314            bool tmp = code->acc1_src0_neg;
315            code->acc1_src0_neg = code->acc1_src1_neg;
316            code->acc1_src1_neg = tmp;
317         }
318         break;
319      case gpir_op_min:
320         code->acc_op = gpir_codegen_acc_op_min;
321         break;
322      case gpir_op_max:
323         code->acc_op = gpir_codegen_acc_op_max;
324         break;
325      case gpir_op_lt:
326         code->acc_op = gpir_codegen_acc_op_lt;
327         break;
328      case gpir_op_ge:
329         code->acc_op = gpir_codegen_acc_op_ge;
330         break;
331      default:
332         assert(0);
333      }
334
335      break;
336
337   case gpir_op_floor:
338   case gpir_op_sign:
339      code->acc1_src0 = gpir_get_alu_input(node, alu->children[0]);
340      code->acc1_src0_neg = alu->children_negate[0];
341      switch (node->op) {
342      case gpir_op_floor:
343         code->acc_op = gpir_codegen_acc_op_floor;
344         break;
345      case gpir_op_sign:
346         code->acc_op = gpir_codegen_acc_op_sign;
347         break;
348      default:
349         assert(0);
350      }
351      break;
352
353   case gpir_op_neg:
354      code->acc1_src0_neg = true;
355      FALLTHROUGH;
356   case gpir_op_mov:
357      code->acc_op = gpir_codegen_acc_op_add;
358      code->acc1_src0 = gpir_get_alu_input(node, alu->children[0]);
359      code->acc1_src1 = gpir_codegen_src_ident;
360      code->acc1_src1_neg = true;
361      break;
362
363   default:
364      assert(0);
365   }
366}
367
368static void gpir_codegen_complex_slot(gpir_codegen_instr *code, gpir_instr *instr)
369{
370   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_COMPLEX];
371
372   if (!node) {
373      code->complex_src = gpir_codegen_src_unused;
374      return;
375   }
376
377   switch (node->op) {
378   case gpir_op_mov:
379   case gpir_op_rcp_impl:
380   case gpir_op_rsqrt_impl:
381   case gpir_op_exp2_impl:
382   case gpir_op_log2_impl:
383   {
384      gpir_alu_node *alu = gpir_node_to_alu(node);
385      code->complex_src = gpir_get_alu_input(node, alu->children[0]);
386      break;
387   }
388   default:
389      assert(0);
390   }
391
392   switch (node->op) {
393   case gpir_op_mov:
394      code->complex_op = gpir_codegen_complex_op_pass;
395      break;
396   case gpir_op_rcp_impl:
397      code->complex_op = gpir_codegen_complex_op_rcp;
398      break;
399   case gpir_op_rsqrt_impl:
400      code->complex_op = gpir_codegen_complex_op_rsqrt;
401      break;
402   case gpir_op_exp2_impl:
403      code->complex_op = gpir_codegen_complex_op_exp2;
404      break;
405   case gpir_op_log2_impl:
406      code->complex_op = gpir_codegen_complex_op_log2;
407      break;
408   default:
409      assert(0);
410   }
411}
412
413static void gpir_codegen_pass_slot(gpir_codegen_instr *code, gpir_instr *instr)
414{
415   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_PASS];
416
417   if (!node) {
418      code->pass_op = gpir_codegen_pass_op_pass;
419      code->pass_src = gpir_codegen_src_unused;
420      return;
421   }
422
423   if (node->op == gpir_op_branch_cond) {
424      gpir_branch_node *branch = gpir_node_to_branch(node);
425
426      code->pass_op = gpir_codegen_pass_op_pass;
427      code->pass_src = gpir_get_alu_input(node, branch->cond);
428
429      /* Fill out branch information */
430      unsigned offset = branch->dest->instr_offset;
431      assert(offset < 0x200);
432      code->branch = true;
433      code->branch_target = offset & 0xff;
434      code->branch_target_lo = !(offset >> 8);
435      code->unknown_1 = 13;
436      return;
437   }
438
439   gpir_alu_node *alu = gpir_node_to_alu(node);
440   code->pass_src = gpir_get_alu_input(node, alu->children[0]);
441
442   switch (node->op) {
443   case gpir_op_mov:
444      code->pass_op = gpir_codegen_pass_op_pass;
445      break;
446   case gpir_op_preexp2:
447      code->pass_op = gpir_codegen_pass_op_preexp2;
448      break;
449   case gpir_op_postlog2:
450      code->pass_op = gpir_codegen_pass_op_postlog2;
451      break;
452   default:
453      assert(0);
454   }
455
456}
457
458static void gpir_codegen_reg0_slot(gpir_codegen_instr *code, gpir_instr *instr)
459{
460   if (!instr->reg0_use_count)
461      return;
462
463   code->register0_attribute = instr->reg0_is_attr;
464   code->register0_addr = instr->reg0_index;
465}
466
467static void gpir_codegen_reg1_slot(gpir_codegen_instr *code, gpir_instr *instr)
468{
469   if (!instr->reg1_use_count)
470      return;
471
472   code->register1_addr = instr->reg1_index;
473}
474
475static void gpir_codegen_mem_slot(gpir_codegen_instr *code, gpir_instr *instr)
476{
477   if (!instr->mem_use_count) {
478      code->load_offset = gpir_codegen_load_off_none;
479      return;
480   }
481
482   code->load_addr = instr->mem_index;
483   code->load_offset = gpir_codegen_load_off_none;
484}
485
486static gpir_codegen_store_src gpir_get_store_input(gpir_node *node)
487{
488   static int slot_to_src[GPIR_INSTR_SLOT_NUM] = {
489      [GPIR_INSTR_SLOT_MUL0] = gpir_codegen_store_src_mul_0,
490      [GPIR_INSTR_SLOT_MUL1] = gpir_codegen_store_src_mul_1,
491      [GPIR_INSTR_SLOT_ADD0] = gpir_codegen_store_src_acc_0,
492      [GPIR_INSTR_SLOT_ADD1] = gpir_codegen_store_src_acc_1,
493      [GPIR_INSTR_SLOT_COMPLEX] = gpir_codegen_store_src_complex,
494      [GPIR_INSTR_SLOT_PASS] = gpir_codegen_store_src_pass,
495      [GPIR_INSTR_SLOT_REG0_LOAD0...GPIR_INSTR_SLOT_STORE3] = gpir_codegen_store_src_none,
496   };
497
498   gpir_store_node *store = gpir_node_to_store(node);
499   return slot_to_src[store->child->sched.pos];
500}
501
502static void gpir_codegen_store_slot(gpir_codegen_instr *code, gpir_instr *instr)
503{
504
505   gpir_node *node = instr->slots[GPIR_INSTR_SLOT_STORE0];
506   if (node)
507      code->store0_src_x = gpir_get_store_input(node);
508   else
509      code->store0_src_x = gpir_codegen_store_src_none;
510
511   node = instr->slots[GPIR_INSTR_SLOT_STORE1];
512   if (node)
513      code->store0_src_y = gpir_get_store_input(node);
514   else
515      code->store0_src_y = gpir_codegen_store_src_none;
516
517   node = instr->slots[GPIR_INSTR_SLOT_STORE2];
518   if (node)
519      code->store1_src_z = gpir_get_store_input(node);
520   else
521      code->store1_src_z = gpir_codegen_store_src_none;
522
523   node = instr->slots[GPIR_INSTR_SLOT_STORE3];
524   if (node)
525      code->store1_src_w = gpir_get_store_input(node);
526   else
527      code->store1_src_w = gpir_codegen_store_src_none;
528
529   if (instr->store_content[0] == GPIR_INSTR_STORE_TEMP) {
530      code->store0_temporary = true;
531      code->unknown_1 = 12;
532   }
533   else {
534      code->store0_varying = instr->store_content[0] == GPIR_INSTR_STORE_VARYING;
535      code->store0_addr = instr->store_index[0];
536   }
537
538   if (instr->store_content[1] == GPIR_INSTR_STORE_TEMP) {
539      code->store1_temporary = true;
540      code->unknown_1 = 12;
541   }
542   else {
543      code->store1_varying = instr->store_content[1] == GPIR_INSTR_STORE_VARYING;
544      code->store1_addr = instr->store_index[1];
545   }
546}
547
548static void gpir_codegen(gpir_codegen_instr *code, gpir_instr *instr)
549{
550   gpir_codegen_mul0_slot(code, instr);
551   gpir_codegen_mul1_slot(code, instr);
552
553   gpir_codegen_add0_slot(code, instr);
554   gpir_codegen_add1_slot(code, instr);
555
556   gpir_codegen_complex_slot(code, instr);
557   gpir_codegen_pass_slot(code, instr);
558
559   gpir_codegen_reg0_slot(code, instr);
560   gpir_codegen_reg1_slot(code, instr);
561   gpir_codegen_mem_slot(code, instr);
562
563   gpir_codegen_store_slot(code, instr);
564}
565
566static void gpir_codegen_print_prog(gpir_compiler *comp)
567{
568   uint32_t *data = comp->prog->shader;
569   int num_dword_per_instr = sizeof(gpir_codegen_instr) / sizeof(uint32_t);
570
571   for (int i = 0; i < comp->num_instr; i++) {
572      printf("%03d: ", i);
573      for (int j = 0; j < num_dword_per_instr; j++)
574         printf("%08x ", data[i * num_dword_per_instr + j]);
575      printf("\n");
576   }
577}
578
579bool gpir_codegen_prog(gpir_compiler *comp)
580{
581   int num_instr = 0;
582   list_for_each_entry(gpir_block, block, &comp->block_list, list) {
583      block->instr_offset = num_instr;
584      num_instr += list_length(&block->instr_list);
585   }
586
587   assert(num_instr <= 512);
588
589   gpir_codegen_instr *code = rzalloc_array(comp->prog, gpir_codegen_instr, num_instr);
590   if (!code)
591      return false;
592
593   int instr_index = 0;
594   list_for_each_entry(gpir_block, block, &comp->block_list, list) {
595      list_for_each_entry(gpir_instr, instr, &block->instr_list, list) {
596         gpir_codegen(code + instr_index, instr);
597         instr_index++;
598      }
599   }
600
601   for (int i = 0; i < num_instr; i++) {
602      if (code[i].register0_attribute)
603         comp->prog->state.prefetch = i;
604   }
605
606   comp->prog->shader = code;
607   comp->prog->state.shader_size = num_instr * sizeof(gpir_codegen_instr);
608
609   if (lima_debug & LIMA_DEBUG_GP) {
610      gpir_codegen_print_prog(comp);
611      gpir_disassemble_program(code, num_instr, stdout);
612   }
613
614   return true;
615}
616
617static gpir_codegen_acc_op gpir_codegen_get_acc_op(gpir_op op)
618{
619   switch (op) {
620   case gpir_op_add:
621   case gpir_op_neg:
622   case gpir_op_mov:
623      return gpir_codegen_acc_op_add;
624   case gpir_op_min:
625      return gpir_codegen_acc_op_min;
626   case gpir_op_max:
627      return gpir_codegen_acc_op_max;
628   case gpir_op_lt:
629      return gpir_codegen_acc_op_lt;
630   case gpir_op_ge:
631      return gpir_codegen_acc_op_ge;
632   case gpir_op_floor:
633      return gpir_codegen_acc_op_floor;
634   case gpir_op_sign:
635      return gpir_codegen_acc_op_sign;
636   default:
637      assert(0);
638   }
639   return -1;
640}
641
642bool gpir_codegen_acc_same_op(gpir_op op1, gpir_op op2)
643{
644   return gpir_codegen_get_acc_op(op1) == gpir_codegen_get_acc_op(op2);
645}
646