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