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
init_colours()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
print(char * buf,size_t size) const369 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
print(char * buf,size_t size,DataType ty) const390 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
print(char * buf,size_t size,DataType ty) const445 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
print(char * buf,size_t size,DataType ty) const469 int Symbol::print(char *buf, size_t size, DataType ty) const
470 {
471 return print(buf, size, NULL, NULL, ty);
472 }
473
print(char * buf,size_t size,Value * rel,Value * dimRel,DataType ty) const474 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
print() const530 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:
PrintPass()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
visit(Function * fn)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
visit(BasicBlock * bb)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
visit(Instruction * insn)757 PrintPass::visit(Instruction *insn)
758 {
759 INFO("%3i: ", serial++);
760 insn->print();
761 return true;
762 }
763
764 void
print()765 Function::print()
766 {
767 PrintPass pass;
768 pass.run(this, true, false);
769 }
770
771 void
print()772 Program::print()
773 {
774 PrintPass pass;
775 init_colours();
776 pass.run(this, true, false);
777 }
778
779 void
printLiveIntervals() const780 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