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