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