xref: /third_party/mesa3d/src/freedreno/isa/encode.c (revision bf215546)
1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "util/log.h"
25bf215546Sopenharmony_ci#include "util/u_math.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "ir3/ir3.h"
28bf215546Sopenharmony_ci#include "ir3/ir3_shader.h"
29bf215546Sopenharmony_ci#include "ir3/instr-a3xx.h"  // TODO move opc's and other useful things to ir3-instr.h or so
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "isa.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_cistruct bitset_params;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_cistruct encode_state {
36bf215546Sopenharmony_ci	unsigned gen;
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci	struct ir3_compiler *compiler;
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci	/**
41bf215546Sopenharmony_ci	 * The instruction which is currently being encoded
42bf215546Sopenharmony_ci	 */
43bf215546Sopenharmony_ci	struct ir3_instruction *instr;
44bf215546Sopenharmony_ci};
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/*
47bf215546Sopenharmony_ci * Helpers defining how to map from ir3_instruction/ir3_register/etc to fields
48bf215546Sopenharmony_ci * to be encoded:
49bf215546Sopenharmony_ci */
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_cistatic inline bool
52bf215546Sopenharmony_ciextract_SRC1_R(struct ir3_instruction *instr)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci	if (instr->nop) {
55bf215546Sopenharmony_ci		assert(!instr->repeat);
56bf215546Sopenharmony_ci		return instr->nop & 0x1;
57bf215546Sopenharmony_ci	}
58bf215546Sopenharmony_ci	return !!(instr->srcs[0]->flags & IR3_REG_R);
59bf215546Sopenharmony_ci}
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_cistatic inline bool
62bf215546Sopenharmony_ciextract_SRC2_R(struct ir3_instruction *instr)
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci	if (instr->nop) {
65bf215546Sopenharmony_ci		assert(!instr->repeat);
66bf215546Sopenharmony_ci		return (instr->nop >> 1) & 0x1;
67bf215546Sopenharmony_ci	}
68bf215546Sopenharmony_ci	/* src2 does not appear in all cat2, but SRC2_R does (for nop encoding) */
69bf215546Sopenharmony_ci	if (instr->srcs_count > 1)
70bf215546Sopenharmony_ci		return !!(instr->srcs[1]->flags & IR3_REG_R);
71bf215546Sopenharmony_ci	return 0;
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic inline opc_t
75bf215546Sopenharmony_ci__instruction_case(struct encode_state *s, struct ir3_instruction *instr)
76bf215546Sopenharmony_ci{
77bf215546Sopenharmony_ci	/*
78bf215546Sopenharmony_ci	 * Temporary hack.. the new world doesn't map opcodes directly to hw
79bf215546Sopenharmony_ci	 * encoding, so there are some cases where we need to fixup the opc
80bf215546Sopenharmony_ci	 * to match what the encoder expects.  Eventually this will go away
81bf215546Sopenharmony_ci	 * once we completely transition away from the packed-struct encoding/
82bf215546Sopenharmony_ci	 * decoding and split up things which are logically different
83bf215546Sopenharmony_ci	 * instructions
84bf215546Sopenharmony_ci	 */
85bf215546Sopenharmony_ci	if (instr->opc == OPC_B) {
86bf215546Sopenharmony_ci		switch (instr->cat0.brtype) {
87bf215546Sopenharmony_ci		case BRANCH_PLAIN:
88bf215546Sopenharmony_ci			return OPC_BR;
89bf215546Sopenharmony_ci		case BRANCH_OR:
90bf215546Sopenharmony_ci			return OPC_BRAO;
91bf215546Sopenharmony_ci		case BRANCH_AND:
92bf215546Sopenharmony_ci			return OPC_BRAA;
93bf215546Sopenharmony_ci		case BRANCH_CONST:
94bf215546Sopenharmony_ci			return OPC_BRAC;
95bf215546Sopenharmony_ci		case BRANCH_ANY:
96bf215546Sopenharmony_ci			return OPC_BANY;
97bf215546Sopenharmony_ci		case BRANCH_ALL:
98bf215546Sopenharmony_ci			return OPC_BALL;
99bf215546Sopenharmony_ci		case BRANCH_X:
100bf215546Sopenharmony_ci			return OPC_BRAX;
101bf215546Sopenharmony_ci		}
102bf215546Sopenharmony_ci	} else if (instr->opc == OPC_MOV) {
103bf215546Sopenharmony_ci		struct ir3_register *src = instr->srcs[0];
104bf215546Sopenharmony_ci		if (src->flags & IR3_REG_IMMED) {
105bf215546Sopenharmony_ci			return OPC_MOV_IMMED;
106bf215546Sopenharmony_ci		} if (src->flags & IR3_REG_RELATIV) {
107bf215546Sopenharmony_ci			if (src->flags & IR3_REG_CONST) {
108bf215546Sopenharmony_ci				return OPC_MOV_RELCONST;
109bf215546Sopenharmony_ci			} else {
110bf215546Sopenharmony_ci				return OPC_MOV_RELGPR;
111bf215546Sopenharmony_ci			}
112bf215546Sopenharmony_ci		} else if (src->flags & IR3_REG_CONST) {
113bf215546Sopenharmony_ci			return OPC_MOV_CONST;
114bf215546Sopenharmony_ci		} else {
115bf215546Sopenharmony_ci			return OPC_MOV_GPR;
116bf215546Sopenharmony_ci		}
117bf215546Sopenharmony_ci	} else if (instr->opc == OPC_DEMOTE) {
118bf215546Sopenharmony_ci		return OPC_KILL;
119bf215546Sopenharmony_ci	} else if (s->compiler->gen >= 6) {
120bf215546Sopenharmony_ci		if (instr->opc == OPC_RESINFO) {
121bf215546Sopenharmony_ci			return OPC_RESINFO_B;
122bf215546Sopenharmony_ci		} else if (instr->opc == OPC_LDIB) {
123bf215546Sopenharmony_ci			return OPC_LDIB_B;
124bf215546Sopenharmony_ci		} else if (instr->opc == OPC_STIB) {
125bf215546Sopenharmony_ci			return OPC_STIB_B;
126bf215546Sopenharmony_ci		}
127bf215546Sopenharmony_ci	}
128bf215546Sopenharmony_ci	return instr->opc;
129bf215546Sopenharmony_ci}
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_cistatic inline unsigned
132bf215546Sopenharmony_ciextract_ABSNEG(struct ir3_register *reg)
133bf215546Sopenharmony_ci{
134bf215546Sopenharmony_ci	// TODO generate enums for this:
135bf215546Sopenharmony_ci	if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)) {
136bf215546Sopenharmony_ci		if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) {
137bf215546Sopenharmony_ci			return 3; // ABSNEG
138bf215546Sopenharmony_ci		} else {
139bf215546Sopenharmony_ci			return 1; // NEG
140bf215546Sopenharmony_ci		}
141bf215546Sopenharmony_ci	} else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) {
142bf215546Sopenharmony_ci		return 2; // ABS
143bf215546Sopenharmony_ci	} else {
144bf215546Sopenharmony_ci		return 0;
145bf215546Sopenharmony_ci	}
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_cistatic inline int32_t
149bf215546Sopenharmony_ciextract_reg_iim(struct ir3_register *reg)
150bf215546Sopenharmony_ci{
151bf215546Sopenharmony_ci   assert(reg->flags & IR3_REG_IMMED);
152bf215546Sopenharmony_ci   return reg->iim_val;
153bf215546Sopenharmony_ci}
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_cistatic inline uint32_t
156bf215546Sopenharmony_ciextract_reg_uim(struct ir3_register *reg)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci   assert(reg->flags & IR3_REG_IMMED);
159bf215546Sopenharmony_ci   return reg->uim_val;
160bf215546Sopenharmony_ci}
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci/**
163bf215546Sopenharmony_ci * This is a bit messy, to deal with the fact that the optional "s2en"
164bf215546Sopenharmony_ci * src is the first src, shifting everything else up by one.
165bf215546Sopenharmony_ci *
166bf215546Sopenharmony_ci * TODO revisit this once legacy 'packed struct' encoding is gone
167bf215546Sopenharmony_ci */
168bf215546Sopenharmony_cistatic inline struct ir3_register *
169bf215546Sopenharmony_ciextract_cat5_SRC(struct ir3_instruction *instr, unsigned n)
170bf215546Sopenharmony_ci{
171bf215546Sopenharmony_ci	if (instr->flags & IR3_INSTR_S2EN) {
172bf215546Sopenharmony_ci		n++;
173bf215546Sopenharmony_ci	}
174bf215546Sopenharmony_ci	if (n < instr->srcs_count)
175bf215546Sopenharmony_ci		return instr->srcs[n];
176bf215546Sopenharmony_ci	return NULL;
177bf215546Sopenharmony_ci}
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_cistatic inline bool
180bf215546Sopenharmony_ciextract_cat5_FULL(struct ir3_instruction *instr)
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci	struct ir3_register *reg = extract_cat5_SRC(instr, 0);
183bf215546Sopenharmony_ci	/* some cat5 have zero src regs, in which case 'FULL' is false */
184bf215546Sopenharmony_ci	if (!reg)
185bf215546Sopenharmony_ci		return false;
186bf215546Sopenharmony_ci	return !(reg->flags & IR3_REG_HALF);
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_cistatic inline cat5_desc_mode_t
190bf215546Sopenharmony_ciextract_cat5_DESC_MODE(struct ir3_instruction *instr)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci	assert(instr->flags & (IR3_INSTR_S2EN | IR3_INSTR_B));
193bf215546Sopenharmony_ci	if (instr->flags & IR3_INSTR_S2EN) {
194bf215546Sopenharmony_ci		if (instr->flags & IR3_INSTR_B) {
195bf215546Sopenharmony_ci			if (instr->flags & IR3_INSTR_A1EN) {
196bf215546Sopenharmony_ci				if (instr->flags & IR3_INSTR_NONUNIF) {
197bf215546Sopenharmony_ci					return CAT5_BINDLESS_A1_NONUNIFORM;
198bf215546Sopenharmony_ci				} else {
199bf215546Sopenharmony_ci					return CAT5_BINDLESS_A1_UNIFORM;
200bf215546Sopenharmony_ci				}
201bf215546Sopenharmony_ci			} else if (instr->flags & IR3_INSTR_NONUNIF) {
202bf215546Sopenharmony_ci				return CAT5_BINDLESS_NONUNIFORM;
203bf215546Sopenharmony_ci			} else {
204bf215546Sopenharmony_ci				return CAT5_BINDLESS_UNIFORM;
205bf215546Sopenharmony_ci			}
206bf215546Sopenharmony_ci		} else {
207bf215546Sopenharmony_ci			if (instr->flags & IR3_INSTR_NONUNIF)
208bf215546Sopenharmony_ci				return CAT5_NONUNIFORM;
209bf215546Sopenharmony_ci			else
210bf215546Sopenharmony_ci				return CAT5_UNIFORM;
211bf215546Sopenharmony_ci		}
212bf215546Sopenharmony_ci		assert(!(instr->cat5.samp | instr->cat5.tex));
213bf215546Sopenharmony_ci	} else if (instr->flags & IR3_INSTR_B) {
214bf215546Sopenharmony_ci		if (instr->flags & IR3_INSTR_A1EN) {
215bf215546Sopenharmony_ci			return CAT5_BINDLESS_A1_IMM;
216bf215546Sopenharmony_ci		} else {
217bf215546Sopenharmony_ci			return CAT5_BINDLESS_IMM;
218bf215546Sopenharmony_ci		}
219bf215546Sopenharmony_ci	}
220bf215546Sopenharmony_ci	return 0;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistatic inline unsigned
224bf215546Sopenharmony_ciextract_cat6_DESC_MODE(struct ir3_instruction *instr)
225bf215546Sopenharmony_ci{
226bf215546Sopenharmony_ci	struct ir3_register *ssbo = instr->srcs[0];
227bf215546Sopenharmony_ci	if (ssbo->flags & IR3_REG_IMMED) {
228bf215546Sopenharmony_ci		return 0; // todo enum
229bf215546Sopenharmony_ci	} else if (instr->flags & IR3_INSTR_NONUNIF) {
230bf215546Sopenharmony_ci		return 2; // todo enum
231bf215546Sopenharmony_ci	} else {
232bf215546Sopenharmony_ci		return 1; // todo enum
233bf215546Sopenharmony_ci	}
234bf215546Sopenharmony_ci}
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci/**
237bf215546Sopenharmony_ci * This is a bit messy, for legacy (pre-bindless) atomic instructions,
238bf215546Sopenharmony_ci * the .g (global) variety have SSBO as first src and everything else
239bf215546Sopenharmony_ci * shifted up by one.
240bf215546Sopenharmony_ci *
241bf215546Sopenharmony_ci * TODO revisit this once legacy 'packed struct' encoding is gone
242bf215546Sopenharmony_ci */
243bf215546Sopenharmony_cistatic inline struct ir3_register *
244bf215546Sopenharmony_ciextract_cat6_SRC(struct ir3_instruction *instr, unsigned n)
245bf215546Sopenharmony_ci{
246bf215546Sopenharmony_ci	if (is_global_a3xx_atomic(instr->opc)) {
247bf215546Sopenharmony_ci		n++;
248bf215546Sopenharmony_ci	}
249bf215546Sopenharmony_ci	assert(n < instr->srcs_count);
250bf215546Sopenharmony_ci	return instr->srcs[n];
251bf215546Sopenharmony_ci}
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_citypedef enum {
254bf215546Sopenharmony_ci	REG_MULITSRC_IMMED,
255bf215546Sopenharmony_ci	REG_MULTISRC_IMMED_FLUT_FULL,
256bf215546Sopenharmony_ci	REG_MULTISRC_IMMED_FLUT_HALF,
257bf215546Sopenharmony_ci	REG_MULTISRC_GPR,
258bf215546Sopenharmony_ci	REG_MULTISRC_CONST,
259bf215546Sopenharmony_ci	REG_MULTISRC_RELATIVE_GPR,
260bf215546Sopenharmony_ci	REG_MULTISRC_RELATIVE_CONST,
261bf215546Sopenharmony_ci} reg_multisrc_t;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_cistatic inline reg_multisrc_t
264bf215546Sopenharmony_ci__multisrc_case(struct encode_state *s, struct ir3_register *reg)
265bf215546Sopenharmony_ci{
266bf215546Sopenharmony_ci	if (reg->flags & IR3_REG_IMMED) {
267bf215546Sopenharmony_ci		assert(opc_cat(s->instr->opc) == 2);
268bf215546Sopenharmony_ci		if (ir3_cat2_int(s->instr->opc)) {
269bf215546Sopenharmony_ci			return REG_MULITSRC_IMMED;
270bf215546Sopenharmony_ci		} else if (reg->flags & IR3_REG_HALF) {
271bf215546Sopenharmony_ci			return REG_MULTISRC_IMMED_FLUT_HALF;
272bf215546Sopenharmony_ci		} else {
273bf215546Sopenharmony_ci			return REG_MULTISRC_IMMED_FLUT_FULL;
274bf215546Sopenharmony_ci		}
275bf215546Sopenharmony_ci	} else if (reg->flags & IR3_REG_RELATIV) {
276bf215546Sopenharmony_ci		if (reg->flags & IR3_REG_CONST) {
277bf215546Sopenharmony_ci			return REG_MULTISRC_RELATIVE_CONST;
278bf215546Sopenharmony_ci		} else {
279bf215546Sopenharmony_ci			return REG_MULTISRC_RELATIVE_GPR;
280bf215546Sopenharmony_ci		}
281bf215546Sopenharmony_ci	} else if (reg->flags & IR3_REG_CONST) {
282bf215546Sopenharmony_ci		return REG_MULTISRC_CONST;
283bf215546Sopenharmony_ci	} else {
284bf215546Sopenharmony_ci		return REG_MULTISRC_GPR;
285bf215546Sopenharmony_ci	}
286bf215546Sopenharmony_ci}
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_citypedef enum {
289bf215546Sopenharmony_ci	REG_CAT3_SRC_GPR,
290bf215546Sopenharmony_ci	REG_CAT3_SRC_CONST_OR_IMMED,
291bf215546Sopenharmony_ci	REG_CAT3_SRC_RELATIVE_GPR,
292bf215546Sopenharmony_ci	REG_CAT3_SRC_RELATIVE_CONST,
293bf215546Sopenharmony_ci} reg_cat3_src_t;
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_cistatic inline reg_cat3_src_t
296bf215546Sopenharmony_ci__cat3_src_case(struct encode_state *s, struct ir3_register *reg)
297bf215546Sopenharmony_ci{
298bf215546Sopenharmony_ci	if (reg->flags & IR3_REG_RELATIV) {
299bf215546Sopenharmony_ci		if (reg->flags & IR3_REG_CONST) {
300bf215546Sopenharmony_ci			return REG_CAT3_SRC_RELATIVE_CONST;
301bf215546Sopenharmony_ci		} else {
302bf215546Sopenharmony_ci			return REG_CAT3_SRC_RELATIVE_GPR;
303bf215546Sopenharmony_ci		}
304bf215546Sopenharmony_ci	} else if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)) {
305bf215546Sopenharmony_ci		return REG_CAT3_SRC_CONST_OR_IMMED;
306bf215546Sopenharmony_ci	} else {
307bf215546Sopenharmony_ci		return REG_CAT3_SRC_GPR;
308bf215546Sopenharmony_ci	}
309bf215546Sopenharmony_ci}
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_citypedef enum {
312bf215546Sopenharmony_ci   STC_DST_IMM,
313bf215546Sopenharmony_ci   STC_DST_A1
314bf215546Sopenharmony_ci} stc_dst_t;
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_cistatic inline stc_dst_t
317bf215546Sopenharmony_ci__stc_dst_case(struct encode_state *s, struct ir3_instruction *instr)
318bf215546Sopenharmony_ci{
319bf215546Sopenharmony_ci   return (instr->flags & IR3_INSTR_A1EN) ? STC_DST_A1 : STC_DST_IMM;
320bf215546Sopenharmony_ci}
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci#include "encode.h"
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_civoid *
326bf215546Sopenharmony_ciisa_assemble(struct ir3_shader_variant *v)
327bf215546Sopenharmony_ci{
328bf215546Sopenharmony_ci	BITSET_WORD *ptr, *instrs;
329bf215546Sopenharmony_ci	const struct ir3_info *info = &v->info;
330bf215546Sopenharmony_ci	struct ir3 *shader = v->ir;
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci	ptr = instrs = rzalloc_size(v, info->size);
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci	foreach_block (block, &shader->block_list) {
335bf215546Sopenharmony_ci		foreach_instr (instr, &block->instr_list) {
336bf215546Sopenharmony_ci			struct encode_state s = {
337bf215546Sopenharmony_ci				.gen = shader->compiler->gen * 100,
338bf215546Sopenharmony_ci				.compiler = shader->compiler,
339bf215546Sopenharmony_ci				.instr = instr,
340bf215546Sopenharmony_ci			};
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci			const bitmask_t encoded = encode__instruction(&s, NULL, instr);
343bf215546Sopenharmony_ci			store_instruction(instrs, encoded);
344bf215546Sopenharmony_ci			instrs += BITMASK_WORDS;
345bf215546Sopenharmony_ci		}
346bf215546Sopenharmony_ci	}
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci	return ptr;
349bf215546Sopenharmony_ci}
350