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
init_colours()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
print(char * buf,size_t size) const373 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
print(char * buf,size_t size,DataType ty) const394 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
print(char * buf,size_t size,DataType ty) const449 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
print(char * buf,size_t size,DataType ty) const473 int Symbol::print(char *buf, size_t size, DataType ty) const
474 {
475 return print(buf, size, NULL, NULL, ty);
476 }
477
print(char * buf,size_t size,Value * rel,Value * dimRel,DataType ty) const478 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
print() const534 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:
PrintPass(bool omitLineNum)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
visit(Function * fn)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
visit(BasicBlock * bb)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
visit(Instruction * insn)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
print()774 Function::print()
775 {
776 PrintPass pass(prog->driver->omitLineNum);
777 pass.run(this, true, false);
778 }
779
780 void
print()781 Program::print()
782 {
783 PrintPass pass(driver->omitLineNum);
784 init_colours();
785 pass.run(this, true, false);
786 }
787
788 void
printLiveIntervals() const789 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