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