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