pan/midgard: Add mir_foreach_successor helper
[mesa.git] / src / panfrost / midgard / mir.c
1 /*
2 * Copyright (C) 2019 Alyssa Rosenzweig <alyssa@rosenzweig.io>
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, sublicense,
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 next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * 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 NONINFRINGEMENT. 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 FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #include "compiler.h"
25 #include "midgard_ops.h"
26
27 void mir_rewrite_index_src_single(midgard_instruction *ins, unsigned old, unsigned new)
28 {
29 for (unsigned i = 0; i < ARRAY_SIZE(ins->ssa_args.src); ++i) {
30 if (ins->ssa_args.src[i] == old)
31 ins->ssa_args.src[i] = new;
32 }
33 }
34
35 static unsigned
36 mir_get_swizzle(midgard_instruction *ins, unsigned idx)
37 {
38 if (ins->type == TAG_ALU_4) {
39 unsigned b = (idx == 0) ? ins->alu.src1 : ins->alu.src2;
40
41 midgard_vector_alu_src s =
42 vector_alu_from_unsigned(b);
43
44 return s.swizzle;
45 } else if (ins->type == TAG_LOAD_STORE_4) {
46 /* Main swizzle of a load is on the destination */
47 if (!OP_IS_STORE(ins->load_store.op))
48 idx++;
49
50 switch (idx) {
51 case 0:
52 return ins->load_store.swizzle;
53 case 1:
54 case 2: {
55 uint8_t raw =
56 (idx == 2) ? ins->load_store.arg_2 : ins->load_store.arg_1;
57
58 return component_to_swizzle(midgard_ldst_select(raw).component);
59 }
60 default:
61 unreachable("Unknown load/store source");
62 }
63 } else if (ins->type == TAG_TEXTURE_4) {
64 switch (idx) {
65 case 0:
66 return ins->texture.in_reg_swizzle;
67 case 1:
68 /* Swizzle on bias doesn't make sense */
69 return 0;
70 default:
71 unreachable("Unknown texture source");
72 }
73 } else {
74 unreachable("Unknown type");
75 }
76 }
77
78 static void
79 mir_set_swizzle(midgard_instruction *ins, unsigned idx, unsigned new)
80 {
81 if (ins->type == TAG_ALU_4) {
82 unsigned b = (idx == 0) ? ins->alu.src1 : ins->alu.src2;
83
84 midgard_vector_alu_src s =
85 vector_alu_from_unsigned(b);
86
87 s.swizzle = new;
88 unsigned pack = vector_alu_srco_unsigned(s);
89
90 if (idx == 0)
91 ins->alu.src1 = pack;
92 else
93 ins->alu.src2 = pack;
94 } else if (ins->type == TAG_LOAD_STORE_4) {
95 /* Main swizzle of a load is on the destination */
96 if (!OP_IS_STORE(ins->load_store.op))
97 idx++;
98
99 switch (idx) {
100 case 0:
101 ins->load_store.swizzle = new;
102 break;
103 case 1:
104 case 2: {
105 uint8_t raw =
106 (idx == 2) ? ins->load_store.arg_2 : ins->load_store.arg_1;
107
108 midgard_ldst_register_select sel
109 = midgard_ldst_select(raw);
110 sel.component = swizzle_to_component(new);
111 uint8_t packed = midgard_ldst_pack(sel);
112
113 if (idx == 2)
114 ins->load_store.arg_2 = packed;
115 else
116 ins->load_store.arg_1 = packed;
117
118 break;
119 }
120 default:
121 assert(new == 0);
122 break;
123 }
124 } else if (ins->type == TAG_TEXTURE_4) {
125 switch (idx) {
126 case 0:
127 ins->texture.in_reg_swizzle = new;
128 break;
129 default:
130 assert(new == 0);
131 break;
132 }
133 } else {
134 unreachable("Unknown type");
135 }
136 }
137
138 static void
139 mir_rewrite_index_src_single_swizzle(midgard_instruction *ins, unsigned old, unsigned new, unsigned swizzle)
140 {
141 for (unsigned i = 0; i < ARRAY_SIZE(ins->ssa_args.src); ++i) {
142 if (ins->ssa_args.src[i] != old) continue;
143
144 ins->ssa_args.src[i] = new;
145
146 mir_set_swizzle(ins, i,
147 pan_compose_swizzle(mir_get_swizzle(ins, i), swizzle));
148 }
149 }
150
151 void
152 mir_rewrite_index_src(compiler_context *ctx, unsigned old, unsigned new)
153 {
154 mir_foreach_instr_global(ctx, ins) {
155 mir_rewrite_index_src_single(ins, old, new);
156 }
157 }
158
159 void
160 mir_rewrite_index_src_swizzle(compiler_context *ctx, unsigned old, unsigned new, unsigned swizzle)
161 {
162 mir_foreach_instr_global(ctx, ins) {
163 mir_rewrite_index_src_single_swizzle(ins, old, new, swizzle);
164 }
165 }
166
167 void
168 mir_rewrite_index_src_tag(compiler_context *ctx, unsigned old, unsigned new, unsigned tag)
169 {
170 mir_foreach_instr_global(ctx, ins) {
171 if (ins->type != tag)
172 continue;
173
174 mir_rewrite_index_src_single(ins, old, new);
175 }
176 }
177
178
179
180 void
181 mir_rewrite_index_dst(compiler_context *ctx, unsigned old, unsigned new)
182 {
183 mir_foreach_instr_global(ctx, ins) {
184 if (ins->ssa_args.dest == old)
185 ins->ssa_args.dest = new;
186 }
187 }
188
189 void
190 mir_rewrite_index_dst_tag(compiler_context *ctx, unsigned old, unsigned new, unsigned tag)
191 {
192 mir_foreach_instr_global(ctx, ins) {
193 if (ins->type != tag)
194 continue;
195
196 if (ins->ssa_args.dest == old)
197 ins->ssa_args.dest = new;
198 }
199 }
200
201
202
203 void
204 mir_rewrite_index(compiler_context *ctx, unsigned old, unsigned new)
205 {
206 mir_rewrite_index_src(ctx, old, new);
207 mir_rewrite_index_dst(ctx, old, new);
208 }
209
210 unsigned
211 mir_use_count(compiler_context *ctx, unsigned value)
212 {
213 unsigned used_count = 0;
214
215 mir_foreach_instr_global(ctx, ins) {
216 if (mir_has_arg(ins, value))
217 ++used_count;
218 }
219
220 return used_count;
221 }
222
223 /* Checks if a value is used only once (or totally dead), which is an important
224 * heuristic to figure out if certain optimizations are Worth It (TM) */
225
226 bool
227 mir_single_use(compiler_context *ctx, unsigned value)
228 {
229 return mir_use_count(ctx, value) <= 1;
230 }
231
232 static bool
233 mir_nontrivial_raw_mod(midgard_vector_alu_src src, bool is_int)
234 {
235 if (is_int)
236 return src.mod == midgard_int_shift;
237 else
238 return src.mod;
239 }
240
241 bool
242 mir_nontrivial_mod(midgard_vector_alu_src src, bool is_int, unsigned mask)
243 {
244 if (mir_nontrivial_raw_mod(src, is_int)) return true;
245
246 /* size-conversion */
247 if (src.half) return true;
248
249 /* swizzle */
250 for (unsigned c = 0; c < 4; ++c) {
251 if (!(mask & (1 << c))) continue;
252 if (((src.swizzle >> (2*c)) & 3) != c) return true;
253 }
254
255 return false;
256 }
257
258 bool
259 mir_nontrivial_source2_mod(midgard_instruction *ins)
260 {
261 bool is_int = midgard_is_integer_op(ins->alu.op);
262
263 midgard_vector_alu_src src2 =
264 vector_alu_from_unsigned(ins->alu.src2);
265
266 return mir_nontrivial_mod(src2, is_int, ins->mask);
267 }
268
269 bool
270 mir_nontrivial_source2_mod_simple(midgard_instruction *ins)
271 {
272 bool is_int = midgard_is_integer_op(ins->alu.op);
273
274 midgard_vector_alu_src src2 =
275 vector_alu_from_unsigned(ins->alu.src2);
276
277 return mir_nontrivial_raw_mod(src2, is_int) || src2.half;
278 }
279
280 bool
281 mir_nontrivial_outmod(midgard_instruction *ins)
282 {
283 bool is_int = midgard_is_integer_op(ins->alu.op);
284 unsigned mod = ins->alu.outmod;
285
286 /* Pseudo-outmod */
287 if (ins->invert)
288 return true;
289
290 /* Type conversion is a sort of outmod */
291 if (ins->alu.dest_override != midgard_dest_override_none)
292 return true;
293
294 if (is_int)
295 return mod != midgard_outmod_int_wrap;
296 else
297 return mod != midgard_outmod_none;
298 }
299
300 /* Checks if an index will be used as a special register -- basically, if we're
301 * used as the input to a non-ALU op */
302
303 bool
304 mir_special_index(compiler_context *ctx, unsigned idx)
305 {
306 mir_foreach_instr_global(ctx, ins) {
307 bool is_ldst = ins->type == TAG_LOAD_STORE_4;
308 bool is_tex = ins->type == TAG_TEXTURE_4;
309
310 if (!(is_ldst || is_tex))
311 continue;
312
313 if (mir_has_arg(ins, idx))
314 return true;
315 }
316
317 return false;
318 }
319
320 /* Is a node written before a given instruction? */
321
322 bool
323 mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node)
324 {
325 if ((node < 0) || (node >= SSA_FIXED_MINIMUM))
326 return true;
327
328 mir_foreach_instr_global(ctx, q) {
329 if (q == ins)
330 break;
331
332 if (q->ssa_args.dest == node)
333 return true;
334 }
335
336 return false;
337 }
338
339 /* Creates a mask of the components of a node read by an instruction, by
340 * analyzing the swizzle with respect to the instruction's mask. E.g.:
341 *
342 * fadd r0.xz, r1.yyyy, r2.zwyx
343 *
344 * will return a mask of Z/Y for r2
345 */
346
347 static unsigned
348 mir_mask_of_read_components_single(unsigned swizzle, unsigned outmask)
349 {
350 unsigned mask = 0;
351
352 for (unsigned c = 0; c < 4; ++c) {
353 if (!(outmask & (1 << c))) continue;
354
355 unsigned comp = (swizzle >> (2*c)) & 3;
356 mask |= (1 << comp);
357 }
358
359 return mask;
360 }
361
362 static unsigned
363 mir_source_count(midgard_instruction *ins)
364 {
365 if (ins->type == TAG_ALU_4) {
366 /* ALU is always binary */
367 return 2;
368 } else if (ins->type == TAG_LOAD_STORE_4) {
369 bool load = !OP_IS_STORE(ins->load_store.op);
370 return (load ? 2 : 3);
371 } else if (ins->type == TAG_TEXTURE_4) {
372 /* Coords, bias.. TODO: Offsets? */
373 return 2;
374 } else {
375 unreachable("Invalid instruction type");
376 }
377 }
378
379 static unsigned
380 mir_component_count_implicit(midgard_instruction *ins, unsigned i)
381 {
382 if (ins->type == TAG_LOAD_STORE_4) {
383 switch (ins->load_store.op) {
384 /* Address implicitly 64-bit */
385 case midgard_op_ld_int4:
386 return (i == 0) ? 1 : 0;
387
388 case midgard_op_st_int4:
389 return (i == 1) ? 1 : 0;
390
391 default:
392 return 0;
393 }
394 }
395
396 return 0;
397 }
398
399 unsigned
400 mir_mask_of_read_components(midgard_instruction *ins, unsigned node)
401 {
402 unsigned mask = 0;
403
404 for (unsigned i = 0; i < mir_source_count(ins); ++i) {
405 if (ins->ssa_args.src[i] != node) continue;
406
407 unsigned swizzle = mir_get_swizzle(ins, i);
408 unsigned m = mir_mask_of_read_components_single(swizzle, ins->mask);
409
410 /* Sometimes multi-arg ops are passed implicitly */
411 unsigned implicit = mir_component_count_implicit(ins, i);
412 assert(implicit < 2);
413
414 /* Extend the mask */
415 if (implicit == 1) {
416 /* Ensure it's a single bit currently */
417 assert((m >> __builtin_ctz(m)) == 0x1);
418
419 /* Set the next bit to extend one*/
420 m |= (m << 1);
421 }
422
423 mask |= m;
424 }
425
426 return mask;
427 }
428
429 unsigned
430 mir_ubo_shift(midgard_load_store_op op)
431 {
432 switch (op) {
433 case midgard_op_ld_ubo_char:
434 return 0;
435 case midgard_op_ld_ubo_char2:
436 return 1;
437 case midgard_op_ld_ubo_char4:
438 return 2;
439 case midgard_op_ld_ubo_short4:
440 return 3;
441 case midgard_op_ld_ubo_int4:
442 return 4;
443 default:
444 unreachable("Invalid op");
445 }
446 }
447
448