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