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