• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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