Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/asahi/compiler/agx_compiler.h
4564 views
1
/*
2
* Copyright (C) 2021 Alyssa Rosenzweig <[email protected]>
3
* Copyright (C) 2020 Collabora Ltd.
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
11
*
12
* The above copyright notice and this permission notice (including the next
13
* paragraph) shall be included in all copies or substantial portions of the
14
* Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*/
24
25
#ifndef __AGX_COMPILER_H
26
#define __AGX_COMPILER_H
27
28
#include "compiler/nir/nir.h"
29
#include "util/u_math.h"
30
#include "util/half_float.h"
31
#include "util/u_dynarray.h"
32
#include "agx_compile.h"
33
#include "agx_opcodes.h"
34
#include "agx_minifloat.h"
35
36
enum agx_dbg {
37
AGX_DBG_MSGS = BITFIELD_BIT(0),
38
AGX_DBG_SHADERS = BITFIELD_BIT(1),
39
AGX_DBG_SHADERDB = BITFIELD_BIT(2),
40
AGX_DBG_VERBOSE = BITFIELD_BIT(3),
41
AGX_DBG_INTERNAL = BITFIELD_BIT(4),
42
};
43
44
extern int agx_debug;
45
46
/* r0-r127 inclusive, as pairs of 16-bits, gives 256 registers */
47
#define AGX_NUM_REGS (256)
48
49
enum agx_index_type {
50
AGX_INDEX_NULL = 0,
51
AGX_INDEX_NORMAL = 1,
52
AGX_INDEX_IMMEDIATE = 2,
53
AGX_INDEX_UNIFORM = 3,
54
AGX_INDEX_REGISTER = 4,
55
AGX_INDEX_NIR_REGISTER = 5,
56
};
57
58
enum agx_size {
59
AGX_SIZE_16 = 0,
60
AGX_SIZE_32 = 1,
61
AGX_SIZE_64 = 2
62
};
63
64
typedef struct {
65
/* Sufficient for as many SSA values as we need. Immediates and uniforms fit in 16-bits */
66
unsigned value : 22;
67
68
/* Indicates that this source kills the referenced value (because it is the
69
* last use in a block and the source is not live after the block). Set by
70
* liveness analysis. */
71
bool kill : 1;
72
73
/* Cache hints */
74
bool cache : 1;
75
bool discard : 1;
76
77
/* src - float modifiers */
78
bool abs : 1;
79
bool neg : 1;
80
81
enum agx_size size : 2;
82
enum agx_index_type type : 3;
83
} agx_index;
84
85
static inline agx_index
86
agx_get_index(unsigned value, enum agx_size size)
87
{
88
return (agx_index) {
89
.type = AGX_INDEX_NORMAL,
90
.value = value,
91
.size = size
92
};
93
}
94
95
static inline agx_index
96
agx_immediate(uint16_t imm)
97
{
98
return (agx_index) {
99
.type = AGX_INDEX_IMMEDIATE,
100
.value = imm,
101
.size = AGX_SIZE_32
102
};
103
}
104
105
static inline agx_index
106
agx_immediate_f(float f)
107
{
108
assert(agx_minifloat_exact(f));
109
return agx_immediate(agx_minifloat_encode(f));
110
}
111
112
/* in half-words, specify r0h as 1, r1 as 2... */
113
static inline agx_index
114
agx_register(uint8_t imm, enum agx_size size)
115
{
116
return (agx_index) {
117
.type = AGX_INDEX_REGISTER,
118
.value = imm,
119
.size = size
120
};
121
}
122
123
static inline agx_index
124
agx_nir_register(unsigned imm, enum agx_size size)
125
{
126
return (agx_index) {
127
.type = AGX_INDEX_NIR_REGISTER,
128
.value = imm,
129
.size = size
130
};
131
}
132
133
/* Also in half-words */
134
static inline agx_index
135
agx_uniform(uint8_t imm, enum agx_size size)
136
{
137
return (agx_index) {
138
.type = AGX_INDEX_UNIFORM,
139
.value = imm,
140
.size = size
141
};
142
}
143
144
static inline agx_index
145
agx_null()
146
{
147
return (agx_index) { .type = AGX_INDEX_NULL };
148
}
149
150
static inline agx_index
151
agx_zero()
152
{
153
return agx_immediate(0);
154
}
155
156
/* IEEE 754 additive identity -0.0, stored as an 8-bit AGX minifloat: mantissa
157
* = exponent = 0, sign bit set */
158
159
static inline agx_index
160
agx_negzero()
161
{
162
return agx_immediate(0x80);
163
}
164
165
static inline agx_index
166
agx_abs(agx_index idx)
167
{
168
idx.abs = true;
169
idx.neg = false;
170
return idx;
171
}
172
173
static inline agx_index
174
agx_neg(agx_index idx)
175
{
176
idx.neg ^= true;
177
return idx;
178
}
179
180
/* Replaces an index, preserving any modifiers */
181
182
static inline agx_index
183
agx_replace_index(agx_index old, agx_index replacement)
184
{
185
replacement.abs = old.abs;
186
replacement.neg = old.neg;
187
return replacement;
188
}
189
190
static inline bool
191
agx_is_null(agx_index idx)
192
{
193
return idx.type == AGX_INDEX_NULL;
194
}
195
196
/* Compares equivalence as references */
197
198
static inline bool
199
agx_is_equiv(agx_index left, agx_index right)
200
{
201
return (left.type == right.type) && (left.value == right.value);
202
}
203
204
#define AGX_MAX_DESTS 1
205
#define AGX_MAX_SRCS 5
206
207
enum agx_icond {
208
AGX_ICOND_UEQ = 0,
209
AGX_ICOND_ULT = 1,
210
AGX_ICOND_UGT = 2,
211
/* unknown */
212
AGX_ICOND_SEQ = 4,
213
AGX_ICOND_SLT = 5,
214
AGX_ICOND_SGT = 6,
215
/* unknown */
216
};
217
218
enum agx_fcond {
219
AGX_FCOND_EQ = 0,
220
AGX_FCOND_LT = 1,
221
AGX_FCOND_GT = 2,
222
AGX_FCOND_LTN = 3,
223
/* unknown */
224
AGX_FCOND_GE = 5,
225
AGX_FCOND_LE = 6,
226
AGX_FCOND_GTN = 7,
227
};
228
229
enum agx_round {
230
AGX_ROUND_RTZ = 0,
231
AGX_ROUND_RTE = 1,
232
};
233
234
enum agx_convert {
235
AGX_CONVERT_U8_TO_F = 0,
236
AGX_CONVERT_S8_TO_F = 1,
237
AGX_CONVERT_F_TO_U16 = 4,
238
AGX_CONVERT_F_TO_S16 = 5,
239
AGX_CONVERT_U16_TO_F = 6,
240
AGX_CONVERT_S16_TO_F = 7,
241
AGX_CONVERT_F_TO_U32 = 8,
242
AGX_CONVERT_F_TO_S32 = 9,
243
AGX_CONVERT_U32_TO_F = 10,
244
AGX_CONVERT_S32_TO_F = 11
245
};
246
247
enum agx_lod_mode {
248
AGX_LOD_MODE_AUTO_LOD = 0,
249
AGX_LOD_MODE_LOD_MIN = 6,
250
AGX_LOD_GRAD = 8,
251
AGX_LOD_GRAD_MIN = 12
252
};
253
254
enum agx_dim {
255
AGX_DIM_TEX_1D = 0,
256
AGX_DIM_TEX_1D_ARRAY = 1,
257
AGX_DIM_TEX_2D = 2,
258
AGX_DIM_TEX_2D_ARRAY = 3,
259
AGX_DIM_TEX_2D_MS = 4,
260
AGX_DIM_TEX_3D = 5,
261
AGX_DIM_TEX_CUBE = 6,
262
AGX_DIM_TEX_CUBE_ARRAY = 7
263
};
264
265
/* Forward declare for branch target */
266
struct agx_block;
267
268
typedef struct {
269
/* Must be first */
270
struct list_head link;
271
272
enum agx_opcode op;
273
274
/* Data flow */
275
agx_index dest[AGX_MAX_DESTS];
276
agx_index src[AGX_MAX_SRCS];
277
278
union {
279
uint32_t imm;
280
uint32_t writeout;
281
uint32_t truth_table;
282
uint32_t component;
283
uint32_t channels;
284
uint32_t bfi_mask;
285
enum agx_sr sr;
286
enum agx_icond icond;
287
enum agx_fcond fcond;
288
enum agx_format format;
289
enum agx_round round;
290
enum agx_lod_mode lod_mode;
291
struct agx_block *target;
292
};
293
294
/* For load varying */
295
bool perspective : 1;
296
297
/* Invert icond/fcond */
298
bool invert_cond : 1;
299
300
/* TODO: Handle tex ops more efficient */
301
enum agx_dim dim : 3;
302
303
/* Final st_vary op */
304
bool last : 1;
305
306
/* Shift for a bitwise or memory op (conflicts with format for memory ops) */
307
unsigned shift : 4;
308
309
/* Scoreboard index, 0 or 1. Leave as 0 for instructions that do not require
310
* scoreboarding (everything but memory load/store and texturing). */
311
unsigned scoreboard : 1;
312
313
/* Number of nested control flow layers to jump by */
314
unsigned nest : 2;
315
316
/* Output modifiers */
317
bool saturate : 1;
318
unsigned mask : 4;
319
} agx_instr;
320
321
struct agx_block;
322
323
typedef struct agx_block {
324
/* Link to next block. Must be first */
325
struct list_head link;
326
327
/* List of instructions emitted for the current block */
328
struct list_head instructions;
329
330
/* Index of the block in source order */
331
unsigned name;
332
333
/* Control flow graph */
334
struct agx_block *successors[2];
335
struct set *predecessors;
336
bool unconditional_jumps;
337
338
/* Liveness analysis results */
339
BITSET_WORD *live_in;
340
BITSET_WORD *live_out;
341
342
/* Register allocation */
343
BITSET_DECLARE(regs_out, AGX_NUM_REGS);
344
345
/* Offset of the block in the emitted binary */
346
off_t offset;
347
348
/** Available for passes to use for metadata */
349
uint8_t pass_flags;
350
} agx_block;
351
352
typedef struct {
353
nir_shader *nir;
354
gl_shader_stage stage;
355
struct list_head blocks; /* list of agx_block */
356
struct agx_shader_info *out;
357
struct agx_shader_key *key;
358
359
/* Remapping table for varyings indexed by driver_location */
360
unsigned varyings[AGX_MAX_VARYINGS];
361
362
/* Handling phi nodes is still TODO while we bring up other parts of the
363
* driver. YOLO the mapping of nir_register to fixed hardware registers */
364
unsigned *nir_regalloc;
365
366
/* We reserve the top (XXX: that hurts thread count) */
367
unsigned max_register;
368
369
/* Place to start pushing new values */
370
unsigned push_base;
371
372
/* For creating temporaries */
373
unsigned alloc;
374
375
/* I don't really understand how writeout ops work yet */
376
bool did_writeout;
377
378
/* Has r0l been zeroed yet due to control flow? */
379
bool any_cf;
380
381
/** Computed metadata */
382
bool has_liveness;
383
384
/* Number of nested control flow structures within the innermost loop. Since
385
* NIR is just loop and if-else, this is the number of nested if-else
386
* statements in the loop */
387
unsigned loop_nesting;
388
389
/* During instruction selection, for inserting control flow */
390
agx_block *current_block;
391
agx_block *continue_block;
392
agx_block *break_block;
393
agx_block *after_block;
394
395
/* Stats for shader-db */
396
unsigned loop_count;
397
unsigned spills;
398
unsigned fills;
399
} agx_context;
400
401
static inline void
402
agx_remove_instruction(agx_instr *ins)
403
{
404
list_del(&ins->link);
405
}
406
407
static inline agx_index
408
agx_temp(agx_context *ctx, enum agx_size size)
409
{
410
return agx_get_index(ctx->alloc++, size);
411
}
412
413
static enum agx_size
414
agx_size_for_bits(unsigned bits)
415
{
416
switch (bits) {
417
case 1:
418
case 16: return AGX_SIZE_16;
419
case 32: return AGX_SIZE_32;
420
case 64: return AGX_SIZE_64;
421
default: unreachable("Invalid bitsize");
422
}
423
}
424
425
static inline agx_index
426
agx_src_index(nir_src *src)
427
{
428
if (!src->is_ssa) {
429
return agx_nir_register(src->reg.reg->index,
430
agx_size_for_bits(nir_src_bit_size(*src)));
431
}
432
433
return agx_get_index(src->ssa->index,
434
agx_size_for_bits(nir_src_bit_size(*src)));
435
}
436
437
static inline agx_index
438
agx_dest_index(nir_dest *dst)
439
{
440
if (!dst->is_ssa) {
441
return agx_nir_register(dst->reg.reg->index,
442
agx_size_for_bits(nir_dest_bit_size(*dst)));
443
}
444
445
return agx_get_index(dst->ssa.index,
446
agx_size_for_bits(nir_dest_bit_size(*dst)));
447
}
448
449
/* Iterators for AGX IR */
450
451
#define agx_foreach_block(ctx, v) \
452
list_for_each_entry(agx_block, v, &ctx->blocks, link)
453
454
#define agx_foreach_block_rev(ctx, v) \
455
list_for_each_entry_rev(agx_block, v, &ctx->blocks, link)
456
457
#define agx_foreach_block_from(ctx, from, v) \
458
list_for_each_entry_from(agx_block, v, from, &ctx->blocks, link)
459
460
#define agx_foreach_block_from_rev(ctx, from, v) \
461
list_for_each_entry_from_rev(agx_block, v, from, &ctx->blocks, link)
462
463
#define agx_foreach_instr_in_block(block, v) \
464
list_for_each_entry(agx_instr, v, &(block)->instructions, link)
465
466
#define agx_foreach_instr_in_block_rev(block, v) \
467
list_for_each_entry_rev(agx_instr, v, &(block)->instructions, link)
468
469
#define agx_foreach_instr_in_block_safe(block, v) \
470
list_for_each_entry_safe(agx_instr, v, &(block)->instructions, link)
471
472
#define agx_foreach_instr_in_block_safe_rev(block, v) \
473
list_for_each_entry_safe_rev(agx_instr, v, &(block)->instructions, link)
474
475
#define agx_foreach_instr_in_block_from(block, v, from) \
476
list_for_each_entry_from(agx_instr, v, from, &(block)->instructions, link)
477
478
#define agx_foreach_instr_in_block_from_rev(block, v, from) \
479
list_for_each_entry_from_rev(agx_instr, v, from, &(block)->instructions, link)
480
481
#define agx_foreach_instr_global(ctx, v) \
482
agx_foreach_block(ctx, v_block) \
483
agx_foreach_instr_in_block(v_block, v)
484
485
#define agx_foreach_instr_global_rev(ctx, v) \
486
agx_foreach_block_rev(ctx, v_block) \
487
agx_foreach_instr_in_block_rev(v_block, v)
488
489
#define agx_foreach_instr_global_safe(ctx, v) \
490
agx_foreach_block(ctx, v_block) \
491
agx_foreach_instr_in_block_safe(v_block, v)
492
493
#define agx_foreach_instr_global_safe_rev(ctx, v) \
494
agx_foreach_block_rev(ctx, v_block) \
495
agx_foreach_instr_in_block_safe_rev(v_block, v)
496
497
/* Based on set_foreach, expanded with automatic type casts */
498
499
#define agx_foreach_successor(blk, v) \
500
agx_block *v; \
501
agx_block **_v; \
502
for (_v = (agx_block **) &blk->successors[0], \
503
v = *_v; \
504
v != NULL && _v < (agx_block **) &blk->successors[2]; \
505
_v++, v = *_v) \
506
507
#define agx_foreach_predecessor(blk, v) \
508
struct set_entry *_entry_##v; \
509
agx_block *v; \
510
for (_entry_##v = _mesa_set_next_entry(blk->predecessors, NULL), \
511
v = (agx_block *) (_entry_##v ? _entry_##v->key : NULL); \
512
_entry_##v != NULL; \
513
_entry_##v = _mesa_set_next_entry(blk->predecessors, _entry_##v), \
514
v = (agx_block *) (_entry_##v ? _entry_##v->key : NULL))
515
516
#define agx_foreach_src(ins, v) \
517
for (unsigned v = 0; v < ARRAY_SIZE(ins->src); ++v)
518
519
#define agx_foreach_dest(ins, v) \
520
for (unsigned v = 0; v < ARRAY_SIZE(ins->dest); ++v)
521
522
static inline agx_instr *
523
agx_prev_op(agx_instr *ins)
524
{
525
return list_last_entry(&(ins->link), agx_instr, link);
526
}
527
528
static inline agx_instr *
529
agx_next_op(agx_instr *ins)
530
{
531
return list_first_entry(&(ins->link), agx_instr, link);
532
}
533
534
static inline agx_block *
535
agx_next_block(agx_block *block)
536
{
537
return list_first_entry(&(block->link), agx_block, link);
538
}
539
540
static inline agx_block *
541
agx_exit_block(agx_context *ctx)
542
{
543
agx_block *last = list_last_entry(&ctx->blocks, agx_block, link);
544
assert(!last->successors[0] && !last->successors[1]);
545
return last;
546
}
547
548
/* Like in NIR, for use with the builder */
549
550
enum agx_cursor_option {
551
agx_cursor_after_block,
552
agx_cursor_before_instr,
553
agx_cursor_after_instr
554
};
555
556
typedef struct {
557
enum agx_cursor_option option;
558
559
union {
560
agx_block *block;
561
agx_instr *instr;
562
};
563
} agx_cursor;
564
565
static inline agx_cursor
566
agx_after_block(agx_block *block)
567
{
568
return (agx_cursor) {
569
.option = agx_cursor_after_block,
570
.block = block
571
};
572
}
573
574
static inline agx_cursor
575
agx_before_instr(agx_instr *instr)
576
{
577
return (agx_cursor) {
578
.option = agx_cursor_before_instr,
579
.instr = instr
580
};
581
}
582
583
static inline agx_cursor
584
agx_after_instr(agx_instr *instr)
585
{
586
return (agx_cursor) {
587
.option = agx_cursor_after_instr,
588
.instr = instr
589
};
590
}
591
592
/* IR builder in terms of cursor infrastructure */
593
594
typedef struct {
595
agx_context *shader;
596
agx_cursor cursor;
597
} agx_builder;
598
599
static inline agx_builder
600
agx_init_builder(agx_context *ctx, agx_cursor cursor)
601
{
602
return (agx_builder) {
603
.shader = ctx,
604
.cursor = cursor
605
};
606
}
607
608
/* Insert an instruction at the cursor and move the cursor */
609
610
static inline void
611
agx_builder_insert(agx_cursor *cursor, agx_instr *I)
612
{
613
switch (cursor->option) {
614
case agx_cursor_after_instr:
615
list_add(&I->link, &cursor->instr->link);
616
cursor->instr = I;
617
return;
618
619
case agx_cursor_after_block:
620
list_addtail(&I->link, &cursor->block->instructions);
621
cursor->option = agx_cursor_after_instr;
622
cursor->instr = I;
623
return;
624
625
case agx_cursor_before_instr:
626
list_addtail(&I->link, &cursor->instr->link);
627
cursor->option = agx_cursor_after_instr;
628
cursor->instr = I;
629
return;
630
}
631
632
unreachable("Invalid cursor option");
633
}
634
635
/* Uniform file management */
636
637
agx_index
638
agx_indexed_sysval(agx_context *ctx, enum agx_push_type type, enum agx_size size,
639
unsigned index, unsigned length);
640
641
/* Routines defined for AIR */
642
643
void agx_print_instr(agx_instr *I, FILE *fp);
644
void agx_print_block(agx_block *block, FILE *fp);
645
void agx_print_shader(agx_context *ctx, FILE *fp);
646
void agx_optimizer(agx_context *ctx);
647
void agx_dce(agx_context *ctx);
648
void agx_ra(agx_context *ctx);
649
void agx_pack_binary(agx_context *ctx, struct util_dynarray *emission);
650
651
void agx_compute_liveness(agx_context *ctx);
652
void agx_liveness_ins_update(BITSET_WORD *live, agx_instr *I);
653
654
#endif
655
656