lima/ppir: do not assume single src for pipeline outputs
[mesa.git] / src / gallium / drivers / lima / ir / pp / lower.c
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/bitscan.h"
26 #include "util/ralloc.h"
27
28 #include "ppir.h"
29
30 static bool ppir_lower_const(ppir_block *block, ppir_node *node)
31 {
32 if (ppir_node_is_root(node)) {
33 ppir_node_delete(node);
34 return true;
35 }
36
37 assert(ppir_node_has_single_succ(node));
38
39 ppir_node *succ = ppir_node_first_succ(node);
40 ppir_dest *dest = ppir_node_get_dest(node);
41
42 switch (succ->type) {
43 case ppir_node_type_alu:
44 case ppir_node_type_branch:
45 /* ALU and branch can consume consts directly */
46 dest->type = ppir_target_pipeline;
47 /* Reg will be updated in node_to_instr later */
48 dest->pipeline = ppir_pipeline_reg_const0;
49
50 /* single succ can still have multiple references to this node */
51 for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
52 ppir_src *src = ppir_node_get_src(succ, i);
53 if (src && src->node == node) {
54 src->type = ppir_target_pipeline;
55 src->pipeline = ppir_pipeline_reg_const0;
56 }
57 }
58 return true;
59 default:
60 /* Create a move for everyone else */
61 break;
62 }
63
64 ppir_node *move = ppir_node_insert_mov(node);
65 if (unlikely(!move))
66 return false;
67
68 ppir_debug("lower const create move %d for %d\n",
69 move->index, node->index);
70
71 /* Need to be careful with changing src/dst type here:
72 * it has to be done *after* successors have their children
73 * replaced, otherwise ppir_node_replace_child() won't find
74 * matching src/dst and as result won't work
75 */
76 ppir_src *mov_src = ppir_node_get_src(move, 0);
77 mov_src->type = dest->type = ppir_target_pipeline;
78 mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_const0;
79
80 return true;
81 }
82
83 static bool ppir_lower_swap_args(ppir_block *block, ppir_node *node)
84 {
85 /* swapped op must be the next op */
86 node->op++;
87
88 assert(node->type == ppir_node_type_alu);
89 ppir_alu_node *alu = ppir_node_to_alu(node);
90 assert(alu->num_src == 2);
91
92 ppir_src tmp = alu->src[0];
93 alu->src[0] = alu->src[1];
94 alu->src[1] = tmp;
95 return true;
96 }
97
98 static bool ppir_lower_load(ppir_block *block, ppir_node *node)
99 {
100 ppir_dest *dest = ppir_node_get_dest(node);
101 if (ppir_node_is_root(node) && dest->type == ppir_target_ssa) {
102 ppir_node_delete(node);
103 return true;
104 }
105
106 /* load can have multiple successors in case if we duplicated load node
107 * that has load node in source
108 */
109 if ((ppir_node_has_single_src_succ(node) || ppir_node_is_root(node)) &&
110 dest->type != ppir_target_register) {
111 ppir_node *succ = ppir_node_first_succ(node);
112 switch (succ->type) {
113 case ppir_node_type_alu:
114 case ppir_node_type_branch: {
115 /* single succ can still have multiple references to this node */
116 for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
117 ppir_src *src = ppir_node_get_src(succ, i);
118 if (src && src->node == node) {
119 /* Can consume uniforms directly */
120 src->type = dest->type = ppir_target_pipeline;
121 src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform;
122 }
123 }
124 return true;
125 }
126 default:
127 /* Create mov for everyone else */
128 break;
129 }
130 }
131
132 ppir_node *move = ppir_node_insert_mov(node);
133 if (unlikely(!move))
134 return false;
135
136 ppir_src *mov_src = ppir_node_get_src(move, 0);
137 mov_src->type = dest->type = ppir_target_pipeline;
138 mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_uniform;
139
140 return true;
141 }
142
143 static bool ppir_lower_ddxy(ppir_block *block, ppir_node *node)
144 {
145 assert(node->type == ppir_node_type_alu);
146 ppir_alu_node *alu = ppir_node_to_alu(node);
147
148 alu->src[1] = alu->src[0];
149 if (node->op == ppir_op_ddx)
150 alu->src[1].negate = !alu->src[1].negate;
151 else if (node->op == ppir_op_ddy)
152 alu->src[0].negate = !alu->src[0].negate;
153 else
154 assert(0);
155
156 alu->num_src = 2;
157
158 return true;
159 }
160
161 static bool ppir_lower_texture(ppir_block *block, ppir_node *node)
162 {
163 ppir_load_texture_node *load_tex = ppir_node_to_load_texture(node);
164 ppir_dest *dest = ppir_node_get_dest(node);
165 ppir_node *src_coords = ppir_node_get_src(node, 0)->node;
166 ppir_load_node *load = NULL;
167
168 if (src_coords && ppir_node_has_single_src_succ(src_coords) &&
169 (src_coords->op == ppir_op_load_coords))
170 load = ppir_node_to_load(src_coords);
171 else {
172 /* Create load_coords node */
173 load = ppir_node_create(block, ppir_op_load_coords_reg, -1, 0);
174 if (!load)
175 return false;
176 list_addtail(&load->node.list, &node->list);
177
178 load->src = load_tex->src[0];
179 load->num_src = 1;
180 if (load_tex->sampler_dim == GLSL_SAMPLER_DIM_CUBE)
181 load->num_components = 3;
182 else
183 load->num_components = 2;
184
185 ppir_debug("%s create load_coords node %d for %d\n",
186 __FUNCTION__, load->node.index, node->index);
187
188 ppir_node_foreach_pred_safe(node, dep) {
189 ppir_node *pred = dep->pred;
190 ppir_node_remove_dep(dep);
191 ppir_node_add_dep(&load->node, pred, ppir_dep_src);
192 }
193 ppir_node_add_dep(node, &load->node, ppir_dep_src);
194 }
195
196 assert(load);
197 load_tex->src[0].type = load->dest.type = ppir_target_pipeline;
198 load_tex->src[0].pipeline = load->dest.pipeline = ppir_pipeline_reg_discard;
199
200 /* Always create move node since there can be successors in other blocks */
201 ppir_node *move = ppir_node_insert_mov_all_blocks(node);
202 if (unlikely(!move))
203 return false;
204
205 ppir_debug("lower texture create move %d for %d\n",
206 move->index, node->index);
207
208 ppir_src *mov_src= ppir_node_get_src(move, 0);
209 mov_src->type = dest->type = ppir_target_pipeline;
210 mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_sampler;
211
212 return true;
213 }
214
215 /* insert a move as the select condition to make sure it can
216 * be inserted to select instr float mul slot
217 */
218 static bool ppir_lower_select(ppir_block *block, ppir_node *node)
219 {
220 ppir_alu_node *alu = ppir_node_to_alu(node);
221
222 ppir_node *move = ppir_node_create(block, ppir_op_sel_cond, -1, 0);
223 if (!move)
224 return false;
225 list_addtail(&move->list, &node->list);
226
227 ppir_alu_node *move_alu = ppir_node_to_alu(move);
228 ppir_src *move_src = move_alu->src, *src = alu->src;
229 move_src->type = src->type;
230 move_src->ssa = src->ssa;
231 move_src->swizzle[0] = src->swizzle[0];
232 move_alu->num_src = 1;
233
234 ppir_dest *move_dest = &move_alu->dest;
235 move_dest->type = ppir_target_pipeline;
236 move_dest->pipeline = ppir_pipeline_reg_fmul;
237 move_dest->write_mask = 1;
238
239 ppir_node *pred = alu->src[0].node;
240 ppir_dep *dep = ppir_dep_for_pred(node, pred);
241 if (dep)
242 ppir_node_replace_pred(dep, move);
243 else
244 ppir_node_add_dep(node, move, ppir_dep_src);
245
246 /* pred can be a register */
247 if (pred)
248 ppir_node_add_dep(move, pred, ppir_dep_src);
249
250 src->swizzle[0] = 0;
251 ppir_node_target_assign(alu->src, move);
252
253 return true;
254 }
255
256 static bool ppir_lower_trunc(ppir_block *block, ppir_node *node)
257 {
258 /* Turn it into a mov with a round to integer output modifier */
259 ppir_alu_node *alu = ppir_node_to_alu(node);
260 ppir_dest *move_dest = &alu->dest;
261 move_dest->modifier = ppir_outmod_round;
262 node->op = ppir_op_mov;
263
264 return true;
265 }
266
267 static bool ppir_lower_abs(ppir_block *block, ppir_node *node)
268 {
269 /* Turn it into a mov and set the absolute modifier */
270 ppir_alu_node *alu = ppir_node_to_alu(node);
271
272 assert(alu->num_src == 1);
273
274 alu->src[0].absolute = true;
275 alu->src[0].negate = false;
276 node->op = ppir_op_mov;
277
278 return true;
279 }
280
281 static bool ppir_lower_neg(ppir_block *block, ppir_node *node)
282 {
283 /* Turn it into a mov and set the negate modifier */
284 ppir_alu_node *alu = ppir_node_to_alu(node);
285
286 assert(alu->num_src == 1);
287
288 alu->src[0].negate = !alu->src[0].negate;
289 node->op = ppir_op_mov;
290
291 return true;
292 }
293
294 static bool ppir_lower_sat(ppir_block *block, ppir_node *node)
295 {
296 /* Turn it into a mov with the saturate output modifier */
297 ppir_alu_node *alu = ppir_node_to_alu(node);
298
299 assert(alu->num_src == 1);
300
301 ppir_dest *move_dest = &alu->dest;
302 move_dest->modifier = ppir_outmod_clamp_fraction;
303 node->op = ppir_op_mov;
304
305 return true;
306 }
307
308 static bool ppir_lower_branch(ppir_block *block, ppir_node *node)
309 {
310 ppir_branch_node *branch = ppir_node_to_branch(node);
311
312 /* Unconditional branch */
313 if (branch->num_src == 0)
314 return true;
315
316 ppir_const_node *zero = ppir_node_create(block, ppir_op_const, -1, 0);
317
318 if (!zero)
319 return false;
320
321 zero->constant.value[0].f = 0;
322 zero->constant.num = 1;
323 zero->dest.type = ppir_target_pipeline;
324 zero->dest.pipeline = ppir_pipeline_reg_const0;
325 zero->dest.ssa.num_components = 1;
326 zero->dest.write_mask = 0x01;
327
328 /* For now we're just comparing branch condition with 0,
329 * in future we should look whether it's possible to move
330 * comparision node into branch itself and use current
331 * way as a fallback for complex conditions.
332 */
333 ppir_node_target_assign(&branch->src[1], &zero->node);
334
335 if (branch->negate)
336 branch->cond_eq = true;
337 else {
338 branch->cond_gt = true;
339 branch->cond_lt = true;
340 }
341
342 branch->num_src = 2;
343
344 ppir_node_add_dep(&branch->node, &zero->node, ppir_dep_src);
345 list_addtail(&zero->node.list, &node->list);
346
347 return true;
348 }
349
350 static bool (*ppir_lower_funcs[ppir_op_num])(ppir_block *, ppir_node *) = {
351 [ppir_op_abs] = ppir_lower_abs,
352 [ppir_op_neg] = ppir_lower_neg,
353 [ppir_op_const] = ppir_lower_const,
354 [ppir_op_ddx] = ppir_lower_ddxy,
355 [ppir_op_ddy] = ppir_lower_ddxy,
356 [ppir_op_lt] = ppir_lower_swap_args,
357 [ppir_op_le] = ppir_lower_swap_args,
358 [ppir_op_load_texture] = ppir_lower_texture,
359 [ppir_op_select] = ppir_lower_select,
360 [ppir_op_trunc] = ppir_lower_trunc,
361 [ppir_op_sat] = ppir_lower_sat,
362 [ppir_op_branch] = ppir_lower_branch,
363 [ppir_op_load_uniform] = ppir_lower_load,
364 [ppir_op_load_temp] = ppir_lower_load,
365 };
366
367 bool ppir_lower_prog(ppir_compiler *comp)
368 {
369 list_for_each_entry(ppir_block, block, &comp->block_list, list) {
370 list_for_each_entry_safe(ppir_node, node, &block->node_list, list) {
371 if (ppir_lower_funcs[node->op] &&
372 !ppir_lower_funcs[node->op](block, node))
373 return false;
374 }
375 }
376
377 return true;
378 }