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