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