nv50/ir: print OP_SUREDB subops in debug mode
[mesa.git] / src / gallium / drivers / nouveau / codegen / nv50_ir_print.cpp
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
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 "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 *DataTypeStr[] =
234 {
235 "-",
236 "u8", "s8",
237 "u16", "s16",
238 "u32", "s32",
239 "u64", "s64",
240 "f16", "f32", "f64",
241 "b96", "b128"
242 };
243
244 static const char *RoundModeStr[] =
245 {
246 "", "rm", "rz", "rp", "rni", "rmi", "rzi", "rpi"
247 };
248
249 static const char *CondCodeStr[] =
250 {
251 "never",
252 "lt",
253 "eq",
254 "le",
255 "gt",
256 "ne",
257 "ge",
258 "",
259 "(invalid)",
260 "ltu",
261 "equ",
262 "leu",
263 "gtu",
264 "neu",
265 "geu",
266 "",
267 "no",
268 "nc",
269 "ns",
270 "na",
271 "a",
272 "s",
273 "c",
274 "o"
275 };
276
277 static const char *SemanticStr[SV_LAST + 1] =
278 {
279 "POSITION",
280 "VERTEX_ID",
281 "INSTANCE_ID",
282 "INVOCATION_ID",
283 "PRIMITIVE_ID",
284 "VERTEX_COUNT",
285 "LAYER",
286 "VIEWPORT_INDEX",
287 "Y_DIR",
288 "FACE",
289 "POINT_SIZE",
290 "POINT_COORD",
291 "CLIP_DISTANCE",
292 "SAMPLE_INDEX",
293 "SAMPLE_POS",
294 "SAMPLE_MASK",
295 "TESS_OUTER",
296 "TESS_INNER",
297 "TESS_COORD",
298 "TID",
299 "CTAID",
300 "NTID",
301 "GRIDID",
302 "NCTAID",
303 "LANEID",
304 "PHYSID",
305 "NPHYSID",
306 "CLOCK",
307 "LBASE",
308 "SBASE",
309 "VERTEX_STRIDE",
310 "INVOCATION_INFO",
311 "THREAD_KILL",
312 "BASEVERTEX",
313 "BASEINSTANCE",
314 "DRAWID",
315 "WORK_DIM",
316 "?",
317 "(INVALID)"
318 };
319
320 static const char *interpStr[16] =
321 {
322 "pass",
323 "mul",
324 "flat",
325 "sc",
326 "cent pass",
327 "cent mul",
328 "cent flat",
329 "cent sc",
330 "off pass",
331 "off mul",
332 "off flat",
333 "off sc",
334 "samp pass",
335 "samp mul",
336 "samp flat",
337 "samp sc"
338 };
339
340 #define PRINT(args...) \
341 do { \
342 pos += snprintf(&buf[pos], size - pos, args); \
343 } while(0)
344
345 #define SPACE_PRINT(cond, args...) \
346 do { \
347 if (cond) \
348 buf[pos++] = ' '; \
349 pos += snprintf(&buf[pos], size - pos, args); \
350 } while(0)
351
352 #define SPACE() \
353 do { \
354 if (pos < size) \
355 buf[pos++] = ' '; \
356 } while(0)
357
358 int Modifier::print(char *buf, size_t size) const
359 {
360 size_t pos = 0;
361
362 if (bits)
363 PRINT("%s", colour[TXT_INSN]);
364
365 size_t base = pos;
366
367 if (bits & NV50_IR_MOD_NOT)
368 PRINT("not");
369 if (bits & NV50_IR_MOD_SAT)
370 SPACE_PRINT(pos > base && pos < size, "sat");
371 if (bits & NV50_IR_MOD_NEG)
372 SPACE_PRINT(pos > base && pos < size, "neg");
373 if (bits & NV50_IR_MOD_ABS)
374 SPACE_PRINT(pos > base && pos < size, "abs");
375
376 return pos;
377 }
378
379 int LValue::print(char *buf, size_t size, DataType ty) const
380 {
381 const char *postFix = "";
382 size_t pos = 0;
383 int idx = join->reg.data.id >= 0 ? join->reg.data.id : id;
384 char p = join->reg.data.id >= 0 ? '$' : '%';
385 char r;
386 int col = TXT_DEFAULT;
387
388 switch (reg.file) {
389 case FILE_GPR:
390 r = 'r'; col = TXT_GPR;
391 if (reg.size == 2) {
392 if (p == '$') {
393 postFix = (idx & 1) ? "h" : "l";
394 idx /= 2;
395 } else {
396 postFix = "s";
397 }
398 } else
399 if (reg.size == 8) {
400 postFix = "d";
401 } else
402 if (reg.size == 16) {
403 postFix = "q";
404 } else
405 if (reg.size == 12) {
406 postFix = "t";
407 }
408 break;
409 case FILE_PREDICATE:
410 r = 'p'; col = TXT_REGISTER;
411 if (reg.size == 2)
412 postFix = "d";
413 else
414 if (reg.size == 4)
415 postFix = "q";
416 break;
417 case FILE_FLAGS:
418 r = 'c'; col = TXT_FLAGS;
419 break;
420 case FILE_ADDRESS:
421 r = 'a'; col = TXT_REGISTER;
422 break;
423 default:
424 assert(!"invalid file for lvalue");
425 r = '?';
426 break;
427 }
428
429 PRINT("%s%c%c%i%s", colour[col], p, r, idx, postFix);
430
431 return pos;
432 }
433
434 int ImmediateValue::print(char *buf, size_t size, DataType ty) const
435 {
436 size_t pos = 0;
437
438 PRINT("%s", colour[TXT_IMMD]);
439
440 switch (ty) {
441 case TYPE_F32: PRINT("%f", reg.data.f32); break;
442 case TYPE_F64: PRINT("%f", reg.data.f64); break;
443 case TYPE_U8: PRINT("0x%02x", reg.data.u8); break;
444 case TYPE_S8: PRINT("%i", reg.data.s8); break;
445 case TYPE_U16: PRINT("0x%04x", reg.data.u16); break;
446 case TYPE_S16: PRINT("%i", reg.data.s16); break;
447 case TYPE_U32: PRINT("0x%08x", reg.data.u32); break;
448 case TYPE_S32: PRINT("%i", reg.data.s32); break;
449 case TYPE_U64:
450 case TYPE_S64:
451 default:
452 PRINT("0x%016" PRIx64, reg.data.u64);
453 break;
454 }
455 return pos;
456 }
457
458 int Symbol::print(char *buf, size_t size, DataType ty) const
459 {
460 return print(buf, size, NULL, NULL, ty);
461 }
462
463 int Symbol::print(char *buf, size_t size,
464 Value *rel, Value *dimRel, DataType ty) const
465 {
466 size_t pos = 0;
467 char c;
468
469 if (ty == TYPE_NONE)
470 ty = typeOfSize(reg.size);
471
472 if (reg.file == FILE_SYSTEM_VALUE) {
473 PRINT("%ssv[%s%s:%i%s", colour[TXT_MEM],
474 colour[TXT_REGISTER],
475 SemanticStr[reg.data.sv.sv], reg.data.sv.index, colour[TXT_MEM]);
476 if (rel) {
477 PRINT("%s+", colour[TXT_DEFAULT]);
478 pos += rel->print(&buf[pos], size - pos);
479 }
480 PRINT("%s]", colour[TXT_MEM]);
481 return pos;
482 }
483
484 switch (reg.file) {
485 case FILE_MEMORY_CONST: c = 'c'; break;
486 case FILE_SHADER_INPUT: c = 'a'; break;
487 case FILE_SHADER_OUTPUT: c = 'o'; break;
488 case FILE_MEMORY_BUFFER: c = 'b'; break; // Only used before lowering
489 case FILE_MEMORY_GLOBAL: c = 'g'; break;
490 case FILE_MEMORY_SHARED: c = 's'; break;
491 case FILE_MEMORY_LOCAL: c = 'l'; break;
492 default:
493 assert(!"invalid file");
494 c = '?';
495 break;
496 }
497
498 if (c == 'c')
499 PRINT("%s%c%i[", colour[TXT_MEM], c, reg.fileIndex);
500 else
501 PRINT("%s%c[", colour[TXT_MEM], c);
502
503 if (dimRel) {
504 pos += dimRel->print(&buf[pos], size - pos, TYPE_S32);
505 PRINT("%s][", colour[TXT_MEM]);
506 }
507
508 if (rel) {
509 pos += rel->print(&buf[pos], size - pos);
510 PRINT("%s%c", colour[TXT_DEFAULT], (reg.data.offset < 0) ? '-' : '+');
511 } else {
512 assert(reg.data.offset >= 0);
513 }
514 PRINT("%s0x%x%s]", colour[TXT_IMMD], abs(reg.data.offset), colour[TXT_MEM]);
515
516 return pos;
517 }
518
519 void Instruction::print() const
520 {
521 #define BUFSZ 512
522
523 const size_t size = BUFSZ;
524
525 char buf[BUFSZ];
526 int s, d;
527 size_t pos = 0;
528
529 PRINT("%s", colour[TXT_INSN]);
530
531 if (join)
532 PRINT("join ");
533
534 if (predSrc >= 0) {
535 const size_t pre = pos;
536 if (getSrc(predSrc)->reg.file == FILE_PREDICATE) {
537 if (cc == CC_NOT_P)
538 PRINT("not");
539 } else {
540 PRINT("%s", CondCodeStr[cc]);
541 }
542 if (pos > pre)
543 SPACE();
544 pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos);
545 PRINT(" %s", colour[TXT_INSN]);
546 }
547
548 if (saturate)
549 PRINT("sat ");
550
551 if (asFlow()) {
552 PRINT("%s", operationStr[op]);
553 if (asFlow()->indirect)
554 PRINT(" ind");
555 if (asFlow()->absolute)
556 PRINT(" abs");
557 if (op == OP_CALL && asFlow()->builtin) {
558 PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin);
559 } else
560 if (op == OP_CALL && asFlow()->target.fn) {
561 PRINT(" %s%s:%i", colour[TXT_BRA],
562 asFlow()->target.fn->getName(),
563 asFlow()->target.fn->getLabel());
564 } else
565 if (asFlow()->target.bb)
566 PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId());
567 } else {
568 PRINT("%s ", operationStr[op]);
569 if (op == OP_LINTERP || op == OP_PINTERP)
570 PRINT("%s ", interpStr[ipa]);
571 switch (op) {
572 case OP_SUREDP:
573 case OP_SUREDB:
574 case OP_ATOM:
575 if (subOp < ARRAY_SIZE(atomSubOpStr))
576 PRINT("%s ", atomSubOpStr[subOp]);
577 break;
578 case OP_LOAD:
579 case OP_STORE:
580 if (subOp < ARRAY_SIZE(ldstSubOpStr))
581 PRINT("%s ", ldstSubOpStr[subOp]);
582 break;
583 case OP_SUBFM:
584 if (subOp < ARRAY_SIZE(subfmOpStr))
585 PRINT("%s ", subfmOpStr[subOp]);
586 break;
587 case OP_SHFL:
588 if (subOp < ARRAY_SIZE(shflOpStr))
589 PRINT("%s ", shflOpStr[subOp]);
590 break;
591 case OP_PIXLD:
592 if (subOp < ARRAY_SIZE(pixldOpStr))
593 PRINT("%s ", pixldOpStr[subOp]);
594 break;
595 case OP_RCP:
596 case OP_RSQ:
597 if (subOp < ARRAY_SIZE(rcprsqOpStr))
598 PRINT("%s ", rcprsqOpStr[subOp]);
599 break;
600 case OP_EMIT:
601 if (subOp < ARRAY_SIZE(emitOpStr))
602 PRINT("%s ", emitOpStr[subOp]);
603 break;
604 default:
605 if (subOp)
606 PRINT("(SUBOP:%u) ", subOp);
607 break;
608 }
609 if (perPatch)
610 PRINT("patch ");
611 if (asTex())
612 PRINT("%s %s$r%u $s%u %s", asTex()->tex.target.getName(),
613 colour[TXT_MEM], asTex()->tex.r, asTex()->tex.s,
614 colour[TXT_INSN]);
615 if (postFactor)
616 PRINT("x2^%i ", postFactor);
617 PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""), DataTypeStr[dType]);
618 }
619
620 if (rnd != ROUND_N)
621 PRINT(" %s", RoundModeStr[rnd]);
622
623 if (defExists(1))
624 PRINT(" {");
625 for (d = 0; defExists(d); ++d) {
626 SPACE();
627 pos += getDef(d)->print(&buf[pos], size - pos);
628 }
629 if (d > 1)
630 PRINT(" %s}", colour[TXT_INSN]);
631 else
632 if (!d && !asFlow())
633 PRINT(" %s#", colour[TXT_INSN]);
634
635 if (asCmp())
636 PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]);
637
638 if (sType != dType)
639 PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]);
640
641 for (s = 0; srcExists(s); ++s) {
642 if (s == predSrc || src(s).usedAsPtr)
643 continue;
644 const size_t pre = pos;
645 SPACE();
646 pos += src(s).mod.print(&buf[pos], BUFSZ - pos);
647 if (pos > pre + 1)
648 SPACE();
649 if (src(s).isIndirect(0) || src(s).isIndirect(1))
650 pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos,
651 getIndirect(s, 0),
652 getIndirect(s, 1));
653 else
654 pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType);
655 }
656 if (exit)
657 PRINT("%s exit", colour[TXT_INSN]);
658
659 PRINT("%s", colour[TXT_DEFAULT]);
660
661 buf[MIN2(pos, BUFSZ - 1)] = 0;
662
663 INFO("%s (%u)\n", buf, encSize);
664 }
665
666 class PrintPass : public Pass
667 {
668 public:
669 PrintPass() : serial(0) { }
670
671 virtual bool visit(Function *);
672 virtual bool visit(BasicBlock *);
673 virtual bool visit(Instruction *);
674
675 private:
676 int serial;
677 };
678
679 bool
680 PrintPass::visit(Function *fn)
681 {
682 char str[16];
683
684 INFO("\n%s:%i (", fn->getName(), fn->getLabel());
685
686 if (!fn->outs.empty())
687 INFO("out");
688 for (std::deque<ValueRef>::iterator it = fn->outs.begin();
689 it != fn->outs.end();
690 ++it) {
691 it->get()->print(str, sizeof(str), typeOfSize(it->get()->reg.size));
692 INFO(" %s", str);
693 }
694
695 if (!fn->ins.empty())
696 INFO("%s%sin", colour[TXT_DEFAULT], fn->outs.empty() ? "" : ", ");
697 for (std::deque<ValueDef>::iterator it = fn->ins.begin();
698 it != fn->ins.end();
699 ++it) {
700 it->get()->print(str, sizeof(str), typeOfSize(it->get()->reg.size));
701 INFO(" %s", str);
702 }
703 INFO("%s)\n", colour[TXT_DEFAULT]);
704
705 return true;
706 }
707
708 bool
709 PrintPass::visit(BasicBlock *bb)
710 {
711 #if 0
712 INFO("---\n");
713 for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next())
714 INFO(" <- BB:%i (%s)\n",
715 BasicBlock::get(ei.getNode())->getId(),
716 ei.getEdge()->typeStr());
717 #endif
718 INFO("BB:%i (%u instructions) - ", bb->getId(), bb->getInsnCount());
719
720 if (bb->idom())
721 INFO("idom = BB:%i, ", bb->idom()->getId());
722
723 INFO("df = { ");
724 for (DLList::Iterator df = bb->getDF().iterator(); !df.end(); df.next())
725 INFO("BB:%i ", BasicBlock::get(df)->getId());
726
727 INFO("}\n");
728
729 for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next())
730 INFO(" -> BB:%i (%s)\n",
731 BasicBlock::get(ei.getNode())->getId(),
732 ei.getEdge()->typeStr());
733
734 return true;
735 }
736
737 bool
738 PrintPass::visit(Instruction *insn)
739 {
740 INFO("%3i: ", serial++);
741 insn->print();
742 return true;
743 }
744
745 void
746 Function::print()
747 {
748 PrintPass pass;
749 pass.run(this, true, false);
750 }
751
752 void
753 Program::print()
754 {
755 PrintPass pass;
756 init_colours();
757 pass.run(this, true, false);
758 }
759
760 void
761 Function::printLiveIntervals() const
762 {
763 INFO("printing live intervals ...\n");
764
765 for (ArrayList::Iterator it = allLValues.iterator(); !it.end(); it.next()) {
766 const Value *lval = Value::get(it)->asLValue();
767 if (lval && !lval->livei.isEmpty()) {
768 INFO("livei(%%%i): ", lval->id);
769 lval->livei.print();
770 }
771 }
772 }
773
774 } // namespace nv50_ir