• 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 #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