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