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