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