• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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