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