1 /*
2 * Copyright © 2020 Google, Inc.
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 "util/log.h"
25 #include "util/u_math.h"
26
27 #include "ir3/ir3.h"
28 #include "ir3/ir3_shader.h"
29 #include "ir3/instr-a3xx.h" // TODO move opc's and other useful things to ir3-instr.h or so
30
31 #include "isa.h"
32
33 struct bitset_params;
34
35 struct encode_state {
36 unsigned gen;
37
38 struct ir3_compiler *compiler;
39
40 /**
41 * The instruction which is currently being encoded
42 */
43 struct ir3_instruction *instr;
44 };
45
46 /*
47 * Helpers defining how to map from ir3_instruction/ir3_register/etc to fields
48 * to be encoded:
49 */
50
51 static inline bool
extract_SRC1_R(struct ir3_instruction * instr)52 extract_SRC1_R(struct ir3_instruction *instr)
53 {
54 if (instr->nop) {
55 assert(!instr->repeat);
56 return instr->nop & 0x1;
57 }
58 return !!(instr->srcs[0]->flags & IR3_REG_R);
59 }
60
61 static inline bool
extract_SRC2_R(struct ir3_instruction * instr)62 extract_SRC2_R(struct ir3_instruction *instr)
63 {
64 if (instr->nop) {
65 assert(!instr->repeat);
66 return (instr->nop >> 1) & 0x1;
67 }
68 /* src2 does not appear in all cat2, but SRC2_R does (for nop encoding) */
69 if (instr->srcs_count > 1)
70 return !!(instr->srcs[1]->flags & IR3_REG_R);
71 return 0;
72 }
73
74 static inline opc_t
__instruction_case(struct encode_state * s,struct ir3_instruction * instr)75 __instruction_case(struct encode_state *s, struct ir3_instruction *instr)
76 {
77 /*
78 * Temporary hack.. the new world doesn't map opcodes directly to hw
79 * encoding, so there are some cases where we need to fixup the opc
80 * to match what the encoder expects. Eventually this will go away
81 * once we completely transition away from the packed-struct encoding/
82 * decoding and split up things which are logically different
83 * instructions
84 */
85 if (instr->opc == OPC_B) {
86 switch (instr->cat0.brtype) {
87 case BRANCH_PLAIN:
88 return OPC_BR;
89 case BRANCH_OR:
90 return OPC_BRAO;
91 case BRANCH_AND:
92 return OPC_BRAA;
93 case BRANCH_CONST:
94 return OPC_BRAC;
95 case BRANCH_ANY:
96 return OPC_BANY;
97 case BRANCH_ALL:
98 return OPC_BALL;
99 case BRANCH_X:
100 return OPC_BRAX;
101 }
102 } else if (instr->opc == OPC_MOV) {
103 struct ir3_register *src = instr->srcs[0];
104 if (src->flags & IR3_REG_IMMED) {
105 return OPC_MOV_IMMED;
106 } if (src->flags & IR3_REG_RELATIV) {
107 if (src->flags & IR3_REG_CONST) {
108 return OPC_MOV_RELCONST;
109 } else {
110 return OPC_MOV_RELGPR;
111 }
112 } else if (src->flags & IR3_REG_CONST) {
113 return OPC_MOV_CONST;
114 } else {
115 return OPC_MOV_GPR;
116 }
117 } else if (instr->opc == OPC_DEMOTE) {
118 return OPC_KILL;
119 } else if (s->compiler->gen >= 6) {
120 if (instr->opc == OPC_RESINFO) {
121 return OPC_RESINFO_B;
122 } else if (instr->opc == OPC_LDIB) {
123 return OPC_LDIB_B;
124 } else if (instr->opc == OPC_STIB) {
125 return OPC_STIB_B;
126 }
127 }
128 return instr->opc;
129 }
130
131 static inline unsigned
extract_ABSNEG(struct ir3_register * reg)132 extract_ABSNEG(struct ir3_register *reg)
133 {
134 // TODO generate enums for this:
135 if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)) {
136 if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) {
137 return 3; // ABSNEG
138 } else {
139 return 1; // NEG
140 }
141 } else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) {
142 return 2; // ABS
143 } else {
144 return 0;
145 }
146 }
147
148 static inline int32_t
extract_reg_iim(struct ir3_register * reg)149 extract_reg_iim(struct ir3_register *reg)
150 {
151 assert(reg->flags & IR3_REG_IMMED);
152 return reg->iim_val;
153 }
154
155 static inline uint32_t
extract_reg_uim(struct ir3_register * reg)156 extract_reg_uim(struct ir3_register *reg)
157 {
158 assert(reg->flags & IR3_REG_IMMED);
159 return reg->uim_val;
160 }
161
162 /**
163 * This is a bit messy, to deal with the fact that the optional "s2en"
164 * src is the first src, shifting everything else up by one.
165 *
166 * TODO revisit this once legacy 'packed struct' encoding is gone
167 */
168 static inline struct ir3_register *
extract_cat5_SRC(struct ir3_instruction * instr,unsigned n)169 extract_cat5_SRC(struct ir3_instruction *instr, unsigned n)
170 {
171 if (instr->flags & IR3_INSTR_S2EN) {
172 n++;
173 }
174 if (n < instr->srcs_count)
175 return instr->srcs[n];
176 return NULL;
177 }
178
179 static inline bool
extract_cat5_FULL(struct ir3_instruction * instr)180 extract_cat5_FULL(struct ir3_instruction *instr)
181 {
182 struct ir3_register *reg = extract_cat5_SRC(instr, 0);
183 /* some cat5 have zero src regs, in which case 'FULL' is false */
184 if (!reg)
185 return false;
186 return !(reg->flags & IR3_REG_HALF);
187 }
188
189 static inline cat5_desc_mode_t
extract_cat5_DESC_MODE(struct ir3_instruction * instr)190 extract_cat5_DESC_MODE(struct ir3_instruction *instr)
191 {
192 assert(instr->flags & (IR3_INSTR_S2EN | IR3_INSTR_B));
193 if (instr->flags & IR3_INSTR_S2EN) {
194 if (instr->flags & IR3_INSTR_B) {
195 if (instr->flags & IR3_INSTR_A1EN) {
196 if (instr->flags & IR3_INSTR_NONUNIF) {
197 return CAT5_BINDLESS_A1_NONUNIFORM;
198 } else {
199 return CAT5_BINDLESS_A1_UNIFORM;
200 }
201 } else if (instr->flags & IR3_INSTR_NONUNIF) {
202 return CAT5_BINDLESS_NONUNIFORM;
203 } else {
204 return CAT5_BINDLESS_UNIFORM;
205 }
206 } else {
207 if (instr->flags & IR3_INSTR_NONUNIF)
208 return CAT5_NONUNIFORM;
209 else
210 return CAT5_UNIFORM;
211 }
212 assert(!(instr->cat5.samp | instr->cat5.tex));
213 } else if (instr->flags & IR3_INSTR_B) {
214 if (instr->flags & IR3_INSTR_A1EN) {
215 return CAT5_BINDLESS_A1_IMM;
216 } else {
217 return CAT5_BINDLESS_IMM;
218 }
219 }
220 return 0;
221 }
222
223 static inline unsigned
extract_cat6_DESC_MODE(struct ir3_instruction * instr)224 extract_cat6_DESC_MODE(struct ir3_instruction *instr)
225 {
226 struct ir3_register *ssbo = instr->srcs[0];
227 if (ssbo->flags & IR3_REG_IMMED) {
228 return 0; // todo enum
229 } else if (instr->flags & IR3_INSTR_NONUNIF) {
230 return 2; // todo enum
231 } else {
232 return 1; // todo enum
233 }
234 }
235
236 /**
237 * This is a bit messy, for legacy (pre-bindless) atomic instructions,
238 * the .g (global) variety have SSBO as first src and everything else
239 * shifted up by one.
240 *
241 * TODO revisit this once legacy 'packed struct' encoding is gone
242 */
243 static inline struct ir3_register *
extract_cat6_SRC(struct ir3_instruction * instr,unsigned n)244 extract_cat6_SRC(struct ir3_instruction *instr, unsigned n)
245 {
246 if (is_global_a3xx_atomic(instr->opc)) {
247 n++;
248 }
249 assert(n < instr->srcs_count);
250 return instr->srcs[n];
251 }
252
253 typedef enum {
254 REG_MULITSRC_IMMED,
255 REG_MULTISRC_IMMED_FLUT_FULL,
256 REG_MULTISRC_IMMED_FLUT_HALF,
257 REG_MULTISRC_GPR,
258 REG_MULTISRC_CONST,
259 REG_MULTISRC_RELATIVE_GPR,
260 REG_MULTISRC_RELATIVE_CONST,
261 } reg_multisrc_t;
262
263 static inline reg_multisrc_t
__multisrc_case(struct encode_state * s,struct ir3_register * reg)264 __multisrc_case(struct encode_state *s, struct ir3_register *reg)
265 {
266 if (reg->flags & IR3_REG_IMMED) {
267 assert(opc_cat(s->instr->opc) == 2);
268 if (ir3_cat2_int(s->instr->opc)) {
269 return REG_MULITSRC_IMMED;
270 } else if (reg->flags & IR3_REG_HALF) {
271 return REG_MULTISRC_IMMED_FLUT_HALF;
272 } else {
273 return REG_MULTISRC_IMMED_FLUT_FULL;
274 }
275 } else if (reg->flags & IR3_REG_RELATIV) {
276 if (reg->flags & IR3_REG_CONST) {
277 return REG_MULTISRC_RELATIVE_CONST;
278 } else {
279 return REG_MULTISRC_RELATIVE_GPR;
280 }
281 } else if (reg->flags & IR3_REG_CONST) {
282 return REG_MULTISRC_CONST;
283 } else {
284 return REG_MULTISRC_GPR;
285 }
286 }
287
288 typedef enum {
289 REG_CAT3_SRC_GPR,
290 REG_CAT3_SRC_CONST_OR_IMMED,
291 REG_CAT3_SRC_RELATIVE_GPR,
292 REG_CAT3_SRC_RELATIVE_CONST,
293 } reg_cat3_src_t;
294
295 static inline reg_cat3_src_t
__cat3_src_case(struct encode_state * s,struct ir3_register * reg)296 __cat3_src_case(struct encode_state *s, struct ir3_register *reg)
297 {
298 if (reg->flags & IR3_REG_RELATIV) {
299 if (reg->flags & IR3_REG_CONST) {
300 return REG_CAT3_SRC_RELATIVE_CONST;
301 } else {
302 return REG_CAT3_SRC_RELATIVE_GPR;
303 }
304 } else if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)) {
305 return REG_CAT3_SRC_CONST_OR_IMMED;
306 } else {
307 return REG_CAT3_SRC_GPR;
308 }
309 }
310
311 typedef enum {
312 STC_DST_IMM,
313 STC_DST_A1
314 } stc_dst_t;
315
316 static inline stc_dst_t
__stc_dst_case(struct encode_state * s,struct ir3_instruction * instr)317 __stc_dst_case(struct encode_state *s, struct ir3_instruction *instr)
318 {
319 return (instr->flags & IR3_INSTR_A1EN) ? STC_DST_A1 : STC_DST_IMM;
320 }
321
322 #include "encode.h"
323
324
325 void *
isa_assemble(struct ir3_shader_variant * v)326 isa_assemble(struct ir3_shader_variant *v)
327 {
328 BITSET_WORD *ptr, *instrs;
329 const struct ir3_info *info = &v->info;
330 struct ir3 *shader = v->ir;
331
332 ptr = instrs = rzalloc_size(v, info->size);
333
334 foreach_block (block, &shader->block_list) {
335 foreach_instr (instr, &block->instr_list) {
336 struct encode_state s = {
337 .gen = shader->compiler->gen * 100,
338 .compiler = shader->compiler,
339 .instr = instr,
340 };
341
342 const bitmask_t encoded = encode__instruction(&s, NULL, instr);
343 store_instruction(instrs, encoded);
344 instrs += BITMASK_WORDS;
345 }
346 }
347
348 return ptr;
349 }
350