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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "nv50_ir.h"
24 #include "nv50_ir_target.h"
25
26 namespace nv50_ir {
27
28 enum TextStyle
29 {
30 TXT_DEFAULT,
31 TXT_GPR,
32 TXT_REGISTER,
33 TXT_FLAGS,
34 TXT_MEM,
35 TXT_IMMD,
36 TXT_BRA,
37 TXT_INSN
38 };
39
40 static const char *_colour[8] =
41 {
42 "\x1b[00m",
43 "\x1b[34m",
44 "\x1b[35m",
45 "\x1b[35m",
46 "\x1b[36m",
47 "\x1b[33m",
48 "\x1b[37m",
49 "\x1b[32m"
50 };
51
52 static const char *_nocolour[8] =
53 {
54 "", "", "", "", "", "", "", ""
55 };
56
57 static const char **colour;
58
init_colours()59 static void init_colours()
60 {
61 if (getenv("NV50_PROG_DEBUG_NO_COLORS") != NULL)
62 colour = _nocolour;
63 else
64 colour = _colour;
65 }
66
67 static const char *OpClassStr[OPCLASS_OTHER + 1] =
68 {
69 "MOVE",
70 "LOAD",
71 "STORE",
72 "ARITH",
73 "SHIFT",
74 "SFU",
75 "LOGIC",
76 "COMPARE",
77 "CONVERT",
78 "ATOMIC",
79 "TEXTURE",
80 "SURFACE",
81 "FLOW",
82 "(INVALID)",
83 "PSEUDO",
84 "OTHER"
85 };
86
87 const char *operationStr[OP_LAST + 1] =
88 {
89 "nop",
90 "phi",
91 "union",
92 "split",
93 "merge",
94 "consec",
95 "mov",
96 "ld",
97 "st",
98 "add",
99 "sub",
100 "mul",
101 "div",
102 "mod",
103 "mad",
104 "fma",
105 "sad",
106 "abs",
107 "neg",
108 "not",
109 "and",
110 "or",
111 "xor",
112 "shl",
113 "shr",
114 "max",
115 "min",
116 "sat",
117 "ceil",
118 "floor",
119 "trunc",
120 "cvt",
121 "set and",
122 "set or",
123 "set xor",
124 "set",
125 "selp",
126 "slct",
127 "rcp",
128 "rsq",
129 "lg2",
130 "sin",
131 "cos",
132 "ex2",
133 "exp",
134 "log",
135 "presin",
136 "preex2",
137 "sqrt",
138 "pow",
139 "bra",
140 "call",
141 "ret",
142 "cont",
143 "break",
144 "preret",
145 "precont",
146 "prebreak",
147 "brkpt",
148 "joinat",
149 "join",
150 "discard",
151 "exit",
152 "barrier",
153 "vfetch",
154 "pfetch",
155 "export",
156 "linterp",
157 "pinterp",
158 "emit",
159 "restart",
160 "tex",
161 "texbias",
162 "texlod",
163 "texfetch",
164 "texquery",
165 "texgrad",
166 "texgather",
167 "texcsaa",
168 "suld",
169 "sust",
170 "dfdx",
171 "dfdy",
172 "rdsv",
173 "wrsv",
174 "pixld",
175 "quadop",
176 "quadon",
177 "quadpop",
178 "popcnt",
179 "insbf",
180 "extbf",
181 "texbar",
182 "(invalid)"
183 };
184
185 static const char *DataTypeStr[] =
186 {
187 "-",
188 "u8", "s8",
189 "u16", "s16",
190 "u32", "s32",
191 "u64", "s64",
192 "f16", "f32", "f64",
193 "b96", "b128"
194 };
195
196 static const char *RoundModeStr[] =
197 {
198 "", "rm", "rz", "rp", "rni", "rmi", "rzi", "rpi"
199 };
200
201 static const char *CondCodeStr[] =
202 {
203 "never",
204 "lt",
205 "eq",
206 "le",
207 "gt",
208 "ne",
209 "ge",
210 "",
211 "(invalid)",
212 "ltu",
213 "equ",
214 "leu",
215 "gtu",
216 "neu",
217 "geu",
218 "",
219 "no",
220 "nc",
221 "ns",
222 "na",
223 "a",
224 "s",
225 "c",
226 "o"
227 };
228
229 static const char *SemanticStr[SV_LAST + 1] =
230 {
231 "POSITION",
232 "VERTEX_ID",
233 "INSTANCE_ID",
234 "INVOCATION_ID",
235 "PRIMITIVE_ID",
236 "VERTEX_COUNT",
237 "LAYER",
238 "VIEWPORT_INDEX",
239 "Y_DIR",
240 "FACE",
241 "POINT_SIZE",
242 "POINT_COORD",
243 "CLIP_DISTANCE",
244 "SAMPLE_INDEX",
245 "TESS_FACTOR",
246 "TESS_COORD",
247 "TID",
248 "CTAID",
249 "NTID",
250 "GRIDID",
251 "NCTAID",
252 "LANEID",
253 "PHYSID",
254 "NPHYSID",
255 "CLOCK",
256 "LBASE",
257 "SBASE",
258 "?",
259 "(INVALID)"
260 };
261
262 static const char *interpStr[16] =
263 {
264 "pass",
265 "mul",
266 "flat",
267 "sc",
268 "cent pass",
269 "cent mul",
270 "cent flat",
271 "cent sc",
272 "off pass",
273 "off mul",
274 "off flat",
275 "off sc",
276 "samp pass",
277 "samp mul",
278 "samp flat",
279 "samp sc"
280 };
281
282 #define PRINT(args...) \
283 do { \
284 pos += snprintf(&buf[pos], size - pos, args); \
285 } while(0)
286
287 #define SPACE_PRINT(cond, args...) \
288 do { \
289 if (cond) \
290 buf[pos++] = ' '; \
291 pos += snprintf(&buf[pos], size - pos, args); \
292 } while(0)
293
294 #define SPACE() \
295 do { \
296 if (pos < size) \
297 buf[pos++] = ' '; \
298 } while(0)
299
print(char * buf,size_t size) const300 int Modifier::print(char *buf, size_t size) const
301 {
302 size_t pos = 0;
303
304 if (bits)
305 PRINT("%s", colour[TXT_INSN]);
306
307 size_t base = pos;
308
309 if (bits & NV50_IR_MOD_NOT)
310 PRINT("not");
311 if (bits & NV50_IR_MOD_SAT)
312 SPACE_PRINT(pos > base && pos < size, "sat");
313 if (bits & NV50_IR_MOD_NEG)
314 SPACE_PRINT(pos > base && pos < size, "neg");
315 if (bits & NV50_IR_MOD_ABS)
316 SPACE_PRINT(pos > base && pos < size, "abs");
317
318 return pos;
319 }
320
print(char * buf,size_t size,DataType ty) const321 int LValue::print(char *buf, size_t size, DataType ty) const
322 {
323 const char *postFix = "";
324 size_t pos = 0;
325 int idx = join->reg.data.id >= 0 ? join->reg.data.id : id;
326 char p = join->reg.data.id >= 0 ? '$' : '%';
327 char r;
328 int col = TXT_DEFAULT;
329
330 switch (reg.file) {
331 case FILE_GPR:
332 r = 'r'; col = TXT_GPR;
333 if (reg.size == 2) {
334 if (p == '$') {
335 postFix = (idx & 1) ? "h" : "l";
336 idx /= 2;
337 } else {
338 postFix = "s";
339 }
340 } else
341 if (reg.size == 8) {
342 postFix = "d";
343 } else
344 if (reg.size == 16) {
345 postFix = "q";
346 } else
347 if (reg.size == 12) {
348 postFix = "t";
349 }
350 break;
351 case FILE_PREDICATE:
352 r = 'p'; col = TXT_REGISTER;
353 if (reg.size == 2)
354 postFix = "d";
355 else
356 if (reg.size == 4)
357 postFix = "q";
358 break;
359 case FILE_FLAGS:
360 r = 'c'; col = TXT_FLAGS;
361 break;
362 case FILE_ADDRESS:
363 r = 'a'; col = TXT_REGISTER;
364 break;
365 default:
366 assert(!"invalid file for lvalue");
367 r = '?';
368 break;
369 }
370
371 PRINT("%s%c%c%i%s", colour[col], p, r, idx, postFix);
372
373 return pos;
374 }
375
print(char * buf,size_t size,DataType ty) const376 int ImmediateValue::print(char *buf, size_t size, DataType ty) const
377 {
378 size_t pos = 0;
379
380 PRINT("%s", colour[TXT_IMMD]);
381
382 switch (ty) {
383 case TYPE_F32: PRINT("%f", reg.data.f32); break;
384 case TYPE_F64: PRINT("%f", reg.data.f64); break;
385 case TYPE_U8: PRINT("0x%02x", reg.data.u8); break;
386 case TYPE_S8: PRINT("%i", reg.data.s8); break;
387 case TYPE_U16: PRINT("0x%04x", reg.data.u16); break;
388 case TYPE_S16: PRINT("%i", reg.data.s16); break;
389 case TYPE_U32: PRINT("0x%08x", reg.data.u32); break;
390 case TYPE_S32: PRINT("%i", reg.data.s32); break;
391 case TYPE_U64:
392 case TYPE_S64:
393 default:
394 PRINT("0x%016lx", reg.data.u64);
395 break;
396 }
397 return pos;
398 }
399
print(char * buf,size_t size,DataType ty) const400 int Symbol::print(char *buf, size_t size, DataType ty) const
401 {
402 return print(buf, size, NULL, NULL, ty);
403 }
404
print(char * buf,size_t size,Value * rel,Value * dimRel,DataType ty) const405 int Symbol::print(char *buf, size_t size,
406 Value *rel, Value *dimRel, DataType ty) const
407 {
408 size_t pos = 0;
409 char c;
410
411 if (ty == TYPE_NONE)
412 ty = typeOfSize(reg.size);
413
414 if (reg.file == FILE_SYSTEM_VALUE) {
415 PRINT("%ssv[%s%s:%i%s", colour[TXT_MEM],
416 colour[TXT_REGISTER],
417 SemanticStr[reg.data.sv.sv], reg.data.sv.index, colour[TXT_MEM]);
418 if (rel) {
419 PRINT("%s+", colour[TXT_DEFAULT]);
420 pos += rel->print(&buf[pos], size - pos);
421 }
422 PRINT("%s]", colour[TXT_MEM]);
423 return pos;
424 }
425
426 switch (reg.file) {
427 case FILE_MEMORY_CONST: c = 'c'; break;
428 case FILE_SHADER_INPUT: c = 'a'; break;
429 case FILE_SHADER_OUTPUT: c = 'o'; break;
430 case FILE_MEMORY_GLOBAL: c = 'g'; break;
431 case FILE_MEMORY_SHARED: c = 's'; break;
432 case FILE_MEMORY_LOCAL: c = 'l'; break;
433 default:
434 assert(!"invalid file");
435 c = '?';
436 break;
437 }
438
439 if (c == 'c')
440 PRINT("%s%c%i[", colour[TXT_MEM], c, reg.fileIndex);
441 else
442 PRINT("%s%c[", colour[TXT_MEM], c);
443
444 if (dimRel) {
445 pos += dimRel->print(&buf[pos], size - pos, TYPE_S32);
446 PRINT("%s][", colour[TXT_MEM]);
447 }
448
449 if (rel) {
450 pos += rel->print(&buf[pos], size - pos);
451 PRINT("%s%c", colour[TXT_DEFAULT], (reg.data.offset < 0) ? '-' : '+');
452 } else {
453 assert(reg.data.offset >= 0);
454 }
455 PRINT("%s0x%x%s]", colour[TXT_IMMD], abs(reg.data.offset), colour[TXT_MEM]);
456
457 return pos;
458 }
459
print() const460 void Instruction::print() const
461 {
462 #define BUFSZ 512
463
464 const size_t size = BUFSZ;
465
466 char buf[BUFSZ];
467 int s, d;
468 size_t pos = 0;
469
470 PRINT("%s", colour[TXT_INSN]);
471
472 if (join)
473 PRINT("join ");
474
475 if (predSrc >= 0) {
476 const size_t pre = pos;
477 if (getSrc(predSrc)->reg.file == FILE_PREDICATE) {
478 if (cc == CC_NOT_P)
479 PRINT("not");
480 } else {
481 PRINT("%s", CondCodeStr[cc]);
482 }
483 if (pos > pre)
484 SPACE();
485 pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos);
486 PRINT(" %s", colour[TXT_INSN]);
487 }
488
489 if (saturate)
490 PRINT("sat ");
491
492 if (asFlow()) {
493 PRINT("%s", operationStr[op]);
494 if (op == OP_CALL && asFlow()->builtin) {
495 PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin);
496 } else
497 if (op == OP_CALL && asFlow()->target.fn) {
498 PRINT(" %s%s:%i", colour[TXT_BRA],
499 asFlow()->target.fn->getName(),
500 asFlow()->target.fn->getLabel());
501 } else
502 if (asFlow()->target.bb)
503 PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId());
504 } else {
505 PRINT("%s ", operationStr[op]);
506 if (op == OP_LINTERP || op == OP_PINTERP)
507 PRINT("%s ", interpStr[ipa]);
508 if (subOp)
509 PRINT("(SUBOP:%u) ", subOp);
510 if (perPatch)
511 PRINT("patch ");
512 if (asTex())
513 PRINT("%s ", asTex()->tex.target.getName());
514 if (postFactor)
515 PRINT("x2^%i ", postFactor);
516 PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""), DataTypeStr[dType]);
517 }
518
519 if (rnd != ROUND_N)
520 PRINT(" %s", RoundModeStr[rnd]);
521
522 if (defExists(1))
523 PRINT(" {");
524 for (d = 0; defExists(d); ++d) {
525 SPACE();
526 pos += getDef(d)->print(&buf[pos], size - pos);
527 }
528 if (d > 1)
529 PRINT(" %s}", colour[TXT_INSN]);
530 else
531 if (!d && !asFlow())
532 PRINT(" %s#", colour[TXT_INSN]);
533
534 if (asCmp())
535 PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]);
536
537 if (sType != dType)
538 PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]);
539
540 for (s = 0; srcExists(s); ++s) {
541 if (s == predSrc || src(s).usedAsPtr)
542 continue;
543 const size_t pre = pos;
544 SPACE();
545 pos += src(s).mod.print(&buf[pos], BUFSZ - pos);
546 if (pos > pre + 1)
547 SPACE();
548 if (src(s).isIndirect(0) || src(s).isIndirect(1))
549 pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos,
550 getIndirect(s, 0),
551 getIndirect(s, 1));
552 else
553 pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType);
554 }
555 if (exit)
556 PRINT("%s exit", colour[TXT_INSN]);
557
558 PRINT("%s", colour[TXT_DEFAULT]);
559
560 buf[MIN2(pos, BUFSZ - 1)] = 0;
561
562 INFO("%s (%u)\n", buf, encSize);
563 }
564
565 class PrintPass : public Pass
566 {
567 public:
PrintPass()568 PrintPass() : serial(0) { }
569
570 virtual bool visit(Function *);
571 virtual bool visit(BasicBlock *);
572 virtual bool visit(Instruction *);
573
574 private:
575 int serial;
576 };
577
578 bool
visit(Function * fn)579 PrintPass::visit(Function *fn)
580 {
581 INFO("\n%s:%i\n", fn->getName(), fn->getLabel());
582
583 return true;
584 }
585
586 bool
visit(BasicBlock * bb)587 PrintPass::visit(BasicBlock *bb)
588 {
589 #if 0
590 INFO("---\n");
591 for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next())
592 INFO(" <- BB:%i (%s)\n",
593 BasicBlock::get(ei.getNode())->getId(),
594 ei.getEdge()->typeStr());
595 #endif
596 INFO("BB:%i (%u instructions) - ", bb->getId(), bb->getInsnCount());
597
598 if (bb->idom())
599 INFO("idom = BB:%i, ", bb->idom()->getId());
600
601 INFO("df = { ");
602 for (DLList::Iterator df = bb->getDF().iterator(); !df.end(); df.next())
603 INFO("BB:%i ", BasicBlock::get(df)->getId());
604
605 INFO("}\n");
606
607 for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next())
608 INFO(" -> BB:%i (%s)\n",
609 BasicBlock::get(ei.getNode())->getId(),
610 ei.getEdge()->typeStr());
611
612 return true;
613 }
614
615 bool
visit(Instruction * insn)616 PrintPass::visit(Instruction *insn)
617 {
618 INFO("%3i: ", serial++);
619 insn->print();
620 return true;
621 }
622
623 void
print()624 Function::print()
625 {
626 PrintPass pass;
627 pass.run(this, true, false);
628 }
629
630 void
print()631 Program::print()
632 {
633 PrintPass pass;
634 init_colours();
635 pass.run(this, true, false);
636 }
637
638 void
printLiveIntervals() const639 Function::printLiveIntervals() const
640 {
641 INFO("printing live intervals ...\n");
642
643 for (ArrayList::Iterator it = allLValues.iterator(); !it.end(); it.next()) {
644 const Value *lval = Value::get(it)->asLValue();
645 if (lval && !lval->livei.isEmpty()) {
646 INFO("livei(%%%i): ", lval->id);
647 lval->livei.print();
648 }
649 }
650 }
651
652 } // namespace nv50_ir
653