1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (c) 2017 Lima Project
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
12bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
13bf215546Sopenharmony_ci * of the Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include "util/ralloc.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "ppir.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_cippir_instr *ppir_instr_create(ppir_block *block)
30bf215546Sopenharmony_ci{
31bf215546Sopenharmony_ci   ppir_instr *instr = rzalloc(block, ppir_instr);
32bf215546Sopenharmony_ci   if (!instr)
33bf215546Sopenharmony_ci      return NULL;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci   list_inithead(&instr->succ_list);
36bf215546Sopenharmony_ci   list_inithead(&instr->pred_list);
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci   instr->index = block->comp->cur_instr_index++;
39bf215546Sopenharmony_ci   instr->reg_pressure = -1;
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci   list_addtail(&instr->list, &block->instr_list);
42bf215546Sopenharmony_ci   return instr;
43bf215546Sopenharmony_ci}
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_civoid ppir_instr_add_dep(ppir_instr *succ, ppir_instr *pred)
46bf215546Sopenharmony_ci{
47bf215546Sopenharmony_ci   /* don't add duplicated instr */
48bf215546Sopenharmony_ci   ppir_instr_foreach_pred(succ, dep) {
49bf215546Sopenharmony_ci      if (pred == dep->pred)
50bf215546Sopenharmony_ci         return;
51bf215546Sopenharmony_ci   }
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   ppir_dep *dep = ralloc(succ, ppir_dep);
54bf215546Sopenharmony_ci   dep->pred = pred;
55bf215546Sopenharmony_ci   dep->succ = succ;
56bf215546Sopenharmony_ci   list_addtail(&dep->pred_link, &succ->pred_list);
57bf215546Sopenharmony_ci   list_addtail(&dep->succ_link, &pred->succ_list);
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_civoid ppir_instr_insert_mul_node(ppir_node *add, ppir_node *mul)
61bf215546Sopenharmony_ci{
62bf215546Sopenharmony_ci   ppir_instr *instr = add->instr;
63bf215546Sopenharmony_ci   int pos = mul->instr_pos;
64bf215546Sopenharmony_ci   int *slots = ppir_op_infos[mul->op].slots;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
67bf215546Sopenharmony_ci      /* possible to insert at required place */
68bf215546Sopenharmony_ci      if (slots[i] == pos) {
69bf215546Sopenharmony_ci         if (!instr->slots[pos]) {
70bf215546Sopenharmony_ci            ppir_alu_node *add_alu = ppir_node_to_alu(add);
71bf215546Sopenharmony_ci            ppir_alu_node *mul_alu = ppir_node_to_alu(mul);
72bf215546Sopenharmony_ci            ppir_dest *dest = &mul_alu->dest;
73bf215546Sopenharmony_ci            int pipeline = pos == PPIR_INSTR_SLOT_ALU_VEC_MUL ?
74bf215546Sopenharmony_ci               ppir_pipeline_reg_vmul : ppir_pipeline_reg_fmul;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci            /* ^vmul/^fmul can't be used as last arg */
77bf215546Sopenharmony_ci            if (add_alu->num_src > 1) {
78bf215546Sopenharmony_ci               ppir_src *last_src = add_alu->src + add_alu->num_src - 1;
79bf215546Sopenharmony_ci               if (ppir_node_target_equal(last_src, dest))
80bf215546Sopenharmony_ci                  return;
81bf215546Sopenharmony_ci            }
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci            /* update add node src to use pipeline reg */
84bf215546Sopenharmony_ci            ppir_src *src = add_alu->src;
85bf215546Sopenharmony_ci            if (add_alu->num_src == 3) {
86bf215546Sopenharmony_ci               if (ppir_node_target_equal(src, dest)) {
87bf215546Sopenharmony_ci                  src->type = ppir_target_pipeline;
88bf215546Sopenharmony_ci                  src->pipeline = pipeline;
89bf215546Sopenharmony_ci               }
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci               if (ppir_node_target_equal(++src, dest)) {
92bf215546Sopenharmony_ci                  src->type = ppir_target_pipeline;
93bf215546Sopenharmony_ci                  src->pipeline = pipeline;
94bf215546Sopenharmony_ci               }
95bf215546Sopenharmony_ci            }
96bf215546Sopenharmony_ci            else {
97bf215546Sopenharmony_ci               assert(ppir_node_target_equal(src, dest));
98bf215546Sopenharmony_ci               src->type = ppir_target_pipeline;
99bf215546Sopenharmony_ci               src->pipeline = pipeline;
100bf215546Sopenharmony_ci            }
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci            /* update mul node dest to output to pipeline reg */
103bf215546Sopenharmony_ci            dest->type = ppir_target_pipeline;
104bf215546Sopenharmony_ci            dest->pipeline = pipeline;
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci            instr->slots[pos] = mul;
107bf215546Sopenharmony_ci            mul->instr = instr;
108bf215546Sopenharmony_ci         }
109bf215546Sopenharmony_ci         return;
110bf215546Sopenharmony_ci      }
111bf215546Sopenharmony_ci   }
112bf215546Sopenharmony_ci}
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci/* check whether a const slot fix into another const slot */
115bf215546Sopenharmony_cistatic bool ppir_instr_insert_const(ppir_const *dst, const ppir_const *src,
116bf215546Sopenharmony_ci                                    uint8_t *swizzle)
117bf215546Sopenharmony_ci{
118bf215546Sopenharmony_ci   int i, j;
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_ci   for (i = 0; i < src->num; i++) {
121bf215546Sopenharmony_ci      for (j = 0; j < dst->num; j++) {
122bf215546Sopenharmony_ci         if (src->value[i].ui == dst->value[j].ui)
123bf215546Sopenharmony_ci            break;
124bf215546Sopenharmony_ci      }
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci      if (j == dst->num) {
127bf215546Sopenharmony_ci         if (dst->num == 4)
128bf215546Sopenharmony_ci            return false;
129bf215546Sopenharmony_ci         dst->value[dst->num++] = src->value[i];
130bf215546Sopenharmony_ci      }
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci      swizzle[i] = j;
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   return true;
136bf215546Sopenharmony_ci}
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_cistatic void ppir_update_src_pipeline(ppir_pipeline pipeline, ppir_src *src,
139bf215546Sopenharmony_ci                                     ppir_dest *dest, uint8_t *swizzle)
140bf215546Sopenharmony_ci{
141bf215546Sopenharmony_ci   if (ppir_node_target_equal(src, dest)) {
142bf215546Sopenharmony_ci      src->type = ppir_target_pipeline;
143bf215546Sopenharmony_ci      src->pipeline = pipeline;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci      if (swizzle) {
146bf215546Sopenharmony_ci         for (int k = 0; k < 4; k++)
147bf215546Sopenharmony_ci            src->swizzle[k] = swizzle[src->swizzle[k]];
148bf215546Sopenharmony_ci      }
149bf215546Sopenharmony_ci   }
150bf215546Sopenharmony_ci}
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci/* make alu node src reflact the pipeline reg */
153bf215546Sopenharmony_cistatic void ppir_instr_update_src_pipeline(ppir_instr *instr, ppir_pipeline pipeline,
154bf215546Sopenharmony_ci                                           ppir_dest *dest, uint8_t *swizzle)
155bf215546Sopenharmony_ci{
156bf215546Sopenharmony_ci   for (int i = PPIR_INSTR_SLOT_ALU_START; i <= PPIR_INSTR_SLOT_ALU_END; i++) {
157bf215546Sopenharmony_ci      if (!instr->slots[i])
158bf215546Sopenharmony_ci         continue;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci      ppir_alu_node *alu = ppir_node_to_alu(instr->slots[i]);
161bf215546Sopenharmony_ci      for (int j = 0; j < alu->num_src; j++) {
162bf215546Sopenharmony_ci         ppir_src *src = alu->src + j;
163bf215546Sopenharmony_ci         ppir_update_src_pipeline(pipeline, src, dest, swizzle);
164bf215546Sopenharmony_ci      }
165bf215546Sopenharmony_ci   }
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci   ppir_node *branch_node = instr->slots[PPIR_INSTR_SLOT_BRANCH];
168bf215546Sopenharmony_ci   if (branch_node && (branch_node->type == ppir_node_type_branch)) {
169bf215546Sopenharmony_ci      ppir_branch_node *branch = ppir_node_to_branch(branch_node);
170bf215546Sopenharmony_ci      for (int j = 0; j < 2; j++) {
171bf215546Sopenharmony_ci         ppir_src *src = branch->src + j;
172bf215546Sopenharmony_ci         ppir_update_src_pipeline(pipeline, src, dest, swizzle);
173bf215546Sopenharmony_ci      }
174bf215546Sopenharmony_ci   }
175bf215546Sopenharmony_ci}
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_cibool ppir_instr_insert_node(ppir_instr *instr, ppir_node *node)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci   if (node->op == ppir_op_const) {
180bf215546Sopenharmony_ci      int i;
181bf215546Sopenharmony_ci      ppir_const_node *c = ppir_node_to_const(node);
182bf215546Sopenharmony_ci      const ppir_const *nc = &c->constant;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci      for (i = 0; i < 2; i++) {
185bf215546Sopenharmony_ci         ppir_const ic = instr->constant[i];
186bf215546Sopenharmony_ci         uint8_t swizzle[4] = {0};
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci         if (ppir_instr_insert_const(&ic, nc, swizzle)) {
189bf215546Sopenharmony_ci            instr->constant[i] = ic;
190bf215546Sopenharmony_ci            ppir_node *succ = ppir_node_first_succ(node);
191bf215546Sopenharmony_ci            for (int s = 0; s < ppir_node_get_src_num(succ); s++) {
192bf215546Sopenharmony_ci               ppir_src *src = ppir_node_get_src(succ, s);
193bf215546Sopenharmony_ci               assert(src);
194bf215546Sopenharmony_ci               if (src->node != node)
195bf215546Sopenharmony_ci                  continue;
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci               ppir_update_src_pipeline(ppir_pipeline_reg_const0 + i, src,
198bf215546Sopenharmony_ci                                        &c->dest, swizzle);
199bf215546Sopenharmony_ci            }
200bf215546Sopenharmony_ci            break;
201bf215546Sopenharmony_ci         }
202bf215546Sopenharmony_ci      }
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci      /* no const slot can insert */
205bf215546Sopenharmony_ci      if (i == 2)
206bf215546Sopenharmony_ci         return false;
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci      return true;
209bf215546Sopenharmony_ci   }
210bf215546Sopenharmony_ci   else {
211bf215546Sopenharmony_ci      int *slots = ppir_op_infos[node->op].slots;
212bf215546Sopenharmony_ci      for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) {
213bf215546Sopenharmony_ci         int pos = slots[i];
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci         if (instr->slots[pos]) {
216bf215546Sopenharmony_ci            /* node already in this instr, i.e. load_uniform */
217bf215546Sopenharmony_ci            if (instr->slots[pos] == node)
218bf215546Sopenharmony_ci               return true;
219bf215546Sopenharmony_ci            else
220bf215546Sopenharmony_ci               continue;
221bf215546Sopenharmony_ci         }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci         /* ^fmul dests (e.g. condition for select) can only be
224bf215546Sopenharmony_ci          * scheduled to ALU_SCL_MUL */
225bf215546Sopenharmony_ci         if (pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) {
226bf215546Sopenharmony_ci            ppir_dest *dest = ppir_node_get_dest(node);
227bf215546Sopenharmony_ci            if (dest && dest->type == ppir_target_pipeline &&
228bf215546Sopenharmony_ci                dest->pipeline == ppir_pipeline_reg_fmul)
229bf215546Sopenharmony_ci            continue;
230bf215546Sopenharmony_ci         }
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci         if (pos == PPIR_INSTR_SLOT_ALU_SCL_MUL ||
233bf215546Sopenharmony_ci             pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) {
234bf215546Sopenharmony_ci            ppir_dest *dest = ppir_node_get_dest(node);
235bf215546Sopenharmony_ci            if (!ppir_target_is_scalar(dest))
236bf215546Sopenharmony_ci               continue;
237bf215546Sopenharmony_ci         }
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci         instr->slots[pos] = node;
240bf215546Sopenharmony_ci         node->instr = instr;
241bf215546Sopenharmony_ci         node->instr_pos = pos;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci         if ((node->op == ppir_op_load_uniform) || (node->op == ppir_op_load_temp)) {
244bf215546Sopenharmony_ci            ppir_load_node *l = ppir_node_to_load(node);
245bf215546Sopenharmony_ci            ppir_instr_update_src_pipeline(
246bf215546Sopenharmony_ci               instr, ppir_pipeline_reg_uniform, &l->dest, NULL);
247bf215546Sopenharmony_ci         }
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci         return true;
250bf215546Sopenharmony_ci      }
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci      return false;
253bf215546Sopenharmony_ci   }
254bf215546Sopenharmony_ci}
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_cistatic struct {
257bf215546Sopenharmony_ci   int len;
258bf215546Sopenharmony_ci   char *name;
259bf215546Sopenharmony_ci} ppir_instr_fields[] = {
260bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_VARYING] = { 4, "vary" },
261bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_TEXLD] = { 4, "texl"},
262bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_UNIFORM] = { 4, "unif" },
263bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_ALU_VEC_MUL] = { 4, "vmul" },
264bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_ALU_SCL_MUL] = { 4, "smul" },
265bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_ALU_VEC_ADD] = { 4, "vadd" },
266bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_ALU_SCL_ADD] = { 4, "sadd" },
267bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_ALU_COMBINE] = { 4, "comb" },
268bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_STORE_TEMP] = { 4, "stor" },
269bf215546Sopenharmony_ci   [PPIR_INSTR_SLOT_BRANCH] = { 4, "brch" },
270bf215546Sopenharmony_ci};
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_civoid ppir_instr_print_list(ppir_compiler *comp)
273bf215546Sopenharmony_ci{
274bf215546Sopenharmony_ci   if (!(lima_debug & LIMA_DEBUG_PP))
275bf215546Sopenharmony_ci      return;
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   printf("======ppir instr list======\n");
278bf215546Sopenharmony_ci   printf("      ");
279bf215546Sopenharmony_ci   for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++)
280bf215546Sopenharmony_ci      printf("%-*s ", ppir_instr_fields[i].len, ppir_instr_fields[i].name);
281bf215546Sopenharmony_ci   printf("const0|1\n");
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   list_for_each_entry(ppir_block, block, &comp->block_list, list) {
284bf215546Sopenharmony_ci      printf("-------block %3d-------\n", block->index);
285bf215546Sopenharmony_ci      list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
286bf215546Sopenharmony_ci         printf("%c%03d: ", instr->stop ? '*' : ' ', instr->index);
287bf215546Sopenharmony_ci         for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
288bf215546Sopenharmony_ci            ppir_node *node = instr->slots[i];
289bf215546Sopenharmony_ci            if (node)
290bf215546Sopenharmony_ci               printf("%-*d ", ppir_instr_fields[i].len, node->index);
291bf215546Sopenharmony_ci            else
292bf215546Sopenharmony_ci               printf("%-*s ", ppir_instr_fields[i].len, "null");
293bf215546Sopenharmony_ci         }
294bf215546Sopenharmony_ci         for (int i = 0; i < 2; i++) {
295bf215546Sopenharmony_ci            if (i)
296bf215546Sopenharmony_ci               printf("| ");
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci            for (int j = 0; j < instr->constant[i].num; j++)
299bf215546Sopenharmony_ci               printf("%f ", instr->constant[i].value[j].f);
300bf215546Sopenharmony_ci         }
301bf215546Sopenharmony_ci         printf("\n");
302bf215546Sopenharmony_ci      }
303bf215546Sopenharmony_ci   }
304bf215546Sopenharmony_ci   printf("===========================\n");
305bf215546Sopenharmony_ci}
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_cistatic void ppir_instr_print_sub(ppir_instr *instr)
308bf215546Sopenharmony_ci{
309bf215546Sopenharmony_ci   printf("[%s%d",
310bf215546Sopenharmony_ci          instr->printed && !ppir_instr_is_leaf(instr) ? "+" : "",
311bf215546Sopenharmony_ci          instr->index);
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   if (!instr->printed) {
314bf215546Sopenharmony_ci      ppir_instr_foreach_pred(instr, dep) {
315bf215546Sopenharmony_ci         ppir_instr_print_sub(dep->pred);
316bf215546Sopenharmony_ci      }
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci      instr->printed = true;
319bf215546Sopenharmony_ci   }
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   printf("]");
322bf215546Sopenharmony_ci}
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_civoid ppir_instr_print_dep(ppir_compiler *comp)
325bf215546Sopenharmony_ci{
326bf215546Sopenharmony_ci   if (!(lima_debug & LIMA_DEBUG_PP))
327bf215546Sopenharmony_ci      return;
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci   list_for_each_entry(ppir_block, block, &comp->block_list, list) {
330bf215546Sopenharmony_ci      list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
331bf215546Sopenharmony_ci         instr->printed = false;
332bf215546Sopenharmony_ci      }
333bf215546Sopenharmony_ci   }
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   printf("======ppir instr depend======\n");
336bf215546Sopenharmony_ci   list_for_each_entry(ppir_block, block, &comp->block_list, list) {
337bf215546Sopenharmony_ci      printf("-------block %3d-------\n", block->index);
338bf215546Sopenharmony_ci      list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
339bf215546Sopenharmony_ci         if (ppir_instr_is_root(instr)) {
340bf215546Sopenharmony_ci            ppir_instr_print_sub(instr);
341bf215546Sopenharmony_ci            printf("\n");
342bf215546Sopenharmony_ci         }
343bf215546Sopenharmony_ci      }
344bf215546Sopenharmony_ci   }
345bf215546Sopenharmony_ci   printf("=============================\n");
346bf215546Sopenharmony_ci}
347