1 /*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * 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 THE
18 * 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 "rogue.h"
25 #include "rogue_builder.h"
26 #include "util/macros.h"
27
28 #include <stdbool.h>
29
30 /**
31 * \file rogue_schedule_instr_groups.c
32 *
33 * \brief Contains the rogue_schedule_instr_groups pass.
34 */
35
rogue_set_io_sel(rogue_instr_group_io_sel * map,enum rogue_alu alu,enum rogue_io io,rogue_ref * ref,bool is_dst)36 static inline void rogue_set_io_sel(rogue_instr_group_io_sel *map,
37 enum rogue_alu alu,
38 enum rogue_io io,
39 rogue_ref *ref,
40 bool is_dst)
41 {
42 /* Skip unassigned I/Os. */
43 if (rogue_ref_is_io_none(ref))
44 return;
45
46 /* Early skip I/Os that have already been assigned (e.g. for grouping). */
47 if (rogue_ref_is_io(ref) && rogue_ref_get_io(ref) == io)
48 return;
49
50 if (alu == ROGUE_ALU_MAIN) {
51 /* Hookup feedthrough outputs to W0 using IS4. */
52 if (is_dst && rogue_io_is_ft(io)) {
53 if (io == ROGUE_IO_FTE) {
54 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS5)) =
55 rogue_ref_io(io);
56 io = ROGUE_IO_W1;
57 } else {
58 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS4)) =
59 rogue_ref_io(io);
60 io = ROGUE_IO_W0;
61 }
62 }
63
64 /* Movc source. */
65 /* TODO: hardcoded to use fte and s1 for now. */
66 if (!is_dst && io == ROGUE_IO_FTE) {
67 enum rogue_io src = ROGUE_IO_S1;
68 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
69 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS4)) = rogue_ref_io(io);
70 io = src;
71 }
72
73 /* Pack source */
74 if (!is_dst && io == ROGUE_IO_IS3) {
75 enum rogue_io src = ROGUE_IO_S0;
76 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
77 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS3)) =
78 rogue_ref_io(ROGUE_IO_FTE);
79 io = src;
80 }
81
82 /* w0/w1 used as sources. */
83 if (!is_dst && rogue_io_is_dst(io)) {
84 enum rogue_io dst_ft =
85 (io == ROGUE_IO_W0 ? ROGUE_IO_IS4 : ROGUE_IO_IS5);
86 enum rogue_io src = ROGUE_IO_S0;
87 *(rogue_instr_group_io_sel_ref(map, dst_ft)) =
88 rogue_ref_io(ROGUE_IO_FTE);
89 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
90 io = src;
91 }
92
93 /* ADD64 fourth source */
94 if (!is_dst && io == ROGUE_IO_IS0) {
95 enum rogue_io src = ROGUE_IO_S3;
96 *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(src);
97 io = src;
98 }
99
100 /* Test source(s). */
101 /* TODO: tidy up. */
102 if (!is_dst && io == ROGUE_IO_IS1) {
103 enum rogue_io src = ROGUE_IO_S0;
104 enum rogue_io ft = ROGUE_IO_FT0;
105
106 /* Already set up. */
107 if (io != ft)
108 *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(ft);
109
110 io = src;
111 }
112
113 if (!is_dst && io == ROGUE_IO_IS2) {
114 enum rogue_io src = ROGUE_IO_S3;
115 enum rogue_io ft = ROGUE_IO_FTE;
116
117 *(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) =
118 rogue_ref_io(ROGUE_IO_S3);
119
120 /* Already set up. */
121 if (io != ft)
122 *(rogue_instr_group_io_sel_ref(map, io)) = rogue_ref_io(ft);
123
124 io = src;
125 }
126 } else if (alu == ROGUE_ALU_BITWISE) {
127 /* TODO: This is temporary because we just have BYP0, do it properly. */
128 if (is_dst)
129 io = ROGUE_IO_W0;
130 }
131
132 /* Set if not already set. */
133 if (rogue_ref_is_null(rogue_instr_group_io_sel_ref(map, io)))
134 *(rogue_instr_group_io_sel_ref(map, io)) = *ref;
135 }
136
137 /* TODO NEXT: Abort if anything in sel map is already set. */
138 /* TODO NEXT: Assert that these are register refs being set. */
139
rogue_lower_alu_io(rogue_alu_instr * alu,rogue_instr_group * group)140 static void rogue_lower_alu_io(rogue_alu_instr *alu, rogue_instr_group *group)
141 {
142 const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
143 enum rogue_instr_phase phase = alu->instr.index;
144
145 for (unsigned u = 0; u < info->num_dsts; ++u) {
146 if (info->phase_io[phase].dst[u] == ROGUE_IO_INVALID)
147 continue;
148
149 rogue_set_io_sel(&group->io_sel,
150 group->header.alu,
151 info->phase_io[phase].dst[u],
152 &alu->dst[u].ref,
153 true);
154 alu->dst[u].ref = rogue_ref_io(info->phase_io[phase].dst[u]);
155 }
156
157 for (unsigned u = 0; u < info->num_srcs; ++u) {
158 if (info->phase_io[phase].src[u] == ROGUE_IO_INVALID)
159 continue;
160
161 rogue_set_io_sel(&group->io_sel,
162 group->header.alu,
163 info->phase_io[phase].src[u],
164 &alu->src[u].ref,
165 false);
166 alu->src[u].ref = rogue_ref_io(info->phase_io[phase].src[u]);
167 }
168 }
169
rogue_lower_backend_io(rogue_backend_instr * backend,rogue_instr_group * group)170 static void rogue_lower_backend_io(rogue_backend_instr *backend,
171 rogue_instr_group *group)
172 {
173 const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
174
175 for (unsigned u = 0; u < info->num_dsts; ++u) {
176 if (info->phase_io.dst[u] == ROGUE_IO_INVALID)
177 continue;
178
179 rogue_set_io_sel(&group->io_sel,
180 group->header.alu,
181 info->phase_io.dst[u],
182 &backend->dst[u].ref,
183 true);
184 backend->dst[u].ref = rogue_ref_io(info->phase_io.dst[u]);
185 }
186
187 for (unsigned u = 0; u < info->num_srcs; ++u) {
188 if (info->phase_io.src[u] == ROGUE_IO_INVALID)
189 continue;
190
191 rogue_set_io_sel(&group->io_sel,
192 group->header.alu,
193 info->phase_io.src[u],
194 &backend->src[u].ref,
195 false);
196 backend->src[u].ref = rogue_ref_io(info->phase_io.src[u]);
197 }
198 }
199
rogue_lower_ctrl_io(rogue_ctrl_instr * ctrl,rogue_instr_group * group)200 static void rogue_lower_ctrl_io(rogue_ctrl_instr *ctrl,
201 rogue_instr_group *group)
202 {
203 /* TODO: Support control instructions with I/O. */
204 }
205
rogue_lower_bitwise_io(rogue_bitwise_instr * bitwise,rogue_instr_group * group)206 static void rogue_lower_bitwise_io(rogue_bitwise_instr *bitwise,
207 rogue_instr_group *group)
208 {
209 const rogue_bitwise_op_info *info = &rogue_bitwise_op_infos[bitwise->op];
210 enum rogue_instr_phase phase = bitwise->instr.index;
211
212 for (unsigned u = 0; u < info->num_dsts; ++u) {
213 if (info->phase_io[phase].dst[u] == ROGUE_IO_INVALID)
214 continue;
215
216 rogue_set_io_sel(&group->io_sel,
217 group->header.alu,
218 info->phase_io[phase].dst[u],
219 &bitwise->dst[u].ref,
220 true);
221 bitwise->dst[u].ref = rogue_ref_io(info->phase_io[phase].dst[u]);
222 }
223
224 for (unsigned u = 0; u < info->num_srcs; ++u) {
225 if (info->phase_io[phase].src[u] == ROGUE_IO_INVALID)
226 continue;
227
228 rogue_set_io_sel(&group->io_sel,
229 group->header.alu,
230 info->phase_io[phase].src[u],
231 &bitwise->src[u].ref,
232 false);
233 bitwise->src[u].ref = rogue_ref_io(info->phase_io[phase].src[u]);
234 }
235 }
236
rogue_lower_instr_group_io(rogue_instr * instr,rogue_instr_group * group)237 static void rogue_lower_instr_group_io(rogue_instr *instr,
238 rogue_instr_group *group)
239 {
240 switch (instr->type) {
241 case ROGUE_INSTR_TYPE_ALU:
242 rogue_lower_alu_io(rogue_instr_as_alu(instr), group);
243 break;
244
245 case ROGUE_INSTR_TYPE_BACKEND:
246 rogue_lower_backend_io(rogue_instr_as_backend(instr), group);
247 break;
248
249 case ROGUE_INSTR_TYPE_CTRL:
250 rogue_lower_ctrl_io(rogue_instr_as_ctrl(instr), group);
251 break;
252
253 case ROGUE_INSTR_TYPE_BITWISE:
254 rogue_lower_bitwise_io(rogue_instr_as_bitwise(instr), group);
255 break;
256
257 default:
258 unreachable("Unsupported instruction group type.");
259 }
260 }
261
262 /* This function uses unreachables rather than asserts because some Rogue IR
263 * instructions are pseudo-instructions that need lowering on certain cores, but
264 * real instructions on others, so these mistakes are more likely to happen.
265 */
rogue_instr_group_put(rogue_instr * instr,rogue_instr_group * group)266 static inline void rogue_instr_group_put(rogue_instr *instr,
267 rogue_instr_group *group)
268 {
269 uint64_t supported_phases = rogue_instr_supported_phases(instr);
270 if (!supported_phases)
271 unreachable("Can't schedule pseudo-instructions.");
272 else if (!util_is_power_of_two_or_zero64(supported_phases))
273 unreachable("Multi-phase instructions unsupported.");
274
275 enum rogue_instr_phase phase =
276 rogue_get_supported_phase(supported_phases, group->header.phases);
277 if (phase == ROGUE_INSTR_PHASE_INVALID)
278 unreachable("Failed to schedule group instruction.");
279
280 /* Update phases. */
281 instr->group = group;
282 instr->index = phase;
283 group->instrs[phase] = instr;
284 group->header.phases |= BITFIELD_BIT(phase);
285
286 /* Ensure we're not mixing and matching repeats! */
287 assert(group->header.repeat == 0 || group->header.repeat == instr->repeat);
288
289 /* Update repeat count. */
290 group->header.repeat = instr->repeat;
291
292 /* Set end flag. */
293 group->header.end = instr->end;
294 instr->end = false;
295
296 /* Ensure we're not mixing and matching execution conditions! */
297 assert(group->header.exec_cond == ROGUE_EXEC_COND_INVALID ||
298 group->header.exec_cond == instr->exec_cond);
299
300 /* Set conditional execution flag. */
301 group->header.exec_cond = instr->exec_cond;
302 instr->exec_cond = ROGUE_EXEC_COND_INVALID;
303
304 /* Lower I/O to sources/destinations/ISS. */
305 rogue_lower_instr_group_io(instr, group);
306 }
307
rogue_move_instr_to_group(rogue_instr * instr,rogue_instr_group * group)308 static inline void rogue_move_instr_to_group(rogue_instr *instr,
309 rogue_instr_group *group)
310 {
311 /* Remove instruction from block instructions list. */
312 list_del(&instr->link);
313
314 /* ralloc_steal instr context from block to instruction group */
315 ralloc_steal(group, instr);
316
317 /* Assign instruction to instruction group. */
318 rogue_instr_group_put(instr, group);
319 }
320
rogue_lower_regs(rogue_shader * shader)321 static void rogue_lower_regs(rogue_shader *shader)
322 {
323 rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_INTERNAL) {
324 rogue_reg_rewrite(shader,
325 reg,
326 ROGUE_REG_CLASS_SPECIAL,
327 reg->index + ROGUE_INTERNAL0_OFFSET);
328 }
329
330 rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_CONST) {
331 rogue_reg_rewrite(shader, reg, ROGUE_REG_CLASS_SPECIAL, reg->index);
332 }
333
334 rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_PIXOUT) {
335 rogue_reg_rewrite(shader,
336 reg,
337 ROGUE_REG_CLASS_SPECIAL,
338 reg->index +
339 (reg->index < ROGUE_PIXOUT_GROUP
340 ? ROGUE_PIXOUT0_OFFSET
341 : (ROGUE_PIXOUT4_OFFSET - ROGUE_PIXOUT_GROUP)));
342 }
343 }
344
rogue_reg_bank_bits(const rogue_ref * ref)345 static unsigned rogue_reg_bank_bits(const rogue_ref *ref)
346 {
347 const rogue_reg *reg;
348
349 if (rogue_ref_is_reg(ref))
350 reg = ref->reg;
351 else if (rogue_ref_is_regarray(ref))
352 reg = ref->regarray->regs[0];
353 else
354 unreachable("Non-register reference.");
355
356 unsigned bits = util_last_bit(rogue_reg_bank_encoding(reg->class));
357 return !bits ? 1 : bits;
358 }
359
rogue_reg_index_bits(const rogue_ref * ref)360 static unsigned rogue_reg_index_bits(const rogue_ref *ref)
361 {
362 const rogue_reg *reg;
363
364 if (rogue_ref_is_reg(ref))
365 reg = ref->reg;
366 else if (rogue_ref_is_regarray(ref))
367 reg = ref->regarray->regs[0];
368 else
369 unreachable("Non-register reference.");
370
371 unsigned bits = util_last_bit(reg->index);
372 return !bits ? 1 : bits;
373 }
374
rogue_calc_dsts_size(rogue_instr_group * group)375 static void rogue_calc_dsts_size(rogue_instr_group *group)
376 {
377 const rogue_instr_group_io_sel *io_sel = &group->io_sel;
378
379 unsigned num_dsts = (!rogue_ref_is_null(&io_sel->dsts[0]) &&
380 !rogue_ref_is_io_none(&io_sel->dsts[0])) +
381 (!rogue_ref_is_null(&io_sel->dsts[1]) &&
382 !rogue_ref_is_io_none(&io_sel->dsts[1]));
383 unsigned bank_bits[ROGUE_ISA_DSTS] = { 0 };
384 unsigned index_bits[ROGUE_ISA_DSTS] = { 0 };
385
386 if (!num_dsts) {
387 return;
388 } else if (num_dsts == 1) {
389 const rogue_ref *dst_ref = !rogue_ref_is_null(&io_sel->dsts[0])
390 ? &io_sel->dsts[0]
391 : &io_sel->dsts[1];
392 bank_bits[0] = rogue_reg_bank_bits(dst_ref);
393 index_bits[0] = rogue_reg_index_bits(dst_ref);
394 } else {
395 bank_bits[0] = rogue_reg_bank_bits(&io_sel->dsts[0]);
396 bank_bits[1] = rogue_reg_bank_bits(&io_sel->dsts[1]);
397 index_bits[0] = rogue_reg_index_bits(&io_sel->dsts[0]);
398 index_bits[1] = rogue_reg_index_bits(&io_sel->dsts[1]);
399 }
400
401 for (unsigned u = 0; u < ROGUE_REG_DST_VARIANTS; ++u) {
402 const rogue_reg_dst_info *info = &rogue_reg_dst_infos[u];
403
404 if ((info->num_dsts < num_dsts) || (info->bank_bits[0] < bank_bits[0]) ||
405 (info->bank_bits[1] < bank_bits[1]) ||
406 (info->index_bits[0] < index_bits[0]) ||
407 (info->index_bits[1] < index_bits[1]))
408 continue;
409
410 group->encode_info.dst_index = u;
411 group->size.dsts = info->bytes;
412 group->size.total += group->size.dsts;
413 return;
414 }
415
416 unreachable("Unable to encode instruction group dsts.");
417 }
418
rogue_calc_iss_size(rogue_instr_group * group)419 static void rogue_calc_iss_size(rogue_instr_group *group)
420 {
421 group->size.iss = (group->header.alu == ROGUE_ALU_MAIN);
422 group->size.total += group->size.iss;
423 }
424
rogue_calc_srcs_size(rogue_instr_group * group,bool upper_srcs)425 static void rogue_calc_srcs_size(rogue_instr_group *group, bool upper_srcs)
426 {
427 const rogue_instr_group_io_sel *io_sel = &group->io_sel;
428 unsigned mux_bits = 0;
429
430 unsigned offset = upper_srcs ? 3 : 0;
431 const rogue_reg_src_info *info_array =
432 upper_srcs ? rogue_reg_upper_src_infos : rogue_reg_lower_src_infos;
433
434 unsigned *src_index = upper_srcs ? &group->encode_info.upper_src_index
435 : &group->encode_info.lower_src_index;
436 unsigned *srcs = upper_srcs ? &group->size.upper_srcs
437 : &group->size.lower_srcs;
438
439 /* Special case: some control instructions have no sources. */
440 if (group->header.alu == ROGUE_ALU_CONTROL) {
441 const rogue_ctrl_instr *ctrl =
442 rogue_instr_as_ctrl(group->instrs[ROGUE_INSTR_PHASE_CTRL]);
443 if (!rogue_ctrl_op_has_srcs(ctrl->op))
444 return;
445 } else if (!upper_srcs && group->header.alu == ROGUE_ALU_MAIN) {
446 /* Special case, IS0 */
447 if (rogue_ref_is_io(&io_sel->iss[0])) {
448 switch (io_sel->iss[0].io) {
449 case ROGUE_IO_S0:
450 mux_bits = 0;
451 break;
452 case ROGUE_IO_S3:
453 mux_bits = 1;
454 break;
455 case ROGUE_IO_S4:
456 mux_bits = 2;
457 break;
458 case ROGUE_IO_S5:
459 mux_bits = 2;
460 break;
461 case ROGUE_IO_S1:
462 mux_bits = 3;
463 break;
464 case ROGUE_IO_S2:
465 mux_bits = 3;
466 break;
467
468 default:
469 unreachable("IS0 set to unsupported value.");
470 }
471 }
472 }
473
474 unsigned num_srcs = 1;
475 if (!rogue_ref_is_null(&io_sel->srcs[2 + offset]))
476 num_srcs = 3;
477 else if (!rogue_ref_is_null(&io_sel->srcs[1 + offset]))
478 num_srcs = 2;
479
480 unsigned bank_bits[ROGUE_ISA_SRCS / 2] = { 0 };
481 unsigned index_bits[ROGUE_ISA_SRCS / 2] = { 0 };
482
483 for (unsigned u = 0; u < ARRAY_SIZE(bank_bits); ++u) {
484 const rogue_ref *src = &io_sel->srcs[u + offset];
485 if (rogue_ref_is_null(src))
486 continue;
487
488 bank_bits[u] = rogue_reg_bank_bits(src);
489 index_bits[u] = rogue_reg_index_bits(src);
490 }
491
492 for (unsigned u = 0; u < ROGUE_REG_SRC_VARIANTS; ++u) {
493 const rogue_reg_src_info *info = &info_array[u];
494
495 if ((info->num_srcs < num_srcs) || (info->mux_bits < mux_bits) ||
496 (info->bank_bits[0] < bank_bits[0]) ||
497 (info->bank_bits[1] < bank_bits[1]) ||
498 (info->bank_bits[2] < bank_bits[2]) ||
499 (info->index_bits[0] < index_bits[0]) ||
500 (info->index_bits[1] < index_bits[1]) ||
501 (info->index_bits[2] < index_bits[2])) {
502 continue;
503 }
504
505 *src_index = u;
506 *srcs = info->bytes;
507 group->size.total += *srcs;
508
509 return;
510 }
511
512 unreachable("Unable to encode instruction group srcs.");
513 }
514
515 #define SM(src_mod) ROGUE_ALU_SRC_MOD_##src_mod
516 #define DM(dst_mod) ROGUE_ALU_DST_MOD_##dst_mod
517 #define OM(op_mod) ROGUE_ALU_OP_MOD_##op_mod
rogue_calc_alu_instrs_size(rogue_instr_group * group,rogue_alu_instr * alu,enum rogue_instr_phase phase)518 static void rogue_calc_alu_instrs_size(rogue_instr_group *group,
519 rogue_alu_instr *alu,
520 enum rogue_instr_phase phase)
521 {
522 switch (alu->op) {
523 /* TODO: All single source have 1 byte and optional extra byte w/ext,
524 * commonise some of these when adding support for more single source
525 * instructions.
526 */
527 case ROGUE_ALU_OP_MBYP:
528 if (rogue_alu_src_mod_is_set(alu, 0, SM(NEG)) ||
529 rogue_alu_src_mod_is_set(alu, 0, SM(ABS))) {
530 group->size.instrs[phase] = 2;
531 } else {
532 group->size.instrs[phase] = 1;
533 }
534 break;
535
536 case ROGUE_ALU_OP_FMUL:
537 group->size.instrs[phase] = 1;
538 break;
539
540 case ROGUE_ALU_OP_FMAD:
541 if (rogue_alu_op_mod_is_set(alu, OM(LP)) ||
542 rogue_alu_src_mod_is_set(alu, 1, SM(ABS)) ||
543 rogue_alu_src_mod_is_set(alu, 1, SM(NEG)) ||
544 rogue_alu_src_mod_is_set(alu, 2, SM(FLR)) ||
545 rogue_alu_src_mod_is_set(alu, 2, SM(ABS))) {
546 group->size.instrs[phase] = 2;
547 } else {
548 group->size.instrs[phase] = 1;
549 }
550 break;
551
552 case ROGUE_ALU_OP_TST:
553 group->size.instrs[phase] = 1;
554
555 if (rogue_alu_op_mod_is_set(alu, OM(L)) ||
556 rogue_alu_op_mod_is_set(alu, OM(LE)) ||
557 !rogue_alu_op_mod_is_set(alu, OM(F32)) ||
558 rogue_alu_src_mod_is_set(alu, 0, SM(E1)) ||
559 rogue_alu_src_mod_is_set(alu, 0, SM(E2)) ||
560 rogue_alu_src_mod_is_set(alu, 0, SM(E3)) ||
561 !rogue_phase_occupied(ROGUE_INSTR_PHASE_2_PCK,
562 group->header.phases)) {
563 group->size.instrs[phase] = 2;
564 }
565 break;
566
567 case ROGUE_ALU_OP_MOVC: {
568 group->size.instrs[phase] = 1;
569
570 bool e0 = rogue_alu_dst_mod_is_set(alu, 0, DM(E0));
571 bool e1 = rogue_alu_dst_mod_is_set(alu, 0, DM(E1));
572 bool e2 = rogue_alu_dst_mod_is_set(alu, 0, DM(E2));
573 bool e3 = rogue_alu_dst_mod_is_set(alu, 0, DM(E3));
574 bool eq = (e0 == e1) && (e0 == e2) && (e0 == e3);
575
576 if ((!rogue_phase_occupied(ROGUE_INSTR_PHASE_2_TST,
577 group->header.phases) &&
578 !rogue_phase_occupied(ROGUE_INSTR_PHASE_2_PCK,
579 group->header.phases)) ||
580 !rogue_ref_is_io_ftt(&alu->src[0].ref) || !eq) {
581 group->size.instrs[phase] = 2;
582 }
583 break;
584 }
585
586 case ROGUE_ALU_OP_PCK_U8888:
587 group->size.instrs[phase] = 2;
588 break;
589
590 case ROGUE_ALU_OP_ADD64:
591 group->size.instrs[phase] = 1;
592
593 if (rogue_ref_is_io_p0(&alu->src[4].ref) ||
594 rogue_alu_src_mod_is_set(alu, 0, SM(ABS)) ||
595 rogue_alu_src_mod_is_set(alu, 0, SM(NEG)) ||
596 rogue_alu_src_mod_is_set(alu, 1, SM(ABS)) ||
597 rogue_alu_src_mod_is_set(alu, 1, SM(NEG)) ||
598 rogue_alu_src_mod_is_set(alu, 2, SM(ABS)))
599 group->size.instrs[phase] = 2;
600 break;
601
602 default:
603 unreachable("Unsupported alu op.");
604 }
605 }
606 #undef OM
607 #undef DM
608 #undef SM
609
610 #define OM(op_mod) BITFIELD64_BIT(ROGUE_BACKEND_OP_MOD_##op_mod)
rogue_backend_cachemode_is_set(const rogue_backend_instr * backend)611 static bool rogue_backend_cachemode_is_set(const rogue_backend_instr *backend)
612 {
613 return !!(backend->mod & (OM(BYPASS) | OM(FORCELINEFILL) | OM(WRITETHROUGH) |
614 OM(WRITEBACK) | OM(LAZYWRITEBACK)));
615 }
616
617 static bool
rogue_backend_slccachemode_is_set(const rogue_backend_instr * backend)618 rogue_backend_slccachemode_is_set(const rogue_backend_instr *backend)
619 {
620 return !!(backend->mod & (OM(SLCBYPASS) | OM(SLCWRITEBACK) |
621 OM(SLCWRITETHROUGH) | OM(SLCNOALLOC)));
622 }
623 #undef OM
624
625 #define OM(op_mod) ROGUE_BACKEND_OP_MOD_##op_mod
rogue_calc_backend_instrs_size(rogue_instr_group * group,rogue_backend_instr * backend,enum rogue_instr_phase phase)626 static void rogue_calc_backend_instrs_size(rogue_instr_group *group,
627 rogue_backend_instr *backend,
628 enum rogue_instr_phase phase)
629 {
630 switch (backend->op) {
631 case ROGUE_BACKEND_OP_FITR_PIXEL:
632 case ROGUE_BACKEND_OP_FITRP_PIXEL:
633 group->size.instrs[phase] = 2;
634 break;
635
636 case ROGUE_BACKEND_OP_UVSW_WRITETHENEMITTHENENDTASK:
637 case ROGUE_BACKEND_OP_UVSW_WRITE:
638 group->size.instrs[phase] = 2;
639 break;
640
641 case ROGUE_BACKEND_OP_UVSW_EMIT:
642 case ROGUE_BACKEND_OP_UVSW_ENDTASK:
643 case ROGUE_BACKEND_OP_UVSW_EMITTHENENDTASK:
644 group->size.instrs[phase] = 1;
645 break;
646
647 case ROGUE_BACKEND_OP_LD:
648 group->size.instrs[phase] = 2;
649
650 if (rogue_ref_is_val(&backend->src[1].ref) ||
651 rogue_backend_slccachemode_is_set(backend)) {
652 group->size.instrs[phase] = 3;
653 }
654 break;
655
656 case ROGUE_BACKEND_OP_ST:
657 group->size.instrs[phase] = 3;
658
659 if (rogue_backend_op_mod_is_set(backend, OM(TILED)) ||
660 rogue_backend_slccachemode_is_set(backend) ||
661 !rogue_ref_is_io_none(&backend->src[5].ref)) {
662 group->size.instrs[phase] = 4;
663 }
664 break;
665
666 case ROGUE_BACKEND_OP_SMP1D:
667 case ROGUE_BACKEND_OP_SMP2D:
668 case ROGUE_BACKEND_OP_SMP3D:
669 group->size.instrs[phase] = 2;
670
671 if (rogue_backend_op_mod_is_set(backend, OM(ARRAY))) {
672 group->size.instrs[phase] = 5;
673 } else if (rogue_backend_op_mod_is_set(backend, OM(WRT)) ||
674 rogue_backend_op_mod_is_set(backend, OM(SCHEDSWAP)) ||
675 rogue_backend_op_mod_is_set(backend, OM(F16)) ||
676 rogue_backend_cachemode_is_set(backend) ||
677 rogue_backend_slccachemode_is_set(backend)) {
678 group->size.instrs[phase] = 4;
679 } else if (rogue_backend_op_mod_is_set(backend, OM(TAO)) ||
680 rogue_backend_op_mod_is_set(backend, OM(SOO)) ||
681 rogue_backend_op_mod_is_set(backend, OM(SNO)) ||
682 rogue_backend_op_mod_is_set(backend, OM(NNCOORDS)) ||
683 rogue_backend_op_mod_is_set(backend, OM(DATA)) ||
684 rogue_backend_op_mod_is_set(backend, OM(INFO)) ||
685 rogue_backend_op_mod_is_set(backend, OM(BOTH)) ||
686 rogue_backend_op_mod_is_set(backend, OM(PROJ)) ||
687 rogue_backend_op_mod_is_set(backend, OM(PPLOD))) {
688 group->size.instrs[phase] = 3;
689 }
690 break;
691
692 case ROGUE_BACKEND_OP_IDF:
693 group->size.instrs[phase] = 2;
694 break;
695
696 case ROGUE_BACKEND_OP_EMITPIX:
697 group->size.instrs[phase] = 1;
698 break;
699
700 default:
701 unreachable("Unsupported backend op.");
702 }
703 }
704 #undef OM
705
rogue_calc_ctrl_instrs_size(rogue_instr_group * group,rogue_ctrl_instr * ctrl,enum rogue_instr_phase phase)706 static void rogue_calc_ctrl_instrs_size(rogue_instr_group *group,
707 rogue_ctrl_instr *ctrl,
708 enum rogue_instr_phase phase)
709 {
710 switch (ctrl->op) {
711 case ROGUE_CTRL_OP_NOP:
712 group->size.instrs[phase] = 1;
713 break;
714
715 case ROGUE_CTRL_OP_WOP:
716 group->size.instrs[phase] = 0;
717 break;
718
719 case ROGUE_CTRL_OP_BR:
720 case ROGUE_CTRL_OP_BA:
721 group->size.instrs[phase] = 5;
722 break;
723
724 case ROGUE_CTRL_OP_WDF:
725 group->size.instrs[phase] = 0;
726 break;
727
728 default:
729 unreachable("Unsupported ctrl op.");
730 }
731 }
732
rogue_calc_bitwise_instrs_size(rogue_instr_group * group,rogue_bitwise_instr * bitwise,enum rogue_instr_phase phase)733 static void rogue_calc_bitwise_instrs_size(rogue_instr_group *group,
734 rogue_bitwise_instr *bitwise,
735 enum rogue_instr_phase phase)
736 {
737 switch (bitwise->op) {
738 case ROGUE_BITWISE_OP_BYP0:
739 group->size.instrs[phase] = 1;
740
741 if (rogue_ref_is_val(&bitwise->src[1].ref)) {
742 group->size.instrs[phase] = 3;
743
744 /* If upper 16 bits aren't zero. */
745 if (rogue_ref_get_val(&bitwise->src[1].ref) & 0xffff0000)
746 group->size.instrs[phase] = 5;
747 }
748 break;
749
750 default:
751 unreachable("Invalid bitwise op.");
752 }
753 }
754
rogue_calc_instrs_size(rogue_instr_group * group)755 static void rogue_calc_instrs_size(rogue_instr_group *group)
756 {
757 rogue_foreach_phase_in_set (p, group->header.phases) {
758 const rogue_instr *instr = group->instrs[p];
759
760 switch (instr->type) {
761 case ROGUE_INSTR_TYPE_ALU:
762 rogue_calc_alu_instrs_size(group, rogue_instr_as_alu(instr), p);
763 break;
764
765 case ROGUE_INSTR_TYPE_BACKEND:
766 rogue_calc_backend_instrs_size(group,
767 rogue_instr_as_backend(instr),
768 p);
769 break;
770
771 case ROGUE_INSTR_TYPE_CTRL:
772 rogue_calc_ctrl_instrs_size(group, rogue_instr_as_ctrl(instr), p);
773 break;
774
775 case ROGUE_INSTR_TYPE_BITWISE:
776 rogue_calc_bitwise_instrs_size(group,
777 rogue_instr_as_bitwise(instr),
778 p);
779 break;
780
781 default:
782 unreachable("Unsupported instruction type.");
783 }
784
785 group->size.total += group->size.instrs[p];
786 }
787 }
788
rogue_calc_header_size(rogue_instr_group * group)789 static void rogue_calc_header_size(rogue_instr_group *group)
790 {
791 group->size.header = 2;
792 if (group->header.alu != ROGUE_ALU_MAIN ||
793 (group->header.end || group->header.repeat > 1 ||
794 group->header.exec_cond > ROGUE_EXEC_COND_P0_TRUE)) {
795 group->size.header = 3;
796 }
797
798 group->size.total += group->size.header;
799 }
800
rogue_calc_padding_size(rogue_instr_group * group)801 static void rogue_calc_padding_size(rogue_instr_group *group)
802 {
803 group->size.word_padding = (group->size.total % 2);
804 group->size.total += group->size.word_padding;
805 }
806
rogue_finalise_instr_group(rogue_instr_group * group)807 static void rogue_finalise_instr_group(rogue_instr_group *group)
808 {
809 rogue_calc_dsts_size(group);
810 rogue_calc_iss_size(group);
811 rogue_calc_srcs_size(group, true);
812 rogue_calc_srcs_size(group, false);
813 rogue_calc_instrs_size(group);
814 rogue_calc_header_size(group);
815 rogue_calc_padding_size(group);
816 }
817
rogue_finalise_shader_offsets(rogue_shader * shader)818 static void rogue_finalise_shader_offsets(rogue_shader *shader)
819 {
820 rogue_instr_group *penultimate_group = NULL;
821 rogue_instr_group *last_group = NULL;
822
823 /* Set instruction group offsets. */
824 unsigned offset = 0;
825 rogue_foreach_instr_group_in_shader (group, shader) {
826 group->size.offset = offset;
827 offset += group->size.total;
828
829 penultimate_group = last_group;
830 last_group = group;
831 }
832
833 /* Ensure the final instruction group has a total size and offset that are a
834 * multiple of the icache alignment. */
835 unsigned total_align = last_group->size.total % ROGUE_ISA_ICACHE_ALIGN;
836 unsigned offset_align = last_group->size.offset % ROGUE_ISA_ICACHE_ALIGN;
837
838 if (total_align) {
839 unsigned padding = ROGUE_ISA_ICACHE_ALIGN - total_align;
840 /* Pad the size of the last instruction. */
841 last_group->size.align_padding += padding;
842 last_group->size.total += padding;
843 }
844
845 if (offset_align) {
846 unsigned padding = ROGUE_ISA_ICACHE_ALIGN - offset_align;
847 /* Pad the size of the penultimate instruction. */
848 penultimate_group->size.align_padding += padding;
849 penultimate_group->size.total += padding;
850 /* Update the offset of the last instruction. */
851 last_group->size.offset += padding;
852 }
853 }
854
855 /* TODO: This just puts single instructions into groups for now. Later we need
856 * to:
857 * - create rules for what instructions can be co-issued/groups.
858 * - schedule/shuffle instructions to get them ready for grouping (also need to
859 * implement ways to stop certain instructions being rearranged, etc. first!)
860 */
861 PUBLIC
rogue_schedule_instr_groups(rogue_shader * shader,bool multi_instr_groups)862 bool rogue_schedule_instr_groups(rogue_shader *shader, bool multi_instr_groups)
863 {
864 if (shader->is_grouped)
865 return false;
866
867 if (multi_instr_groups) {
868 unreachable("Multi instruction groups are unsupported.");
869 return false;
870 }
871
872 rogue_lower_regs(shader);
873
874 rogue_instr_group *group;
875 bool grouping = false;
876 unsigned g = 0;
877 rogue_foreach_block (block, shader) {
878 struct list_head instr_groups;
879 list_inithead(&instr_groups);
880
881 rogue_foreach_instr_in_block_safe (instr, block) {
882 enum rogue_alu group_alu = ROGUE_ALU_INVALID;
883 switch (instr->type) {
884 case ROGUE_INSTR_TYPE_ALU:
885 case ROGUE_INSTR_TYPE_BACKEND:
886 group_alu = ROGUE_ALU_MAIN;
887 break;
888
889 case ROGUE_INSTR_TYPE_CTRL:
890 group_alu = ROGUE_ALU_CONTROL;
891 break;
892
893 case ROGUE_INSTR_TYPE_BITWISE:
894 group_alu = ROGUE_ALU_BITWISE;
895 break;
896
897 default:
898 unreachable("Unsupported instruction type.");
899 }
900
901 if (!grouping) {
902 group = rogue_instr_group_create(block, group_alu);
903 group->index = g++;
904 }
905
906 assert(group_alu == group->header.alu);
907 rogue_move_instr_to_group(instr, group);
908
909 grouping = instr->group_next;
910
911 if (!grouping) {
912 rogue_finalise_instr_group(group);
913 list_addtail(&group->link, &instr_groups);
914 }
915 }
916
917 list_replace(&instr_groups, &block->instrs);
918 }
919
920 shader->next_instr = g;
921 shader->is_grouped = true;
922
923 rogue_finalise_shader_offsets(shader);
924
925 return true;
926 }
927