pan/midgard: Add mir_insert_instruction*scheduled helpers
[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->src); ++i) {
30 if (ins->src[i] == old)
31 ins->src[i] = new;
32 }
33 }
34
35 void mir_rewrite_index_dst_single(midgard_instruction *ins, unsigned old, unsigned new)
36 {
37 if (ins->dest == old)
38 ins->dest = new;
39 }
40
41 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 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->src); ++i) {
148 if (ins->src[i] != old) continue;
149
150 ins->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->dest == old)
202 ins->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 /* We can replicate constants in places so who cares */
235 if (value == SSA_FIXED_REGISTER(REGISTER_CONSTANT))
236 return true;
237
238 return mir_use_count(ctx, value) <= 1;
239 }
240
241 static bool
242 mir_nontrivial_raw_mod(midgard_vector_alu_src src, bool is_int)
243 {
244 if (is_int)
245 return src.mod == midgard_int_shift;
246 else
247 return src.mod;
248 }
249
250 bool
251 mir_nontrivial_mod(midgard_vector_alu_src src, bool is_int, unsigned mask)
252 {
253 if (mir_nontrivial_raw_mod(src, is_int)) return true;
254
255 /* size-conversion */
256 if (src.half) return true;
257
258 /* swizzle */
259 for (unsigned c = 0; c < 4; ++c) {
260 if (!(mask & (1 << c))) continue;
261 if (((src.swizzle >> (2*c)) & 3) != c) return true;
262 }
263
264 return false;
265 }
266
267 bool
268 mir_nontrivial_source2_mod(midgard_instruction *ins)
269 {
270 bool is_int = midgard_is_integer_op(ins->alu.op);
271
272 midgard_vector_alu_src src2 =
273 vector_alu_from_unsigned(ins->alu.src2);
274
275 return mir_nontrivial_mod(src2, is_int, ins->mask);
276 }
277
278 bool
279 mir_nontrivial_source2_mod_simple(midgard_instruction *ins)
280 {
281 bool is_int = midgard_is_integer_op(ins->alu.op);
282
283 midgard_vector_alu_src src2 =
284 vector_alu_from_unsigned(ins->alu.src2);
285
286 return mir_nontrivial_raw_mod(src2, is_int) || src2.half;
287 }
288
289 bool
290 mir_nontrivial_outmod(midgard_instruction *ins)
291 {
292 bool is_int = midgard_is_integer_op(ins->alu.op);
293 unsigned mod = ins->alu.outmod;
294
295 /* Pseudo-outmod */
296 if (ins->invert)
297 return true;
298
299 /* Type conversion is a sort of outmod */
300 if (ins->alu.dest_override != midgard_dest_override_none)
301 return true;
302
303 if (is_int)
304 return mod != midgard_outmod_int_wrap;
305 else
306 return mod != midgard_outmod_none;
307 }
308
309 /* Checks if an index will be used as a special register -- basically, if we're
310 * used as the input to a non-ALU op */
311
312 bool
313 mir_special_index(compiler_context *ctx, unsigned idx)
314 {
315 mir_foreach_instr_global(ctx, ins) {
316 bool is_ldst = ins->type == TAG_LOAD_STORE_4;
317 bool is_tex = ins->type == TAG_TEXTURE_4;
318
319 if (!(is_ldst || is_tex))
320 continue;
321
322 if (mir_has_arg(ins, idx))
323 return true;
324 }
325
326 return false;
327 }
328
329 /* Is a node written before a given instruction? */
330
331 bool
332 mir_is_written_before(compiler_context *ctx, midgard_instruction *ins, unsigned node)
333 {
334 if (node >= SSA_FIXED_MINIMUM)
335 return true;
336
337 mir_foreach_instr_global(ctx, q) {
338 if (q == ins)
339 break;
340
341 if (q->dest == node)
342 return true;
343 }
344
345 return false;
346 }
347
348 /* Creates a mask of the components of a node read by an instruction, by
349 * analyzing the swizzle with respect to the instruction's mask. E.g.:
350 *
351 * fadd r0.xz, r1.yyyy, r2.zwyx
352 *
353 * will return a mask of Z/Y for r2
354 */
355
356 static unsigned
357 mir_mask_of_read_components_single(unsigned swizzle, unsigned outmask)
358 {
359 unsigned mask = 0;
360
361 for (unsigned c = 0; c < 4; ++c) {
362 if (!(outmask & (1 << c))) continue;
363
364 unsigned comp = (swizzle >> (2*c)) & 3;
365 mask |= (1 << comp);
366 }
367
368 return mask;
369 }
370
371 static unsigned
372 mir_source_count(midgard_instruction *ins)
373 {
374 if (ins->type == TAG_ALU_4) {
375 /* ALU is always binary */
376 return 2;
377 } else if (ins->type == TAG_LOAD_STORE_4) {
378 bool load = !OP_IS_STORE(ins->load_store.op);
379 return (load ? 2 : 3);
380 } else if (ins->type == TAG_TEXTURE_4) {
381 /* Coords, bias.. TODO: Offsets? */
382 return 2;
383 } else {
384 unreachable("Invalid instruction type");
385 }
386 }
387
388 static unsigned
389 mir_component_count_implicit(midgard_instruction *ins, unsigned i)
390 {
391 if (ins->type == TAG_LOAD_STORE_4) {
392 switch (ins->load_store.op) {
393 /* Address implicitly 64-bit */
394 case midgard_op_ld_int4:
395 return (i == 0) ? 1 : 0;
396
397 case midgard_op_st_int4:
398 return (i == 1) ? 1 : 0;
399
400 default:
401 return 0;
402 }
403 }
404
405 return 0;
406 }
407
408 unsigned
409 mir_mask_of_read_components(midgard_instruction *ins, unsigned node)
410 {
411 unsigned mask = 0;
412
413 for (unsigned i = 0; i < mir_source_count(ins); ++i) {
414 if (ins->src[i] != node) continue;
415
416 unsigned swizzle = mir_get_swizzle(ins, i);
417 unsigned m = mir_mask_of_read_components_single(swizzle, ins->mask);
418
419 /* Sometimes multi-arg ops are passed implicitly */
420 unsigned implicit = mir_component_count_implicit(ins, i);
421 assert(implicit < 2);
422
423 /* Extend the mask */
424 if (implicit == 1) {
425 /* Ensure it's a single bit currently */
426 assert((m >> __builtin_ctz(m)) == 0x1);
427
428 /* Set the next bit to extend one*/
429 m |= (m << 1);
430 }
431
432 mask |= m;
433 }
434
435 return mask;
436 }
437
438 unsigned
439 mir_ubo_shift(midgard_load_store_op op)
440 {
441 switch (op) {
442 case midgard_op_ld_ubo_char:
443 return 0;
444 case midgard_op_ld_ubo_char2:
445 return 1;
446 case midgard_op_ld_ubo_char4:
447 return 2;
448 case midgard_op_ld_ubo_short4:
449 return 3;
450 case midgard_op_ld_ubo_int4:
451 return 4;
452 default:
453 unreachable("Invalid op");
454 }
455 }
456
457 /* Register allocation occurs after instruction scheduling, which is fine until
458 * we start needing to spill registers and therefore insert instructions into
459 * an already-scheduled program. We don't have to be terribly efficient about
460 * this, since spilling is already slow. So just semantically we need to insert
461 * the instruction into a new bundle before/after the bundle of the instruction
462 * in question */
463
464 static midgard_bundle
465 mir_bundle_for_op(compiler_context *ctx, midgard_instruction ins)
466 {
467 midgard_instruction *u = mir_upload_ins(ctx, ins);
468
469 midgard_bundle bundle = {
470 .tag = ins.type,
471 .instruction_count = 1,
472 .instructions = { u },
473 };
474
475 if (bundle.tag == TAG_ALU_4) {
476 assert(OP_IS_MOVE(u->alu.op));
477 u->unit = UNIT_VMUL;
478
479 size_t bytes_emitted = sizeof(uint32_t) + sizeof(midgard_reg_info) + sizeof(midgard_vector_alu);
480 bundle.padding = ~(bytes_emitted - 1) & 0xF;
481 bundle.control = ins.type | u->unit;
482 }
483
484 return bundle;
485 }
486
487 static unsigned
488 mir_bundle_idx_for_ins(midgard_instruction *tag, midgard_block *block)
489 {
490 midgard_bundle *bundles =
491 (midgard_bundle *) block->bundles.data;
492
493 size_t count = (block->bundles.size / sizeof(midgard_bundle));
494
495 for (unsigned i = 0; i < count; ++i) {
496 for (unsigned j = 0; j < bundles[i].instruction_count; ++j) {
497 if (bundles[i].instructions[j] == tag)
498 return i;
499 }
500 }
501
502 mir_print_instruction(tag);
503 unreachable("Instruction not scheduled in block");
504 }
505
506 void
507 mir_insert_instruction_before_scheduled(
508 compiler_context *ctx,
509 midgard_block *block,
510 midgard_instruction *tag,
511 midgard_instruction ins)
512 {
513 unsigned before = mir_bundle_idx_for_ins(tag, block);
514 size_t count = util_dynarray_num_elements(&block->bundles, midgard_bundle);
515 UNUSED void *unused = util_dynarray_grow(&block->bundles, midgard_bundle, 1);
516
517 midgard_bundle *bundles = (midgard_bundle *) block->bundles.data;
518 memmove(bundles + before + 1, bundles + before, (count - before) * sizeof(midgard_bundle));
519 midgard_bundle *before_bundle = bundles + before + 1;
520
521 midgard_bundle new = mir_bundle_for_op(ctx, ins);
522 memcpy(bundles + before, &new, sizeof(new));
523
524 list_addtail(&new.instructions[0]->link, &before_bundle->instructions[0]->link);
525 }
526
527 void
528 mir_insert_instruction_after_scheduled(
529 compiler_context *ctx,
530 midgard_block *block,
531 midgard_instruction *tag,
532 midgard_instruction ins)
533 {
534 unsigned after = mir_bundle_idx_for_ins(tag, block);
535 size_t count = util_dynarray_num_elements(&block->bundles, midgard_bundle);
536 UNUSED void *unused = util_dynarray_grow(&block->bundles, midgard_bundle, 1);
537
538 midgard_bundle *bundles = (midgard_bundle *) block->bundles.data;
539 memmove(bundles + after + 2, bundles + after + 1, (count - after - 1) * sizeof(midgard_bundle));
540 midgard_bundle *after_bundle_1 = bundles + after + 2;
541
542 midgard_bundle new = mir_bundle_for_op(ctx, ins);
543 memcpy(bundles + after + 1, &new, sizeof(new));
544 list_addtail(&new.instructions[0]->link, &after_bundle_1->instructions[0]->link);
545 }