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