xref: /aosp_15_r20/external/mesa3d/src/freedreno/isa/encode.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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