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/bitscan.h"
26bf215546Sopenharmony_ci#include "util/ralloc.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "ppir.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_cistatic bool ppir_lower_const(ppir_block *block, ppir_node *node)
31bf215546Sopenharmony_ci{
32bf215546Sopenharmony_ci   if (ppir_node_is_root(node)) {
33bf215546Sopenharmony_ci      ppir_node_delete(node);
34bf215546Sopenharmony_ci      return true;
35bf215546Sopenharmony_ci   }
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci   assert(ppir_node_has_single_succ(node));
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci   ppir_node *succ = ppir_node_first_succ(node);
40bf215546Sopenharmony_ci   ppir_dest *dest = ppir_node_get_dest(node);
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci   switch (succ->type) {
43bf215546Sopenharmony_ci   case ppir_node_type_alu:
44bf215546Sopenharmony_ci   case ppir_node_type_branch:
45bf215546Sopenharmony_ci      /* ALU and branch can consume consts directly */
46bf215546Sopenharmony_ci      dest->type = ppir_target_pipeline;
47bf215546Sopenharmony_ci      /* Reg will be updated in node_to_instr later */
48bf215546Sopenharmony_ci      dest->pipeline = ppir_pipeline_reg_const0;
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci      /* single succ can still have multiple references to this node */
51bf215546Sopenharmony_ci      for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
52bf215546Sopenharmony_ci         ppir_src *src = ppir_node_get_src(succ, i);
53bf215546Sopenharmony_ci         if (src && src->node == node) {
54bf215546Sopenharmony_ci            src->type = ppir_target_pipeline;
55bf215546Sopenharmony_ci            src->pipeline = ppir_pipeline_reg_const0;
56bf215546Sopenharmony_ci         }
57bf215546Sopenharmony_ci      }
58bf215546Sopenharmony_ci      return true;
59bf215546Sopenharmony_ci   default:
60bf215546Sopenharmony_ci      /* Create a move for everyone else */
61bf215546Sopenharmony_ci      break;
62bf215546Sopenharmony_ci   }
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci   ppir_node *move = ppir_node_insert_mov(node);
65bf215546Sopenharmony_ci   if (unlikely(!move))
66bf215546Sopenharmony_ci      return false;
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   ppir_debug("lower const create move %d for %d\n",
69bf215546Sopenharmony_ci              move->index, node->index);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   /* Need to be careful with changing src/dst type here:
72bf215546Sopenharmony_ci    * it has to be done *after* successors have their children
73bf215546Sopenharmony_ci    * replaced, otherwise ppir_node_replace_child() won't find
74bf215546Sopenharmony_ci    * matching src/dst and as result won't work
75bf215546Sopenharmony_ci    */
76bf215546Sopenharmony_ci   ppir_src *mov_src = ppir_node_get_src(move, 0);
77bf215546Sopenharmony_ci   mov_src->type = dest->type = ppir_target_pipeline;
78bf215546Sopenharmony_ci   mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_const0;
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   return true;
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_cistatic bool ppir_lower_swap_args(ppir_block *block, ppir_node *node)
84bf215546Sopenharmony_ci{
85bf215546Sopenharmony_ci   /* swapped op must be the next op */
86bf215546Sopenharmony_ci   node->op++;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   assert(node->type == ppir_node_type_alu);
89bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
90bf215546Sopenharmony_ci   assert(alu->num_src == 2);
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   ppir_src tmp = alu->src[0];
93bf215546Sopenharmony_ci   alu->src[0] = alu->src[1];
94bf215546Sopenharmony_ci   alu->src[1] = tmp;
95bf215546Sopenharmony_ci   return true;
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_cistatic bool ppir_lower_load(ppir_block *block, ppir_node *node)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   ppir_dest *dest = ppir_node_get_dest(node);
101bf215546Sopenharmony_ci   if (ppir_node_is_root(node) && dest->type == ppir_target_ssa) {
102bf215546Sopenharmony_ci      ppir_node_delete(node);
103bf215546Sopenharmony_ci      return true;
104bf215546Sopenharmony_ci   }
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci   /* load can have multiple successors in case if we duplicated load node
107bf215546Sopenharmony_ci    * that has load node in source
108bf215546Sopenharmony_ci    */
109bf215546Sopenharmony_ci   if ((ppir_node_has_single_src_succ(node) || ppir_node_is_root(node)) &&
110bf215546Sopenharmony_ci      dest->type != ppir_target_register) {
111bf215546Sopenharmony_ci      ppir_node *succ = ppir_node_first_succ(node);
112bf215546Sopenharmony_ci      switch (succ->type) {
113bf215546Sopenharmony_ci      case ppir_node_type_alu:
114bf215546Sopenharmony_ci      case ppir_node_type_branch: {
115bf215546Sopenharmony_ci         /* single succ can still have multiple references to this node */
116bf215546Sopenharmony_ci         for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
117bf215546Sopenharmony_ci            ppir_src *src = ppir_node_get_src(succ, i);
118bf215546Sopenharmony_ci            if (src && src->node == node) {
119bf215546Sopenharmony_ci               /* Can consume uniforms directly */
120bf215546Sopenharmony_ci               src->type = dest->type = ppir_target_pipeline;
121bf215546Sopenharmony_ci               src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform;
122bf215546Sopenharmony_ci            }
123bf215546Sopenharmony_ci         }
124bf215546Sopenharmony_ci         return true;
125bf215546Sopenharmony_ci      }
126bf215546Sopenharmony_ci      default:
127bf215546Sopenharmony_ci         /* Create mov for everyone else */
128bf215546Sopenharmony_ci         break;
129bf215546Sopenharmony_ci      }
130bf215546Sopenharmony_ci   }
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   ppir_node *move = ppir_node_insert_mov(node);
133bf215546Sopenharmony_ci   if (unlikely(!move))
134bf215546Sopenharmony_ci      return false;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   ppir_src *mov_src = ppir_node_get_src(move, 0);
137bf215546Sopenharmony_ci   mov_src->type = dest->type = ppir_target_pipeline;
138bf215546Sopenharmony_ci   mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   return true;
141bf215546Sopenharmony_ci}
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_cistatic bool ppir_lower_ddxy(ppir_block *block, ppir_node *node)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci   assert(node->type == ppir_node_type_alu);
146bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   alu->src[1] = alu->src[0];
149bf215546Sopenharmony_ci   if (node->op == ppir_op_ddx)
150bf215546Sopenharmony_ci      alu->src[1].negate = !alu->src[1].negate;
151bf215546Sopenharmony_ci   else if (node->op == ppir_op_ddy)
152bf215546Sopenharmony_ci      alu->src[0].negate = !alu->src[0].negate;
153bf215546Sopenharmony_ci   else
154bf215546Sopenharmony_ci      assert(0);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci   alu->num_src = 2;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   return true;
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_cistatic bool ppir_lower_texture(ppir_block *block, ppir_node *node)
162bf215546Sopenharmony_ci{
163bf215546Sopenharmony_ci   ppir_dest *dest = ppir_node_get_dest(node);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   if (ppir_node_has_single_succ(node) && dest->type == ppir_target_ssa) {
166bf215546Sopenharmony_ci      ppir_node *succ = ppir_node_first_succ(node);
167bf215546Sopenharmony_ci      dest->type = ppir_target_pipeline;
168bf215546Sopenharmony_ci      dest->pipeline = ppir_pipeline_reg_sampler;
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci      for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
171bf215546Sopenharmony_ci         ppir_src *src = ppir_node_get_src(succ, i);
172bf215546Sopenharmony_ci         if (src && src->node == node) {
173bf215546Sopenharmony_ci            src->type = ppir_target_pipeline;
174bf215546Sopenharmony_ci            src->pipeline = ppir_pipeline_reg_sampler;
175bf215546Sopenharmony_ci         }
176bf215546Sopenharmony_ci      }
177bf215546Sopenharmony_ci      return true;
178bf215546Sopenharmony_ci   }
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   /* Create move node as fallback */
181bf215546Sopenharmony_ci   ppir_node *move = ppir_node_insert_mov(node);
182bf215546Sopenharmony_ci   if (unlikely(!move))
183bf215546Sopenharmony_ci      return false;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   ppir_debug("lower texture create move %d for %d\n",
186bf215546Sopenharmony_ci              move->index, node->index);
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   ppir_src *mov_src = ppir_node_get_src(move, 0);
189bf215546Sopenharmony_ci   mov_src->type = dest->type = ppir_target_pipeline;
190bf215546Sopenharmony_ci   mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_sampler;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   return true;
193bf215546Sopenharmony_ci}
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci/* Check if the select condition and ensure it can be inserted to
196bf215546Sopenharmony_ci * the scalar mul slot */
197bf215546Sopenharmony_cistatic bool ppir_lower_select(ppir_block *block, ppir_node *node)
198bf215546Sopenharmony_ci{
199bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
200bf215546Sopenharmony_ci   ppir_src *src0 = &alu->src[0];
201bf215546Sopenharmony_ci   ppir_src *src1 = &alu->src[1];
202bf215546Sopenharmony_ci   ppir_src *src2 = &alu->src[2];
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   /* If the condition is already an alu scalar whose only successor
205bf215546Sopenharmony_ci    * is the select node, just turn it into pipeline output. */
206bf215546Sopenharmony_ci   /* The (src2->node == cond) case is a tricky exception.
207bf215546Sopenharmony_ci    * The reason is that we must force cond to output to ^fmul -- but
208bf215546Sopenharmony_ci    * then it no longer writes to a register and it is impossible to
209bf215546Sopenharmony_ci    * reference ^fmul in src2. So in that exceptional case, also fall
210bf215546Sopenharmony_ci    * back to the mov. */
211bf215546Sopenharmony_ci   ppir_node *cond = src0->node;
212bf215546Sopenharmony_ci   if (cond &&
213bf215546Sopenharmony_ci       cond->type == ppir_node_type_alu &&
214bf215546Sopenharmony_ci       ppir_node_has_single_succ(cond) &&
215bf215546Sopenharmony_ci       ppir_target_is_scalar(ppir_node_get_dest(cond)) &&
216bf215546Sopenharmony_ci       ppir_node_schedulable_slot(cond, PPIR_INSTR_SLOT_ALU_SCL_MUL) &&
217bf215546Sopenharmony_ci       src2->node != cond) {
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci      ppir_dest *cond_dest = ppir_node_get_dest(cond);
220bf215546Sopenharmony_ci      cond_dest->type = ppir_target_pipeline;
221bf215546Sopenharmony_ci      cond_dest->pipeline = ppir_pipeline_reg_fmul;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci      ppir_node_target_assign(src0, cond);
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci      /* src1 could also be a reference from the same node as
226bf215546Sopenharmony_ci       * the condition, so update it in that case. */
227bf215546Sopenharmony_ci      if (src1->node && src1->node == cond)
228bf215546Sopenharmony_ci         ppir_node_target_assign(src1, cond);
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci      return true;
231bf215546Sopenharmony_ci   }
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   /* If the condition can't be used for any reason, insert a mov
234bf215546Sopenharmony_ci    * so that the condition can end up in ^fmul */
235bf215546Sopenharmony_ci   ppir_node *move = ppir_node_create(block, ppir_op_mov, -1, 0);
236bf215546Sopenharmony_ci   if (!move)
237bf215546Sopenharmony_ci      return false;
238bf215546Sopenharmony_ci   list_addtail(&move->list, &node->list);
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   ppir_alu_node *move_alu = ppir_node_to_alu(move);
241bf215546Sopenharmony_ci   ppir_src *move_src = move_alu->src;
242bf215546Sopenharmony_ci   move_src->type = src0->type;
243bf215546Sopenharmony_ci   move_src->ssa = src0->ssa;
244bf215546Sopenharmony_ci   move_src->swizzle[0] = src0->swizzle[0];
245bf215546Sopenharmony_ci   move_alu->num_src = 1;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   ppir_dest *move_dest = &move_alu->dest;
248bf215546Sopenharmony_ci   move_dest->type = ppir_target_pipeline;
249bf215546Sopenharmony_ci   move_dest->pipeline = ppir_pipeline_reg_fmul;
250bf215546Sopenharmony_ci   move_dest->write_mask = 1;
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   ppir_node *pred = src0->node;
253bf215546Sopenharmony_ci   ppir_dep *dep = ppir_dep_for_pred(node, pred);
254bf215546Sopenharmony_ci   if (dep)
255bf215546Sopenharmony_ci      ppir_node_replace_pred(dep, move);
256bf215546Sopenharmony_ci   else
257bf215546Sopenharmony_ci      ppir_node_add_dep(node, move, ppir_dep_src);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   /* pred can be a register */
260bf215546Sopenharmony_ci   if (pred)
261bf215546Sopenharmony_ci      ppir_node_add_dep(move, pred, ppir_dep_src);
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   ppir_node_target_assign(src0, move);
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   /* src1 could also be a reference from the same node as
266bf215546Sopenharmony_ci    * the condition, so update it in that case. */
267bf215546Sopenharmony_ci   if (src1->node && src1->node == pred)
268bf215546Sopenharmony_ci      ppir_node_target_assign(src1, move);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   return true;
271bf215546Sopenharmony_ci}
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_cistatic bool ppir_lower_trunc(ppir_block *block, ppir_node *node)
274bf215546Sopenharmony_ci{
275bf215546Sopenharmony_ci   /* Turn it into a mov with a round to integer output modifier */
276bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
277bf215546Sopenharmony_ci   ppir_dest *move_dest = &alu->dest;
278bf215546Sopenharmony_ci   move_dest->modifier = ppir_outmod_round;
279bf215546Sopenharmony_ci   node->op = ppir_op_mov;
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_ci   return true;
282bf215546Sopenharmony_ci}
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_cistatic bool ppir_lower_abs(ppir_block *block, ppir_node *node)
285bf215546Sopenharmony_ci{
286bf215546Sopenharmony_ci   /* Turn it into a mov and set the absolute modifier */
287bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   assert(alu->num_src == 1);
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci   alu->src[0].absolute = true;
292bf215546Sopenharmony_ci   alu->src[0].negate = false;
293bf215546Sopenharmony_ci   node->op = ppir_op_mov;
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   return true;
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_cistatic bool ppir_lower_neg(ppir_block *block, ppir_node *node)
299bf215546Sopenharmony_ci{
300bf215546Sopenharmony_ci   /* Turn it into a mov and set the negate modifier */
301bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   assert(alu->num_src == 1);
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   alu->src[0].negate = !alu->src[0].negate;
306bf215546Sopenharmony_ci   node->op = ppir_op_mov;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   return true;
309bf215546Sopenharmony_ci}
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_cistatic bool ppir_lower_sat(ppir_block *block, ppir_node *node)
312bf215546Sopenharmony_ci{
313bf215546Sopenharmony_ci   /* Turn it into a mov with the saturate output modifier */
314bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci   assert(alu->num_src == 1);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   ppir_dest *move_dest = &alu->dest;
319bf215546Sopenharmony_ci   move_dest->modifier = ppir_outmod_clamp_fraction;
320bf215546Sopenharmony_ci   node->op = ppir_op_mov;
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   return true;
323bf215546Sopenharmony_ci}
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_cistatic bool ppir_lower_branch_merge_condition(ppir_block *block, ppir_node *node)
326bf215546Sopenharmony_ci{
327bf215546Sopenharmony_ci   /* Check if we can merge a condition with a branch instruction,
328bf215546Sopenharmony_ci    * removing the need for a select instruction */
329bf215546Sopenharmony_ci   assert(node->type == ppir_node_type_branch);
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   if (!ppir_node_has_single_pred(node))
332bf215546Sopenharmony_ci      return false;
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   ppir_node *pred = ppir_node_first_pred(node);
335bf215546Sopenharmony_ci   assert(pred);
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci   if (pred->type != ppir_node_type_alu)
338bf215546Sopenharmony_ci      return false;
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci   switch (pred->op)
341bf215546Sopenharmony_ci   {
342bf215546Sopenharmony_ci      case ppir_op_lt:
343bf215546Sopenharmony_ci      case ppir_op_gt:
344bf215546Sopenharmony_ci      case ppir_op_le:
345bf215546Sopenharmony_ci      case ppir_op_ge:
346bf215546Sopenharmony_ci      case ppir_op_eq:
347bf215546Sopenharmony_ci      case ppir_op_ne:
348bf215546Sopenharmony_ci         break;
349bf215546Sopenharmony_ci      default:
350bf215546Sopenharmony_ci         return false;
351bf215546Sopenharmony_ci   }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   ppir_dest *dest = ppir_node_get_dest(pred);
354bf215546Sopenharmony_ci   if (!ppir_node_has_single_succ(pred) || dest->type != ppir_target_ssa)
355bf215546Sopenharmony_ci      return false;
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   ppir_alu_node *cond = ppir_node_to_alu(pred);
358bf215546Sopenharmony_ci   /* branch can't reference pipeline registers */
359bf215546Sopenharmony_ci   if (cond->src[0].type == ppir_target_pipeline ||
360bf215546Sopenharmony_ci       cond->src[1].type == ppir_target_pipeline)
361bf215546Sopenharmony_ci      return false;
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   /* branch can't use flags */
364bf215546Sopenharmony_ci   if (cond->src[0].negate || cond->src[0].absolute ||
365bf215546Sopenharmony_ci       cond->src[1].negate || cond->src[1].absolute)
366bf215546Sopenharmony_ci      return false;
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   /* at this point, it can be successfully be replaced. */
369bf215546Sopenharmony_ci   ppir_branch_node *branch = ppir_node_to_branch(node);
370bf215546Sopenharmony_ci   switch (pred->op)
371bf215546Sopenharmony_ci   {
372bf215546Sopenharmony_ci      case ppir_op_le:
373bf215546Sopenharmony_ci         branch->cond_gt = true;
374bf215546Sopenharmony_ci         break;
375bf215546Sopenharmony_ci      case ppir_op_lt:
376bf215546Sopenharmony_ci         branch->cond_eq = true;
377bf215546Sopenharmony_ci         branch->cond_gt = true;
378bf215546Sopenharmony_ci         break;
379bf215546Sopenharmony_ci      case ppir_op_ge:
380bf215546Sopenharmony_ci         branch->cond_lt = true;
381bf215546Sopenharmony_ci         break;
382bf215546Sopenharmony_ci      case ppir_op_gt:
383bf215546Sopenharmony_ci         branch->cond_eq = true;
384bf215546Sopenharmony_ci         branch->cond_lt = true;
385bf215546Sopenharmony_ci         break;
386bf215546Sopenharmony_ci      case ppir_op_eq:
387bf215546Sopenharmony_ci         branch->cond_lt = true;
388bf215546Sopenharmony_ci         branch->cond_gt = true;
389bf215546Sopenharmony_ci         break;
390bf215546Sopenharmony_ci      case ppir_op_ne:
391bf215546Sopenharmony_ci         branch->cond_eq = true;
392bf215546Sopenharmony_ci         break;
393bf215546Sopenharmony_ci      default:
394bf215546Sopenharmony_ci         assert(0);
395bf215546Sopenharmony_ci         break;
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   assert(cond->num_src == 2);
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci   branch->num_src = 2;
401bf215546Sopenharmony_ci   branch->src[0] = cond->src[0];
402bf215546Sopenharmony_ci   branch->src[1] = cond->src[1];
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   /* for all nodes before the condition */
405bf215546Sopenharmony_ci   ppir_node_foreach_pred_safe(pred, dep) {
406bf215546Sopenharmony_ci      /* insert the branch node as successor */
407bf215546Sopenharmony_ci      ppir_node *p = dep->pred;
408bf215546Sopenharmony_ci      ppir_node_remove_dep(dep);
409bf215546Sopenharmony_ci      ppir_node_add_dep(node, p, ppir_dep_src);
410bf215546Sopenharmony_ci   }
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   ppir_node_delete(pred);
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   return true;
415bf215546Sopenharmony_ci}
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_cistatic bool ppir_lower_branch(ppir_block *block, ppir_node *node)
418bf215546Sopenharmony_ci{
419bf215546Sopenharmony_ci   ppir_branch_node *branch = ppir_node_to_branch(node);
420bf215546Sopenharmony_ci
421bf215546Sopenharmony_ci   /* Unconditional branch */
422bf215546Sopenharmony_ci   if (branch->num_src == 0)
423bf215546Sopenharmony_ci      return true;
424bf215546Sopenharmony_ci
425bf215546Sopenharmony_ci   /* Check if we can merge a condition with the branch */
426bf215546Sopenharmony_ci   if (ppir_lower_branch_merge_condition(block, node))
427bf215546Sopenharmony_ci      return true;
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   /* If the condition cannot be merged, fall back to a
430bf215546Sopenharmony_ci    * comparison against zero */
431bf215546Sopenharmony_ci   ppir_const_node *zero = ppir_node_create(block, ppir_op_const, -1, 0);
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   if (!zero)
434bf215546Sopenharmony_ci      return false;
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   zero->constant.value[0].f = 0;
437bf215546Sopenharmony_ci   zero->constant.num = 1;
438bf215546Sopenharmony_ci   zero->dest.type = ppir_target_pipeline;
439bf215546Sopenharmony_ci   zero->dest.pipeline = ppir_pipeline_reg_const0;
440bf215546Sopenharmony_ci   zero->dest.ssa.num_components = 1;
441bf215546Sopenharmony_ci   zero->dest.write_mask = 0x01;
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci   ppir_node_target_assign(&branch->src[1], &zero->node);
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   if (branch->negate)
446bf215546Sopenharmony_ci      branch->cond_eq = true;
447bf215546Sopenharmony_ci   else {
448bf215546Sopenharmony_ci      branch->cond_gt = true;
449bf215546Sopenharmony_ci      branch->cond_lt = true;
450bf215546Sopenharmony_ci   }
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   branch->num_src = 2;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   ppir_node_add_dep(&branch->node, &zero->node, ppir_dep_src);
455bf215546Sopenharmony_ci   list_addtail(&zero->node.list, &node->list);
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci   return true;
458bf215546Sopenharmony_ci}
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_cistatic bool ppir_lower_accum(ppir_block *block, ppir_node *node)
461bf215546Sopenharmony_ci{
462bf215546Sopenharmony_ci    /* If the last argument of a node placed in PPIR_INSTR_SLOT_ALU_SCL_ADD
463bf215546Sopenharmony_ci    * (or PPIR_INSTR_SLOT_ALU_VEC_ADD) is placed in
464bf215546Sopenharmony_ci    * PPIR_INSTR_SLOT_ALU_SCL_MUL (or PPIR_INSTR_SLOT_ALU_VEC_MUL) we cannot
465bf215546Sopenharmony_ci    * save a register (and an instruction) by using a pipeline register.
466bf215546Sopenharmony_ci    * Therefore it is interesting to make sure arguments of that type are
467bf215546Sopenharmony_ci    * the first argument by swapping arguments (if possible) */
468bf215546Sopenharmony_ci   ppir_alu_node *alu = ppir_node_to_alu(node);
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   assert(alu->num_src >= 2);
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   if (alu->src[0].type == ppir_target_pipeline)
473bf215546Sopenharmony_ci      return true;
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci   if (alu->src[0].type == ppir_target_ssa) {
476bf215546Sopenharmony_ci      int *src_0_slots = ppir_op_infos[alu->src[0].node->op].slots;
477bf215546Sopenharmony_ci      if (src_0_slots) {
478bf215546Sopenharmony_ci         for (int i = 0; src_0_slots[i] != PPIR_INSTR_SLOT_END; i++) {
479bf215546Sopenharmony_ci            if ((src_0_slots[i] == PPIR_INSTR_SLOT_ALU_SCL_MUL) ||
480bf215546Sopenharmony_ci               (src_0_slots[i] == PPIR_INSTR_SLOT_ALU_VEC_MUL)) {
481bf215546Sopenharmony_ci               return true;
482bf215546Sopenharmony_ci            }
483bf215546Sopenharmony_ci         }
484bf215546Sopenharmony_ci      }
485bf215546Sopenharmony_ci   }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   int src_to_swap = -1;
488bf215546Sopenharmony_ci   for (int j = 1; j < alu->num_src; j++) {
489bf215546Sopenharmony_ci      if (alu->src[j].type != ppir_target_ssa)
490bf215546Sopenharmony_ci         continue;
491bf215546Sopenharmony_ci      int *src_slots = ppir_op_infos[alu->src[j].node->op].slots;
492bf215546Sopenharmony_ci      if (!src_slots)
493bf215546Sopenharmony_ci         continue;
494bf215546Sopenharmony_ci      for (int i = 0; src_slots[i] != PPIR_INSTR_SLOT_END; i++) {
495bf215546Sopenharmony_ci         if ((src_slots[i] == PPIR_INSTR_SLOT_ALU_SCL_MUL) ||
496bf215546Sopenharmony_ci             (src_slots[i] == PPIR_INSTR_SLOT_ALU_VEC_MUL)) {
497bf215546Sopenharmony_ci            src_to_swap = j;
498bf215546Sopenharmony_ci            break;
499bf215546Sopenharmony_ci         }
500bf215546Sopenharmony_ci      }
501bf215546Sopenharmony_ci      if (src_to_swap > 0)
502bf215546Sopenharmony_ci         break;
503bf215546Sopenharmony_ci   }
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_ci   if (src_to_swap < 0)
506bf215546Sopenharmony_ci      return true;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   /* Swap arguments so that we can use a pipeline register later on */
509bf215546Sopenharmony_ci   ppir_src tmp = alu->src[0];
510bf215546Sopenharmony_ci   alu->src[0] = alu->src[src_to_swap];
511bf215546Sopenharmony_ci   alu->src[src_to_swap] = tmp;
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   return true;
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_cistatic bool (*ppir_lower_funcs[ppir_op_num])(ppir_block *, ppir_node *) = {
517bf215546Sopenharmony_ci   [ppir_op_abs] = ppir_lower_abs,
518bf215546Sopenharmony_ci   [ppir_op_neg] = ppir_lower_neg,
519bf215546Sopenharmony_ci   [ppir_op_const] = ppir_lower_const,
520bf215546Sopenharmony_ci   [ppir_op_ddx] = ppir_lower_ddxy,
521bf215546Sopenharmony_ci   [ppir_op_ddy] = ppir_lower_ddxy,
522bf215546Sopenharmony_ci   [ppir_op_lt] = ppir_lower_swap_args,
523bf215546Sopenharmony_ci   [ppir_op_le] = ppir_lower_swap_args,
524bf215546Sopenharmony_ci   [ppir_op_load_texture] = ppir_lower_texture,
525bf215546Sopenharmony_ci   [ppir_op_select] = ppir_lower_select,
526bf215546Sopenharmony_ci   [ppir_op_trunc] = ppir_lower_trunc,
527bf215546Sopenharmony_ci   [ppir_op_sat] = ppir_lower_sat,
528bf215546Sopenharmony_ci   [ppir_op_branch] = ppir_lower_branch,
529bf215546Sopenharmony_ci   [ppir_op_load_uniform] = ppir_lower_load,
530bf215546Sopenharmony_ci   [ppir_op_load_temp] = ppir_lower_load,
531bf215546Sopenharmony_ci   [ppir_op_add] = ppir_lower_accum,
532bf215546Sopenharmony_ci   [ppir_op_max] = ppir_lower_accum,
533bf215546Sopenharmony_ci   [ppir_op_min] = ppir_lower_accum,
534bf215546Sopenharmony_ci   [ppir_op_eq] = ppir_lower_accum,
535bf215546Sopenharmony_ci   [ppir_op_ne] = ppir_lower_accum,
536bf215546Sopenharmony_ci};
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_cibool ppir_lower_prog(ppir_compiler *comp)
539bf215546Sopenharmony_ci{
540bf215546Sopenharmony_ci   list_for_each_entry(ppir_block, block, &comp->block_list, list) {
541bf215546Sopenharmony_ci      list_for_each_entry_safe(ppir_node, node, &block->node_list, list) {
542bf215546Sopenharmony_ci         if (ppir_lower_funcs[node->op] &&
543bf215546Sopenharmony_ci             !ppir_lower_funcs[node->op](block, node))
544bf215546Sopenharmony_ci            return false;
545bf215546Sopenharmony_ci      }
546bf215546Sopenharmony_ci   }
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_ci   return true;
549bf215546Sopenharmony_ci}
550