• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2024 Imagination Technologies Ltd.
3  *
4  * SPDX-License-Identifier: MIT
5  */
6 
7 /**
8  * \file pco_group_instrs.c
9  *
10  * \brief PCO instruction grouping pass.
11  */
12 
13 #include "hwdef/rogue_hw_defs.h"
14 #include "pco.h"
15 #include "pco_builder.h"
16 #include "pco_map.h"
17 #include "util/macros.h"
18 
19 #include <stdbool.h>
20 
21 /**
22  * \brief Calculates the decode-assist value for an instruction group.
23  *
24  * \param[in] igrp PCO instruction group.
25  * \return The decode-assist value.
26  */
calc_da(pco_igrp * igrp)27 static inline unsigned calc_da(pco_igrp *igrp)
28 {
29    unsigned da = igrp->enc.len.hdr;
30    bool no_srcs_dests = !igrp->enc.len.lower_srcs &&
31                         !igrp->enc.len.upper_srcs && !igrp->enc.len.dests;
32 
33    switch (igrp->hdr.alutype) {
34    case PCO_ALUTYPE_MAIN:
35    case PCO_ALUTYPE_BITWISE: {
36       for (enum pco_op_phase p = _PCO_OP_PHASE_COUNT; p-- > 0;) {
37          if (igrp->hdr.alutype == PCO_ALUTYPE_BITWISE || p > PCO_OP_PHASE_1)
38             da += igrp->enc.len.instrs[p];
39       }
40       break;
41    }
42 
43    case PCO_ALUTYPE_CONTROL:
44       if (no_srcs_dests)
45          return 0;
46 
47       da += igrp->enc.len.instrs[PCO_OP_PHASE_CTRL];
48       break;
49 
50    default:
51       unreachable();
52    }
53 
54    return da;
55 }
56 
57 /**
58  * \brief Calculates the lengths for an instruction group.
59  *
60  * \param[in,out] igrp PCO instruction group.
61  * \param[in,out] offset_bytes The cumulative shader offset (in bytes).
62  */
calc_lengths(pco_igrp * igrp,unsigned * offset_bytes)63 static inline void calc_lengths(pco_igrp *igrp, unsigned *offset_bytes)
64 {
65    unsigned total_length = 0;
66 
67    igrp->enc.len.hdr = pco_igrp_hdr_bytes(igrp->variant.hdr);
68    total_length += igrp->enc.len.hdr;
69 
70    igrp->enc.len.lower_srcs = pco_src_bytes(igrp->variant.lower_src);
71    total_length += igrp->enc.len.lower_srcs;
72 
73    igrp->enc.len.upper_srcs = pco_src_bytes(igrp->variant.upper_src);
74    total_length += igrp->enc.len.upper_srcs;
75 
76    igrp->enc.len.iss = pco_iss_bytes(igrp->variant.iss);
77    total_length += igrp->enc.len.iss;
78 
79    igrp->enc.len.dests = pco_dst_bytes(igrp->variant.dest);
80    total_length += igrp->enc.len.dests;
81 
82    for (enum pco_op_phase phase = 0; phase < _PCO_OP_PHASE_COUNT; ++phase) {
83       switch (igrp->hdr.alutype) {
84       case PCO_ALUTYPE_MAIN:
85          if (phase == PCO_OP_PHASE_BACKEND) {
86             igrp->enc.len.instrs[phase] =
87                pco_backend_bytes(igrp->variant.instr[phase].backend);
88          } else {
89             igrp->enc.len.instrs[phase] =
90                pco_main_bytes(igrp->variant.instr[phase].main);
91          }
92          break;
93 
94       case PCO_ALUTYPE_BITWISE:
95          igrp->enc.len.instrs[phase] =
96             pco_bitwise_bytes(igrp->variant.instr[phase].bitwise);
97          break;
98 
99       case PCO_ALUTYPE_CONTROL:
100          igrp->enc.len.instrs[phase] =
101             pco_ctrl_bytes(igrp->variant.instr[phase].ctrl);
102          break;
103 
104       default:
105          unreachable();
106       }
107 
108       total_length += igrp->enc.len.instrs[phase];
109    }
110 
111    igrp->enc.len.word_padding = total_length % 2;
112    total_length += igrp->enc.len.word_padding;
113 
114    igrp->enc.len.total = total_length;
115 
116    /* Set igrp header length and decode-assist. */
117    igrp->hdr.length = igrp->enc.len.total / 2;
118    igrp->hdr.da = calc_da(igrp);
119 
120    /* Set offset and update running offset byte count. */
121    igrp->enc.offset = *offset_bytes;
122    *offset_bytes += igrp->enc.len.total;
123 }
124 
125 /**
126  * \brief Calculates the alignment padding to be applied to
127  *        the last instruction group in the shader.
128  *
129  * \param[in,out] last_igrp The last instruction group.
130  * \param[in,out] offset_bytes The cumulative shader offset (in bytes).
131  */
calc_align_padding(pco_igrp * last_igrp,unsigned * offset_bytes)132 static inline void calc_align_padding(pco_igrp *last_igrp,
133                                       unsigned *offset_bytes)
134 {
135    /* We should never end up with a completely empty shader. */
136    assert(last_igrp);
137 
138    unsigned total_align = last_igrp->enc.len.total % ROGUE_ICACHE_ALIGN;
139    unsigned offset_align = last_igrp->enc.offset % ROGUE_ICACHE_ALIGN;
140 
141    if (total_align) {
142       unsigned padding = ROGUE_ICACHE_ALIGN - total_align;
143       *offset_bytes += padding;
144 
145       /* Pad the size of the last igrp. */
146       last_igrp->enc.len.align_padding += padding;
147       last_igrp->enc.len.total += padding;
148 
149       /* Update the last igrp header length. */
150       last_igrp->hdr.length = last_igrp->enc.len.total / 2;
151    }
152 
153    if (offset_align) {
154       unsigned padding = ROGUE_ICACHE_ALIGN - offset_align;
155       *offset_bytes += padding;
156 
157       /* Pad the size of the penultimate igrp. */
158       pco_igrp *penultimate_igrp =
159          list_entry(last_igrp->link.prev, pco_igrp, link);
160 
161       penultimate_igrp->enc.len.align_padding += padding;
162       penultimate_igrp->enc.len.total += padding;
163 
164       /* Update the penultimate igrp header length. */
165       penultimate_igrp->hdr.length = penultimate_igrp->enc.len.total / 2;
166 
167       /* Update the offset of the last igrp. */
168       last_igrp->enc.offset += padding;
169    }
170 }
171 
172 /**
173  * \brief Converts a PCO instruction to an instruction group.
174  *
175  * \param[in] b PCO builder.
176  * \param[in] instr PCO instruction.
177  * \param[out] igrp PCO instruction group.
178  * \param[in,out] offset_bytes The cumulative shader offset (in bytes).
179  */
pco_instr_to_igrp(pco_builder * b,pco_instr * instr,pco_igrp * igrp,unsigned * offset_bytes)180 static void pco_instr_to_igrp(pco_builder *b,
181                               pco_instr *instr,
182                               pco_igrp *igrp,
183                               unsigned *offset_bytes)
184 {
185    pco_map_igrp(igrp, instr);
186    calc_lengths(igrp, offset_bytes);
187    pco_builder_insert_igrp(b, igrp);
188 }
189 
190 /**
191  * \brief Groups PCO instructions into instruction groups.
192  *
193  * \param[in,out] shader PCO shader.
194  * \return True if the pass made progress.
195  */
pco_group_instrs(pco_shader * shader)196 bool pco_group_instrs(pco_shader *shader)
197 {
198    pco_builder b;
199    pco_igrp *igrp = NULL;
200    unsigned offset_bytes = 0;
201 
202    assert(!shader->is_grouped);
203 
204    pco_foreach_func_in_shader (func, shader) {
205       /* TODO: double check that *start* alignment is satisfied by
206        * calc_align_padding when having multiple functions?
207        */
208       pco_foreach_block_in_func (block, func) {
209          b = pco_builder_create(func, pco_cursor_before_block(block));
210          pco_foreach_instr_in_block_safe (instr, block) {
211             igrp = pco_igrp_create(func);
212             pco_instr_to_igrp(&b, instr, igrp, &offset_bytes);
213          }
214       }
215 
216       /* Ensure the final instruction group has a total size and offset
217        * that are a multiple of the icache alignment.
218        */
219       calc_align_padding(igrp, &offset_bytes);
220    }
221 
222    shader->is_grouped = true;
223    return true;
224 }
225