Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/isa/encode.c
4564 views
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
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
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
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->gpu_id > 600) &&
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->gpu_id >= 600) {
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
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 *
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
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
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
return CAT5_BINDLESS_A1_UNIFORM;
183
} else if (instr->flags & IR3_INSTR_NONUNIF) {
184
return CAT5_BINDLESS_NONUNIFORM;
185
} else {
186
return CAT5_BINDLESS_UNIFORM;
187
}
188
} else {
189
/* TODO: This should probably be CAT5_UNIFORM, at least on a6xx,
190
* as this is what the blob does and it is presumably faster, but
191
* first we should confirm it is actually nonuniform and figure
192
* out when the whole descriptor mode mechanism was introduced.
193
*/
194
return CAT5_NONUNIFORM;
195
}
196
assert(!(instr->cat5.samp | instr->cat5.tex));
197
} else if (instr->flags & IR3_INSTR_B) {
198
if (instr->flags & IR3_INSTR_A1EN) {
199
return CAT5_BINDLESS_A1_IMM;
200
} else {
201
return CAT5_BINDLESS_IMM;
202
}
203
}
204
return 0;
205
}
206
207
static inline unsigned
208
extract_cat6_DESC_MODE(struct ir3_instruction *instr)
209
{
210
struct ir3_register *ssbo = instr->srcs[0];
211
if (ssbo->flags & IR3_REG_IMMED) {
212
return 0; // todo enum
213
} else if (instr->flags & IR3_INSTR_NONUNIF) {
214
return 2; // todo enum
215
} else {
216
return 1; // todo enum
217
}
218
}
219
220
/**
221
* This is a bit messy, for legacy (pre-bindless) atomic instructions,
222
* the .g (global) variety have SSBO as first src and everything else
223
* shifted up by one.
224
*
225
* TODO revisit this once legacy 'packed struct' encoding is gone
226
*/
227
static inline struct ir3_register *
228
extract_cat6_SRC(struct ir3_instruction *instr, unsigned n)
229
{
230
if (instr->flags & IR3_INSTR_G) {
231
n++;
232
}
233
assert(n < instr->srcs_count);
234
return instr->srcs[n];
235
}
236
237
typedef enum {
238
REG_MULITSRC_IMMED,
239
REG_MULTISRC_IMMED_FLUT_FULL,
240
REG_MULTISRC_IMMED_FLUT_HALF,
241
REG_MULTISRC_GPR,
242
REG_MULTISRC_CONST,
243
REG_MULTISRC_RELATIVE_GPR,
244
REG_MULTISRC_RELATIVE_CONST,
245
} reg_multisrc_t;
246
247
static inline reg_multisrc_t
248
__multisrc_case(struct encode_state *s, struct ir3_register *reg)
249
{
250
if (reg->flags & IR3_REG_IMMED) {
251
assert(opc_cat(s->instr->opc) == 2);
252
if (ir3_cat2_int(s->instr->opc)) {
253
return REG_MULITSRC_IMMED;
254
} else if (reg->flags & IR3_REG_HALF) {
255
return REG_MULTISRC_IMMED_FLUT_HALF;
256
} else {
257
return REG_MULTISRC_IMMED_FLUT_FULL;
258
}
259
} else if (reg->flags & IR3_REG_RELATIV) {
260
if (reg->flags & IR3_REG_CONST) {
261
return REG_MULTISRC_RELATIVE_CONST;
262
} else {
263
return REG_MULTISRC_RELATIVE_GPR;
264
}
265
} else if (reg->flags & IR3_REG_CONST) {
266
return REG_MULTISRC_CONST;
267
} else {
268
return REG_MULTISRC_GPR;
269
}
270
}
271
272
typedef enum {
273
REG_CAT3_SRC_GPR,
274
REG_CAT3_SRC_CONST_OR_IMMED,
275
REG_CAT3_SRC_RELATIVE_GPR,
276
REG_CAT3_SRC_RELATIVE_CONST,
277
} reg_cat3_src_t;
278
279
static inline reg_cat3_src_t
280
__cat3_src_case(struct encode_state *s, struct ir3_register *reg)
281
{
282
if (reg->flags & IR3_REG_RELATIV) {
283
if (reg->flags & IR3_REG_CONST) {
284
return REG_CAT3_SRC_RELATIVE_CONST;
285
} else {
286
return REG_CAT3_SRC_RELATIVE_GPR;
287
}
288
} else if (reg->flags & (IR3_REG_CONST | IR3_REG_IMMED)) {
289
return REG_CAT3_SRC_CONST_OR_IMMED;
290
} else {
291
return REG_CAT3_SRC_GPR;
292
}
293
}
294
295
#include "encode.h"
296
297
298
void *
299
isa_assemble(struct ir3_shader_variant *v)
300
{
301
uint64_t *ptr, *instrs;
302
const struct ir3_info *info = &v->info;
303
struct ir3 *shader = v->ir;
304
305
ptr = instrs = rzalloc_size(v, info->size);
306
307
foreach_block (block, &shader->block_list) {
308
foreach_instr (instr, &block->instr_list) {
309
struct encode_state s = {
310
.compiler = shader->compiler,
311
.instr = instr,
312
};
313
314
*(instrs++) = encode__instruction(&s, NULL, instr);
315
}
316
}
317
318
return ptr;
319
}
320
321