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