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