Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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