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