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