xref: /aosp_15_r20/external/mesa3d/src/imagination/rogue/passes/rogue_schedule_instr_groups.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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