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