1 /* 2 * Copyright 2011 Christoph Bumiller 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 shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 * SOFTWARE. 21 */ 22 23 #include "nv50_ir.h" 24 #include "nv50_ir_build_util.h" 25 26 namespace nv50_ir { 27 28 BuildUtil::BuildUtil() 29 { 30 init(NULL); 31 } 32 33 BuildUtil::BuildUtil(Program *prog) 34 { 35 init(prog); 36 } 37 38 void 39 BuildUtil::init(Program *prog) 40 { 41 this->prog = prog; 42 43 func = NULL; 44 bb = NULL; 45 pos = NULL; 46 47 memset(imms, 0, sizeof(imms)); 48 immCount = 0; 49 } 50 51 void 52 BuildUtil::addImmediate(ImmediateValue *imm) 53 { 54 if (immCount > (NV50_IR_BUILD_IMM_HT_SIZE * 3) / 4) 55 return; 56 57 unsigned int pos = u32Hash(imm->reg.data.u32); 58 59 while (imms[pos]) 60 pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE; 61 imms[pos] = imm; 62 immCount++; 63 } 64 65 Instruction * 66 BuildUtil::mkOp1(operation op, DataType ty, Value *dst, Value *src) 67 { 68 Instruction *insn = new_Instruction(func, op, ty); 69 70 insn->setDef(0, dst); 71 insn->setSrc(0, src); 72 73 insert(insn); 74 return insn; 75 } 76 77 Instruction * 78 BuildUtil::mkOp2(operation op, DataType ty, Value *dst, 79 Value *src0, Value *src1) 80 { 81 Instruction *insn = new_Instruction(func, op, ty); 82 83 insn->setDef(0, dst); 84 insn->setSrc(0, src0); 85 insn->setSrc(1, src1); 86 87 insert(insn); 88 return insn; 89 } 90 91 Instruction * 92 BuildUtil::mkOp3(operation op, DataType ty, Value *dst, 93 Value *src0, Value *src1, Value *src2) 94 { 95 Instruction *insn = new_Instruction(func, op, ty); 96 97 insn->setDef(0, dst); 98 insn->setSrc(0, src0); 99 insn->setSrc(1, src1); 100 insn->setSrc(2, src2); 101 102 insert(insn); 103 return insn; 104 } 105 106 LValue * 107 BuildUtil::mkLoad(DataType ty, Symbol *mem, Value *ptr) 108 { 109 Instruction *insn = new_Instruction(func, OP_LOAD, ty); 110 LValue *def = getScratch(); 111 112 insn->setDef(0, def); 113 insn->setSrc(0, mem); 114 if (ptr) 115 insn->setIndirect(0, 0, ptr); 116 117 insert(insn); 118 return def; 119 } 120 121 Instruction * 122 BuildUtil::mkStore(operation op, DataType ty, Symbol *mem, Value *ptr, 123 Value *stVal) 124 { 125 Instruction *insn = new_Instruction(func, op, ty); 126 127 insn->setSrc(0, mem); 128 insn->setSrc(1, stVal); 129 if (ptr) 130 insn->setIndirect(0, 0, ptr); 131 132 insert(insn); 133 return insn; 134 } 135 136 Instruction * 137 BuildUtil::mkFetch(Value *dst, DataType ty, DataFile file, int32_t offset, 138 Value *attrRel, Value *primRel) 139 { 140 Symbol *sym = mkSymbol(file, 0, ty, offset); 141 142 Instruction *insn = mkOp1(OP_VFETCH, ty, dst, sym); 143 144 insn->setIndirect(0, 0, attrRel); 145 insn->setIndirect(0, 1, primRel); 146 147 // already inserted 148 return insn; 149 } 150 151 Instruction * 152 BuildUtil::mkInterp(unsigned mode, Value *dst, int32_t offset, Value *rel) 153 { 154 operation op = OP_LINTERP; 155 DataType ty = TYPE_F32; 156 157 if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_FLAT) 158 ty = TYPE_U32; 159 else 160 if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_PERSPECTIVE) 161 op = OP_PINTERP; 162 163 Symbol *sym = mkSymbol(FILE_SHADER_INPUT, 0, ty, offset); 164 165 Instruction *insn = mkOp1(op, ty, dst, sym); 166 insn->setIndirect(0, 0, rel); 167 return insn; 168 } 169 170 Instruction * 171 BuildUtil::mkMov(Value *dst, Value *src, DataType ty) 172 { 173 Instruction *insn = new_Instruction(func, OP_MOV, ty); 174 175 insn->setDef(0, dst); 176 insn->setSrc(0, src); 177 178 insert(insn); 179 return insn; 180 } 181 182 Instruction * 183 BuildUtil::mkMovToReg(int id, Value *src) 184 { 185 Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(src->reg.size)); 186 187 insn->setDef(0, new_LValue(func, FILE_GPR)); 188 insn->getDef(0)->reg.data.id = id; 189 insn->setSrc(0, src); 190 191 insert(insn); 192 return insn; 193 } 194 195 Instruction * 196 BuildUtil::mkMovFromReg(Value *dst, int id) 197 { 198 Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(dst->reg.size)); 199 200 insn->setDef(0, dst); 201 insn->setSrc(0, new_LValue(func, FILE_GPR)); 202 insn->getSrc(0)->reg.data.id = id; 203 204 insert(insn); 205 return insn; 206 } 207 208 Instruction * 209 BuildUtil::mkCvt(operation op, 210 DataType dstTy, Value *dst, DataType srcTy, Value *src) 211 { 212 Instruction *insn = new_Instruction(func, op, dstTy); 213 214 insn->setType(dstTy, srcTy); 215 insn->setDef(0, dst); 216 insn->setSrc(0, src); 217 218 insert(insn); 219 return insn; 220 } 221 222 CmpInstruction * 223 BuildUtil::mkCmp(operation op, CondCode cc, DataType ty, Value *dst, 224 Value *src0, Value *src1, Value *src2) 225 { 226 CmpInstruction *insn = new_CmpInstruction(func, op); 227 228 insn->setType((dst->reg.file == FILE_PREDICATE || 229 dst->reg.file == FILE_FLAGS) ? TYPE_U8 : ty, ty); 230 insn->setCondition(cc); 231 insn->setDef(0, dst); 232 insn->setSrc(0, src0); 233 insn->setSrc(1, src1); 234 if (src2) 235 insn->setSrc(2, src2); 236 237 if (dst->reg.file == FILE_FLAGS) 238 insn->flagsDef = 0; 239 240 insert(insn); 241 return insn; 242 } 243 244 Instruction * 245 BuildUtil::mkTex(operation op, TexTarget targ, uint8_t tic, uint8_t tsc, 246 Value **def, Value **src) 247 { 248 TexInstruction *tex = new_TexInstruction(func, op); 249 250 for (int d = 0; d < 4 && def[d]; ++d) 251 tex->setDef(d, def[d]); 252 for (int s = 0; s < 4 && src[s]; ++s) 253 tex->setSrc(s, src[s]); 254 255 tex->setTexture(targ, tic, tsc); 256 257 return tex; 258 } 259 260 Instruction * 261 BuildUtil::mkQuadop(uint8_t q, Value *def, uint8_t l, Value *src0, Value *src1) 262 { 263 Instruction *quadop = mkOp2(OP_QUADOP, TYPE_F32, def, src0, src1); 264 quadop->subOp = q; 265 quadop->lanes = l; 266 return quadop; 267 } 268 269 Instruction * 270 BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc) 271 { 272 LValue *def0 = getSSA(); 273 LValue *def1 = getSSA(); 274 275 mkMov(def0, trSrc)->setPredicate(CC_P, pred); 276 mkMov(def1, flSrc)->setPredicate(CC_NOT_P, pred); 277 278 return mkOp2(OP_UNION, typeOfSize(dst->reg.size), dst, def0, def1); 279 } 280 281 Instruction * 282 BuildUtil::mkSplit(Value *h[2], uint8_t halfSize, Value *val) 283 { 284 Instruction *insn = NULL; 285 286 const DataType fTy = typeOfSize(halfSize * 2); 287 288 if (val->reg.file == FILE_IMMEDIATE) 289 val = mkMov(getSSA(halfSize * 2), val, fTy)->getDef(0); 290 291 if (isMemoryFile(val->reg.file)) { 292 h[0] = cloneShallow(getFunction(), val); 293 h[1] = cloneShallow(getFunction(), val); 294 h[0]->reg.size = halfSize; 295 h[1]->reg.size = halfSize; 296 h[1]->reg.data.offset += halfSize; 297 } else { 298 h[0] = getSSA(halfSize, val->reg.file); 299 h[1] = getSSA(halfSize, val->reg.file); 300 insn = mkOp1(OP_SPLIT, fTy, h[0], val); 301 insn->setDef(1, h[1]); 302 } 303 return insn; 304 } 305 306 FlowInstruction * 307 BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred) 308 { 309 FlowInstruction *insn = new_FlowInstruction(func, op, targ); 310 311 if (pred) 312 insn->setPredicate(cc, pred); 313 314 insert(insn); 315 return insn; 316 } 317 318 void 319 BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit) 320 { 321 static const uint16_t baseSize2[16] = 322 { 323 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220, 324 0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040, 325 }; 326 327 int base = 0; 328 329 for (; rMask; rMask >>= 4, base += 4) { 330 const uint32_t mask = rMask & 0xf; 331 if (!mask) 332 continue; 333 int base1 = (baseSize2[mask] >> 0) & 0xf; 334 int size1 = (baseSize2[mask] >> 4) & 0xf; 335 int base2 = (baseSize2[mask] >> 8) & 0xf; 336 int size2 = (baseSize2[mask] >> 12) & 0xf; 337 Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL); 338 if (1) { // size1 can't be 0 339 LValue *reg = new_LValue(func, f); 340 reg->reg.size = size1 << unit; 341 reg->reg.data.id = base + base1; 342 insn->setDef(0, reg); 343 } 344 if (size2) { 345 LValue *reg = new_LValue(func, f); 346 reg->reg.size = size2 << unit; 347 reg->reg.data.id = base + base2; 348 insn->setDef(1, reg); 349 } 350 } 351 } 352 353 ImmediateValue * 354 BuildUtil::mkImm(uint32_t u) 355 { 356 unsigned int pos = u32Hash(u); 357 358 while (imms[pos] && imms[pos]->reg.data.u32 != u) 359 pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE; 360 361 ImmediateValue *imm = imms[pos]; 362 if (!imm) { 363 imm = new_ImmediateValue(prog, u); 364 addImmediate(imm); 365 } 366 return imm; 367 } 368 369 ImmediateValue * 370 BuildUtil::mkImm(uint64_t u) 371 { 372 ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0); 373 374 imm->reg.size = 8; 375 imm->reg.type = TYPE_U64; 376 imm->reg.data.u64 = u; 377 378 return imm; 379 } 380 381 ImmediateValue * 382 BuildUtil::mkImm(float f) 383 { 384 union { 385 float f32; 386 uint32_t u32; 387 } u; 388 u.f32 = f; 389 return mkImm(u.u32); 390 } 391 392 Value * 393 BuildUtil::loadImm(Value *dst, float f) 394 { 395 return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f)); 396 } 397 398 Value * 399 BuildUtil::loadImm(Value *dst, uint32_t u) 400 { 401 return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u)); 402 } 403 404 Value * 405 BuildUtil::loadImm(Value *dst, uint64_t u) 406 { 407 return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u)); 408 } 409 410 Symbol * 411 BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty, 412 uint32_t baseAddr) 413 { 414 Symbol *sym = new_Symbol(prog, file, fileIndex); 415 416 sym->setOffset(baseAddr); 417 sym->reg.type = ty; 418 sym->reg.size = typeSizeof(ty); 419 420 return sym; 421 } 422 423 Symbol * 424 BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex) 425 { 426 Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0); 427 428 assert(svIndex < 4 || 429 (svName == SV_CLIP_DISTANCE || svName == SV_TESS_FACTOR)); 430 431 switch (svName) { 432 case SV_POSITION: 433 case SV_FACE: 434 case SV_YDIR: 435 case SV_POINT_SIZE: 436 case SV_POINT_COORD: 437 case SV_CLIP_DISTANCE: 438 case SV_TESS_FACTOR: 439 sym->reg.type = TYPE_F32; 440 break; 441 default: 442 sym->reg.type = TYPE_U32; 443 break; 444 } 445 sym->reg.size = typeSizeof(sym->reg.type); 446 447 sym->reg.data.sv.sv = svName; 448 sym->reg.data.sv.index = svIndex; 449 450 return sym; 451 } 452 453 void 454 BuildUtil::DataArray::setup(unsigned array, unsigned arrayIdx, 455 uint32_t base, int len, int vecDim, int eltSize, 456 DataFile file, int8_t fileIdx) 457 { 458 this->array = array; 459 this->arrayIdx = arrayIdx; 460 this->baseAddr = base; 461 this->arrayLen = len; 462 this->vecDim = vecDim; 463 this->eltSize = eltSize; 464 this->file = file; 465 this->regOnly = !isMemoryFile(file); 466 467 if (!regOnly) { 468 baseSym = new_Symbol(up->getProgram(), file, fileIdx); 469 baseSym->setOffset(baseAddr); 470 baseSym->reg.size = eltSize; 471 } else { 472 baseSym = NULL; 473 } 474 } 475 476 Value * 477 BuildUtil::DataArray::acquire(ValueMap &m, int i, int c) 478 { 479 if (regOnly) { 480 Value *v = lookup(m, i, c); 481 if (!v) 482 v = insert(m, i, c, new_LValue(up->getFunction(), file)); 483 484 return v; 485 } else { 486 return up->getScratch(); 487 } 488 } 489 490 Value * 491 BuildUtil::DataArray::load(ValueMap &m, int i, int c, Value *ptr) 492 { 493 if (regOnly) { 494 Value *v = lookup(m, i, c); 495 if (!v) 496 v = insert(m, i, c, new_LValue(up->getFunction(), file)); 497 498 return v; 499 } else { 500 Value *sym = lookup(m, i, c); 501 if (!sym) 502 sym = insert(m, i, c, mkSymbol(i, c)); 503 504 return up->mkLoad(typeOfSize(eltSize), static_cast<Symbol *>(sym), ptr); 505 } 506 } 507 508 void 509 BuildUtil::DataArray::store(ValueMap &m, int i, int c, Value *ptr, Value *value) 510 { 511 if (regOnly) { 512 assert(!ptr); 513 if (!lookup(m, i, c)) 514 insert(m, i, c, value); 515 516 assert(lookup(m, i, c) == value); 517 } else { 518 Value *sym = lookup(m, i, c); 519 if (!sym) 520 sym = insert(m, i, c, mkSymbol(i, c)); 521 522 const DataType stTy = typeOfSize(value->reg.size); 523 524 up->mkStore(OP_STORE, stTy, static_cast<Symbol *>(sym), ptr, value); 525 } 526 } 527 528 Symbol * 529 BuildUtil::DataArray::mkSymbol(int i, int c) 530 { 531 const unsigned int idx = i * vecDim + c; 532 Symbol *sym = new_Symbol(up->getProgram(), file, 0); 533 534 assert(baseSym || (idx < arrayLen && c < vecDim)); 535 536 sym->reg.size = eltSize; 537 sym->reg.type = typeOfSize(eltSize); 538 sym->setAddress(baseSym, baseAddr + idx * eltSize); 539 return sym; 540 } 541 542 } // namespace nv50_ir 543