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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include "codegen/nv50_ir.h" 24 #include "codegen/nv50_ir_target.h" 25 26 #include <inttypes.h> 27 28 namespace nv50_ir { 29 30 enum TextStyle 31 { 32 TXT_DEFAULT, 33 TXT_GPR, 34 TXT_REGISTER, 35 TXT_FLAGS, 36 TXT_MEM, 37 TXT_IMMD, 38 TXT_BRA, 39 TXT_INSN 40 }; 41 42 static const char *_colour[8] = 43 { 44 "\x1b[00m", 45 "\x1b[34m", 46 "\x1b[35m", 47 "\x1b[35m", 48 "\x1b[36m", 49 "\x1b[33m", 50 "\x1b[37m", 51 "\x1b[32m" 52 }; 53 54 static const char *_nocolour[8] = 55 { 56 "", "", "", "", "", "", "", "" 57 }; 58 59 static const char **colour; 60 61 static void init_colours() 62 { 63 if (getenv("NV50_PROG_DEBUG_NO_COLORS") != NULL) 64 colour = _nocolour; 65 else 66 colour = _colour; 67 } 68 69 const char *operationStr[OP_LAST + 1] = 70 { 71 "nop", 72 "phi", 73 "union", 74 "split", 75 "merge", 76 "consec", 77 "mov", 78 "ld", 79 "st", 80 "add", 81 "sub", 82 "mul", 83 "div", 84 "mod", 85 "mad", 86 "fma", 87 "sad", 88 "shladd", 89 "abs", 90 "neg", 91 "not", 92 "and", 93 "or", 94 "xor", 95 "shl", 96 "shr", 97 "max", 98 "min", 99 "sat", 100 "ceil", 101 "floor", 102 "trunc", 103 "cvt", 104 "set and", 105 "set or", 106 "set xor", 107 "set", 108 "selp", 109 "slct", 110 "rcp", 111 "rsq", 112 "lg2", 113 "sin", 114 "cos", 115 "ex2", 116 "exp", 117 "log", 118 "presin", 119 "preex2", 120 "sqrt", 121 "pow", 122 "bra", 123 "call", 124 "ret", 125 "cont", 126 "break", 127 "preret", 128 "precont", 129 "prebreak", 130 "brkpt", 131 "joinat", 132 "join", 133 "discard", 134 "exit", 135 "membar", 136 "vfetch", 137 "pfetch", 138 "afetch", 139 "export", 140 "linterp", 141 "pinterp", 142 "emit", 143 "restart", 144 "tex", 145 "texbias", 146 "texlod", 147 "texfetch", 148 "texquery", 149 "texgrad", 150 "texgather", 151 "texquerylod", 152 "texcsaa", 153 "texprep", 154 "suldb", 155 "suldp", 156 "sustb", 157 "sustp", 158 "suredb", 159 "suredp", 160 "sulea", 161 "subfm", 162 "suclamp", 163 "sueau", 164 "suq", 165 "madsp", 166 "texbar", 167 "dfdx", 168 "dfdy", 169 "rdsv", 170 "wrsv", 171 "pixld", 172 "quadop", 173 "quadon", 174 "quadpop", 175 "popcnt", 176 "insbf", 177 "extbf", 178 "bfind", 179 "permt", 180 "atom", 181 "bar", 182 "vadd", 183 "vavg", 184 "vmin", 185 "vmax", 186 "vsad", 187 "vset", 188 "vshr", 189 "vshl", 190 "vsel", 191 "cctl", 192 "shfl", 193 "vote", 194 "bufq", 195 "(invalid)" 196 }; 197 198 static const char *atomSubOpStr[] = 199 { 200 "add", "min", "max", "inc", "dec", "and", "or", "xor", "cas", "exch" 201 }; 202 203 static const char *ldstSubOpStr[] = 204 { 205 "", "lock", "unlock" 206 }; 207 208 static const char *subfmOpStr[] = 209 { 210 "", "3d" 211 }; 212 213 static const char *shflOpStr[] = 214 { 215 "idx", "up", "down", "bfly" 216 }; 217 218 static const char *pixldOpStr[] = 219 { 220 "count", "covmask", "offset", "cent_offset", "sampleid" 221 }; 222 223 static const char *rcprsqOpStr[] = 224 { 225 "", "64h" 226 }; 227 228 static const char *emitOpStr[] = 229 { 230 "", "restart" 231 }; 232 233 static const char *cctlOpStr[] = 234 { 235 "", "", "", "", "", "iv", "ivall" 236 }; 237 238 static const char *barOpStr[] = 239 { 240 "sync", "arrive", "red and", "red or", "red popc" 241 }; 242 243 static const char *DataTypeStr[] = 244 { 245 "-", 246 "u8", "s8", 247 "u16", "s16", 248 "u32", "s32", 249 "u64", "s64", 250 "f16", "f32", "f64", 251 "b96", "b128" 252 }; 253 254 static const char *RoundModeStr[] = 255 { 256 "", "rm", "rz", "rp", "rni", "rmi", "rzi", "rpi" 257 }; 258 259 static const char *CondCodeStr[] = 260 { 261 "never", 262 "lt", 263 "eq", 264 "le", 265 "gt", 266 "ne", 267 "ge", 268 "", 269 "(invalid)", 270 "ltu", 271 "equ", 272 "leu", 273 "gtu", 274 "neu", 275 "geu", 276 "", 277 "no", 278 "nc", 279 "ns", 280 "na", 281 "a", 282 "s", 283 "c", 284 "o" 285 }; 286 287 static const char *SemanticStr[SV_LAST + 1] = 288 { 289 "POSITION", 290 "VERTEX_ID", 291 "INSTANCE_ID", 292 "INVOCATION_ID", 293 "PRIMITIVE_ID", 294 "VERTEX_COUNT", 295 "LAYER", 296 "VIEWPORT_INDEX", 297 "Y_DIR", 298 "FACE", 299 "POINT_SIZE", 300 "POINT_COORD", 301 "CLIP_DISTANCE", 302 "SAMPLE_INDEX", 303 "SAMPLE_POS", 304 "SAMPLE_MASK", 305 "TESS_OUTER", 306 "TESS_INNER", 307 "TESS_COORD", 308 "TID", 309 "CTAID", 310 "NTID", 311 "GRIDID", 312 "NCTAID", 313 "LANEID", 314 "PHYSID", 315 "NPHYSID", 316 "CLOCK", 317 "LBASE", 318 "SBASE", 319 "VERTEX_STRIDE", 320 "INVOCATION_INFO", 321 "THREAD_KILL", 322 "BASEVERTEX", 323 "BASEINSTANCE", 324 "DRAWID", 325 "WORK_DIM", 326 "LANEMASK_EQ", 327 "LANEMASK_LT", 328 "LANEMASK_LE", 329 "LANEMASK_GT", 330 "LANEMASK_GE", 331 "?", 332 "(INVALID)" 333 }; 334 335 static const char *interpStr[16] = 336 { 337 "pass", 338 "mul", 339 "flat", 340 "sc", 341 "cent pass", 342 "cent mul", 343 "cent flat", 344 "cent sc", 345 "off pass", 346 "off mul", 347 "off flat", 348 "off sc", 349 "samp pass", 350 "samp mul", 351 "samp flat", 352 "samp sc" 353 }; 354 355 #define PRINT(args...) \ 356 do { \ 357 pos += snprintf(&buf[pos], size - pos, args); \ 358 } while(0) 359 360 #define SPACE_PRINT(cond, args...) \ 361 do { \ 362 if (cond) \ 363 buf[pos++] = ' '; \ 364 pos += snprintf(&buf[pos], size - pos, args); \ 365 } while(0) 366 367 #define SPACE() \ 368 do { \ 369 if (pos < size) \ 370 buf[pos++] = ' '; \ 371 } while(0) 372 373 int Modifier::print(char *buf, size_t size) const 374 { 375 size_t pos = 0; 376 377 if (bits) 378 PRINT("%s", colour[TXT_INSN]); 379 380 size_t base = pos; 381 382 if (bits & NV50_IR_MOD_NOT) 383 PRINT("not"); 384 if (bits & NV50_IR_MOD_SAT) 385 SPACE_PRINT(pos > base && pos < size, "sat"); 386 if (bits & NV50_IR_MOD_NEG) 387 SPACE_PRINT(pos > base && pos < size, "neg"); 388 if (bits & NV50_IR_MOD_ABS) 389 SPACE_PRINT(pos > base && pos < size, "abs"); 390 391 return pos; 392 } 393 394 int LValue::print(char *buf, size_t size, DataType ty) const 395 { 396 const char *postFix = ""; 397 size_t pos = 0; 398 int idx = join->reg.data.id >= 0 ? join->reg.data.id : id; 399 char p = join->reg.data.id >= 0 ? '$' : '%'; 400 char r; 401 int col = TXT_DEFAULT; 402 403 switch (reg.file) { 404 case FILE_GPR: 405 r = 'r'; col = TXT_GPR; 406 if (reg.size == 2) { 407 if (p == '$') { 408 postFix = (idx & 1) ? "h" : "l"; 409 idx /= 2; 410 } else { 411 postFix = "s"; 412 } 413 } else 414 if (reg.size == 8) { 415 postFix = "d"; 416 } else 417 if (reg.size == 16) { 418 postFix = "q"; 419 } else 420 if (reg.size == 12) { 421 postFix = "t"; 422 } 423 break; 424 case FILE_PREDICATE: 425 r = 'p'; col = TXT_REGISTER; 426 if (reg.size == 2) 427 postFix = "d"; 428 else 429 if (reg.size == 4) 430 postFix = "q"; 431 break; 432 case FILE_FLAGS: 433 r = 'c'; col = TXT_FLAGS; 434 break; 435 case FILE_ADDRESS: 436 r = 'a'; col = TXT_REGISTER; 437 break; 438 default: 439 assert(!"invalid file for lvalue"); 440 r = '?'; 441 break; 442 } 443 444 PRINT("%s%c%c%i%s", colour[col], p, r, idx, postFix); 445 446 return pos; 447 } 448 449 int ImmediateValue::print(char *buf, size_t size, DataType ty) const 450 { 451 size_t pos = 0; 452 453 PRINT("%s", colour[TXT_IMMD]); 454 455 switch (ty) { 456 case TYPE_F32: PRINT("%f", reg.data.f32); break; 457 case TYPE_F64: PRINT("%f", reg.data.f64); break; 458 case TYPE_U8: PRINT("0x%02x", reg.data.u8); break; 459 case TYPE_S8: PRINT("%i", reg.data.s8); break; 460 case TYPE_U16: PRINT("0x%04x", reg.data.u16); break; 461 case TYPE_S16: PRINT("%i", reg.data.s16); break; 462 case TYPE_U32: PRINT("0x%08x", reg.data.u32); break; 463 case TYPE_S32: PRINT("%i", reg.data.s32); break; 464 case TYPE_U64: 465 case TYPE_S64: 466 default: 467 PRINT("0x%016" PRIx64, reg.data.u64); 468 break; 469 } 470 return pos; 471 } 472 473 int Symbol::print(char *buf, size_t size, DataType ty) const 474 { 475 return print(buf, size, NULL, NULL, ty); 476 } 477 478 int Symbol::print(char *buf, size_t size, 479 Value *rel, Value *dimRel, DataType ty) const 480 { 481 size_t pos = 0; 482 char c; 483 484 if (ty == TYPE_NONE) 485 ty = typeOfSize(reg.size); 486 487 if (reg.file == FILE_SYSTEM_VALUE) { 488 PRINT("%ssv[%s%s:%i%s", colour[TXT_MEM], 489 colour[TXT_REGISTER], 490 SemanticStr[reg.data.sv.sv], reg.data.sv.index, colour[TXT_MEM]); 491 if (rel) { 492 PRINT("%s+", colour[TXT_DEFAULT]); 493 pos += rel->print(&buf[pos], size - pos); 494 } 495 PRINT("%s]", colour[TXT_MEM]); 496 return pos; 497 } 498 499 switch (reg.file) { 500 case FILE_MEMORY_CONST: c = 'c'; break; 501 case FILE_SHADER_INPUT: c = 'a'; break; 502 case FILE_SHADER_OUTPUT: c = 'o'; break; 503 case FILE_MEMORY_BUFFER: c = 'b'; break; // Only used before lowering 504 case FILE_MEMORY_GLOBAL: c = 'g'; break; 505 case FILE_MEMORY_SHARED: c = 's'; break; 506 case FILE_MEMORY_LOCAL: c = 'l'; break; 507 default: 508 assert(!"invalid file"); 509 c = '?'; 510 break; 511 } 512 513 if (c == 'c') 514 PRINT("%s%c%i[", colour[TXT_MEM], c, reg.fileIndex); 515 else 516 PRINT("%s%c[", colour[TXT_MEM], c); 517 518 if (dimRel) { 519 pos += dimRel->print(&buf[pos], size - pos, TYPE_S32); 520 PRINT("%s][", colour[TXT_MEM]); 521 } 522 523 if (rel) { 524 pos += rel->print(&buf[pos], size - pos); 525 PRINT("%s%c", colour[TXT_DEFAULT], (reg.data.offset < 0) ? '-' : '+'); 526 } else { 527 assert(reg.data.offset >= 0); 528 } 529 PRINT("%s0x%x%s]", colour[TXT_IMMD], abs(reg.data.offset), colour[TXT_MEM]); 530 531 return pos; 532 } 533 534 void Instruction::print() const 535 { 536 #define BUFSZ 512 537 538 const size_t size = BUFSZ; 539 540 char buf[BUFSZ]; 541 int s, d; 542 size_t pos = 0; 543 544 PRINT("%s", colour[TXT_INSN]); 545 546 if (join) 547 PRINT("join "); 548 549 if (predSrc >= 0) { 550 const size_t pre = pos; 551 if (getSrc(predSrc)->reg.file == FILE_PREDICATE) { 552 if (cc == CC_NOT_P) 553 PRINT("not"); 554 } else { 555 PRINT("%s", CondCodeStr[cc]); 556 } 557 if (pos > pre) 558 SPACE(); 559 pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos); 560 PRINT(" %s", colour[TXT_INSN]); 561 } 562 563 if (saturate) 564 PRINT("sat "); 565 566 if (asFlow()) { 567 PRINT("%s", operationStr[op]); 568 if (asFlow()->indirect) 569 PRINT(" ind"); 570 if (asFlow()->absolute) 571 PRINT(" abs"); 572 if (op == OP_CALL && asFlow()->builtin) { 573 PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin); 574 } else 575 if (op == OP_CALL && asFlow()->target.fn) { 576 PRINT(" %s%s:%i", colour[TXT_BRA], 577 asFlow()->target.fn->getName(), 578 asFlow()->target.fn->getLabel()); 579 } else 580 if (asFlow()->target.bb) 581 PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId()); 582 } else { 583 PRINT("%s ", operationStr[op]); 584 if (op == OP_LINTERP || op == OP_PINTERP) 585 PRINT("%s ", interpStr[ipa]); 586 switch (op) { 587 case OP_SUREDP: 588 case OP_SUREDB: 589 case OP_ATOM: 590 if (subOp < ARRAY_SIZE(atomSubOpStr)) 591 PRINT("%s ", atomSubOpStr[subOp]); 592 break; 593 case OP_LOAD: 594 case OP_STORE: 595 if (subOp < ARRAY_SIZE(ldstSubOpStr)) 596 PRINT("%s ", ldstSubOpStr[subOp]); 597 break; 598 case OP_SUBFM: 599 if (subOp < ARRAY_SIZE(subfmOpStr)) 600 PRINT("%s ", subfmOpStr[subOp]); 601 break; 602 case OP_SHFL: 603 if (subOp < ARRAY_SIZE(shflOpStr)) 604 PRINT("%s ", shflOpStr[subOp]); 605 break; 606 case OP_PIXLD: 607 if (subOp < ARRAY_SIZE(pixldOpStr)) 608 PRINT("%s ", pixldOpStr[subOp]); 609 break; 610 case OP_RCP: 611 case OP_RSQ: 612 if (subOp < ARRAY_SIZE(rcprsqOpStr)) 613 PRINT("%s ", rcprsqOpStr[subOp]); 614 break; 615 case OP_EMIT: 616 if (subOp < ARRAY_SIZE(emitOpStr)) 617 PRINT("%s ", emitOpStr[subOp]); 618 break; 619 case OP_CCTL: 620 if (subOp < ARRAY_SIZE(cctlOpStr)) 621 PRINT("%s ", cctlOpStr[subOp]); 622 break; 623 case OP_BAR: 624 if (subOp < ARRAY_SIZE(barOpStr)) 625 PRINT("%s ", barOpStr[subOp]); 626 break; 627 default: 628 if (subOp) 629 PRINT("(SUBOP:%u) ", subOp); 630 break; 631 } 632 if (perPatch) 633 PRINT("patch "); 634 if (asTex()) 635 PRINT("%s %s$r%u $s%u %s", asTex()->tex.target.getName(), 636 colour[TXT_MEM], asTex()->tex.r, asTex()->tex.s, 637 colour[TXT_INSN]); 638 if (postFactor) 639 PRINT("x2^%i ", postFactor); 640 PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""), DataTypeStr[dType]); 641 } 642 643 if (rnd != ROUND_N) 644 PRINT(" %s", RoundModeStr[rnd]); 645 646 if (defExists(1)) 647 PRINT(" {"); 648 for (d = 0; defExists(d); ++d) { 649 SPACE(); 650 pos += getDef(d)->print(&buf[pos], size - pos); 651 } 652 if (d > 1) 653 PRINT(" %s}", colour[TXT_INSN]); 654 else 655 if (!d && !asFlow()) 656 PRINT(" %s#", colour[TXT_INSN]); 657 658 if (asCmp()) 659 PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]); 660 661 if (sType != dType) 662 PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]); 663 664 for (s = 0; srcExists(s); ++s) { 665 if (s == predSrc || src(s).usedAsPtr) 666 continue; 667 const size_t pre = pos; 668 SPACE(); 669 pos += src(s).mod.print(&buf[pos], BUFSZ - pos); 670 if (pos > pre + 1) 671 SPACE(); 672 if (src(s).isIndirect(0) || src(s).isIndirect(1)) 673 pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos, 674 getIndirect(s, 0), 675 getIndirect(s, 1)); 676 else 677 pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType); 678 } 679 if (exit) 680 PRINT("%s exit", colour[TXT_INSN]); 681 682 PRINT("%s", colour[TXT_DEFAULT]); 683 684 buf[MIN2(pos, BUFSZ - 1)] = 0; 685 686 INFO("%s (%u)\n", buf, encSize); 687 } 688 689 class PrintPass : public Pass 690 { 691 public: 692 PrintPass(bool omitLineNum) : serial(0), omit_serial(omitLineNum) { } 693 694 virtual bool visit(Function *); 695 virtual bool visit(BasicBlock *); 696 virtual bool visit(Instruction *); 697 698 private: 699 int serial; 700 bool omit_serial; 701 }; 702 703 bool 704 PrintPass::visit(Function *fn) 705 { 706 char str[16]; 707 708 INFO("\n%s:%i (", fn->getName(), fn->getLabel()); 709 710 if (!fn->outs.empty()) 711 INFO("out"); 712 for (std::deque<ValueRef>::iterator it = fn->outs.begin(); 713 it != fn->outs.end(); 714 ++it) { 715 it->get()->print(str, sizeof(str), typeOfSize(it->get()->reg.size)); 716 INFO(" %s", str); 717 } 718 719 if (!fn->ins.empty()) 720 INFO("%s%sin", colour[TXT_DEFAULT], fn->outs.empty() ? "" : ", "); 721 for (std::deque<ValueDef>::iterator it = fn->ins.begin(); 722 it != fn->ins.end(); 723 ++it) { 724 it->get()->print(str, sizeof(str), typeOfSize(it->get()->reg.size)); 725 INFO(" %s", str); 726 } 727 INFO("%s)\n", colour[TXT_DEFAULT]); 728 729 return true; 730 } 731 732 bool 733 PrintPass::visit(BasicBlock *bb) 734 { 735 #if 0 736 INFO("---\n"); 737 for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) 738 INFO(" <- BB:%i (%s)\n", 739 BasicBlock::get(ei.getNode())->getId(), 740 ei.getEdge()->typeStr()); 741 #endif 742 INFO("BB:%i (%u instructions) - ", bb->getId(), bb->getInsnCount()); 743 744 if (bb->idom()) 745 INFO("idom = BB:%i, ", bb->idom()->getId()); 746 747 INFO("df = { "); 748 for (DLList::Iterator df = bb->getDF().iterator(); !df.end(); df.next()) 749 INFO("BB:%i ", BasicBlock::get(df)->getId()); 750 751 INFO("}\n"); 752 753 for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) 754 INFO(" -> BB:%i (%s)\n", 755 BasicBlock::get(ei.getNode())->getId(), 756 ei.getEdge()->typeStr()); 757 758 return true; 759 } 760 761 bool 762 PrintPass::visit(Instruction *insn) 763 { 764 if (omit_serial) 765 INFO(" "); 766 else 767 INFO("%3i: ", serial); 768 serial++; 769 insn->print(); 770 return true; 771 } 772 773 void 774 Function::print() 775 { 776 PrintPass pass(prog->driver->omitLineNum); 777 pass.run(this, true, false); 778 } 779 780 void 781 Program::print() 782 { 783 PrintPass pass(driver->omitLineNum); 784 init_colours(); 785 pass.run(this, true, false); 786 } 787 788 void 789 Function::printLiveIntervals() const 790 { 791 INFO("printing live intervals ...\n"); 792 793 for (ArrayList::Iterator it = allLValues.iterator(); !it.end(); it.next()) { 794 const Value *lval = Value::get(it)->asLValue(); 795 if (lval && !lval->livei.isEmpty()) { 796 INFO("livei(%%%i): ", lval->id); 797 lval->livei.print(); 798 } 799 } 800 } 801 802 } // namespace nv50_ir 803