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