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