xref: /third_party/mesa3d/src/freedreno/isa/encode.c (revision bf215546)
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
33struct bitset_params;
34
35struct 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
51static inline bool
52extract_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
61static inline bool
62extract_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
74static inline opc_t
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
131static inline unsigned
132extract_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
148static inline int32_t
149extract_reg_iim(struct ir3_register *reg)
150{
151   assert(reg->flags & IR3_REG_IMMED);
152   return reg->iim_val;
153}
154
155static inline uint32_t
156extract_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 */
168static inline struct ir3_register *
169extract_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
179static inline bool
180extract_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
189static inline cat5_desc_mode_t
190extract_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
223static inline unsigned
224extract_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 */
243static inline struct ir3_register *
244extract_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
253typedef 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
263static inline reg_multisrc_t
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
288typedef 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
295static inline reg_cat3_src_t
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
311typedef enum {
312   STC_DST_IMM,
313   STC_DST_A1
314} stc_dst_t;
315
316static inline stc_dst_t
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
325void *
326isa_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