Home | History | Annotate | Download | only in codegen
      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 namespace nv50_ir {
     27 
     28 enum TextStyle
     29 {
     30    TXT_DEFAULT,
     31    TXT_GPR,
     32    TXT_REGISTER,
     33    TXT_FLAGS,
     34    TXT_MEM,
     35    TXT_IMMD,
     36    TXT_BRA,
     37    TXT_INSN
     38 };
     39 
     40 static const char *_colour[8] =
     41 {
     42    "\x1b[00m",
     43    "\x1b[34m",
     44    "\x1b[35m",
     45    "\x1b[35m",
     46    "\x1b[36m",
     47    "\x1b[33m",
     48    "\x1b[37m",
     49    "\x1b[32m"
     50 };
     51 
     52 static const char *_nocolour[8] =
     53 {
     54       "", "", "", "", "", "", "", ""
     55 };
     56 
     57 static const char **colour;
     58 
     59 static void init_colours()
     60 {
     61    if (getenv("NV50_PROG_DEBUG_NO_COLORS") != NULL)
     62       colour = _nocolour;
     63    else
     64       colour = _colour;
     65 }
     66 
     67 static const char *OpClassStr[OPCLASS_OTHER + 1] =
     68 {
     69    "MOVE",
     70    "LOAD",
     71    "STORE",
     72    "ARITH",
     73    "SHIFT",
     74    "SFU",
     75    "LOGIC",
     76    "COMPARE",
     77    "CONVERT",
     78    "ATOMIC",
     79    "TEXTURE",
     80    "SURFACE",
     81    "FLOW",
     82    "(INVALID)",
     83    "PSEUDO",
     84    "OTHER"
     85 };
     86 
     87 const char *operationStr[OP_LAST + 1] =
     88 {
     89    "nop",
     90    "phi",
     91    "union",
     92    "split",
     93    "merge",
     94    "consec",
     95    "mov",
     96    "ld",
     97    "st",
     98    "add",
     99    "sub",
    100    "mul",
    101    "div",
    102    "mod",
    103    "mad",
    104    "fma",
    105    "sad",
    106    "abs",
    107    "neg",
    108    "not",
    109    "and",
    110    "or",
    111    "xor",
    112    "shl",
    113    "shr",
    114    "max",
    115    "min",
    116    "sat",
    117    "ceil",
    118    "floor",
    119    "trunc",
    120    "cvt",
    121    "set and",
    122    "set or",
    123    "set xor",
    124    "set",
    125    "selp",
    126    "slct",
    127    "rcp",
    128    "rsq",
    129    "lg2",
    130    "sin",
    131    "cos",
    132    "ex2",
    133    "exp",
    134    "log",
    135    "presin",
    136    "preex2",
    137    "sqrt",
    138    "pow",
    139    "bra",
    140    "call",
    141    "ret",
    142    "cont",
    143    "break",
    144    "preret",
    145    "precont",
    146    "prebreak",
    147    "brkpt",
    148    "joinat",
    149    "join",
    150    "discard",
    151    "exit",
    152    "barrier",
    153    "vfetch",
    154    "pfetch",
    155    "export",
    156    "linterp",
    157    "pinterp",
    158    "emit",
    159    "restart",
    160    "tex",
    161    "texbias",
    162    "texlod",
    163    "texfetch",
    164    "texquery",
    165    "texgrad",
    166    "texgather",
    167    "texcsaa",
    168    "suld",
    169    "sust",
    170    "dfdx",
    171    "dfdy",
    172    "rdsv",
    173    "wrsv",
    174    "pixld",
    175    "quadop",
    176    "quadon",
    177    "quadpop",
    178    "popcnt",
    179    "insbf",
    180    "extbf",
    181    "texbar",
    182    "(invalid)"
    183 };
    184 
    185 static const char *DataTypeStr[] =
    186 {
    187    "-",
    188    "u8", "s8",
    189    "u16", "s16",
    190    "u32", "s32",
    191    "u64", "s64",
    192    "f16", "f32", "f64",
    193    "b96", "b128"
    194 };
    195 
    196 static const char *RoundModeStr[] =
    197 {
    198    "", "rm", "rz", "rp", "rni", "rmi", "rzi", "rpi"
    199 };
    200 
    201 static const char *CondCodeStr[] =
    202 {
    203    "never",
    204    "lt",
    205    "eq",
    206    "le",
    207    "gt",
    208    "ne",
    209    "ge",
    210    "",
    211    "(invalid)",
    212    "ltu",
    213    "equ",
    214    "leu",
    215    "gtu",
    216    "neu",
    217    "geu",
    218    "",
    219    "no",
    220    "nc",
    221    "ns",
    222    "na",
    223    "a",
    224    "s",
    225    "c",
    226    "o"
    227 };
    228 
    229 static const char *SemanticStr[SV_LAST + 1] =
    230 {
    231    "POSITION",
    232    "VERTEX_ID",
    233    "INSTANCE_ID",
    234    "INVOCATION_ID",
    235    "PRIMITIVE_ID",
    236    "VERTEX_COUNT",
    237    "LAYER",
    238    "VIEWPORT_INDEX",
    239    "Y_DIR",
    240    "FACE",
    241    "POINT_SIZE",
    242    "POINT_COORD",
    243    "CLIP_DISTANCE",
    244    "SAMPLE_INDEX",
    245    "TESS_FACTOR",
    246    "TESS_COORD",
    247    "TID",
    248    "CTAID",
    249    "NTID",
    250    "GRIDID",
    251    "NCTAID",
    252    "LANEID",
    253    "PHYSID",
    254    "NPHYSID",
    255    "CLOCK",
    256    "LBASE",
    257    "SBASE",
    258    "?",
    259    "(INVALID)"
    260 };
    261 
    262 static const char *interpStr[16] =
    263 {
    264    "pass",
    265    "mul",
    266    "flat",
    267    "sc",
    268    "cent pass",
    269    "cent mul",
    270    "cent flat",
    271    "cent sc",
    272    "off pass",
    273    "off mul",
    274    "off flat",
    275    "off sc",
    276    "samp pass",
    277    "samp mul",
    278    "samp flat",
    279    "samp sc"
    280 };
    281 
    282 #define PRINT(args...)                                \
    283    do {                                               \
    284       pos += snprintf(&buf[pos], size - pos, args);   \
    285    } while(0)
    286 
    287 #define SPACE_PRINT(cond, args...)                      \
    288    do {                                                 \
    289       if (cond)                                         \
    290          buf[pos++] = ' ';                              \
    291       pos += snprintf(&buf[pos], size - pos, args);     \
    292    } while(0)
    293 
    294 #define SPACE()                                    \
    295    do {                                            \
    296       if (pos < size)                              \
    297          buf[pos++] = ' ';                         \
    298    } while(0)
    299 
    300 int Modifier::print(char *buf, size_t size) const
    301 {
    302    size_t pos = 0;
    303 
    304    if (bits)
    305       PRINT("%s", colour[TXT_INSN]);
    306 
    307    size_t base = pos;
    308 
    309    if (bits & NV50_IR_MOD_NOT)
    310       PRINT("not");
    311    if (bits & NV50_IR_MOD_SAT)
    312       SPACE_PRINT(pos > base && pos < size, "sat");
    313    if (bits & NV50_IR_MOD_NEG)
    314       SPACE_PRINT(pos > base && pos < size, "neg");
    315    if (bits & NV50_IR_MOD_ABS)
    316       SPACE_PRINT(pos > base && pos < size, "abs");
    317 
    318    return pos;
    319 }
    320 
    321 int LValue::print(char *buf, size_t size, DataType ty) const
    322 {
    323    const char *postFix = "";
    324    size_t pos = 0;
    325    int idx = join->reg.data.id >= 0 ? join->reg.data.id : id;
    326    char p = join->reg.data.id >= 0 ? '$' : '%';
    327    char r;
    328    int col = TXT_DEFAULT;
    329 
    330    switch (reg.file) {
    331    case FILE_GPR:
    332       r = 'r'; col = TXT_GPR;
    333       if (reg.size == 2) {
    334          if (p == '$') {
    335             postFix = (idx & 1) ? "h" : "l";
    336             idx /= 2;
    337          } else {
    338             postFix = "s";
    339          }
    340       } else
    341       if (reg.size == 8) {
    342          postFix = "d";
    343       } else
    344       if (reg.size == 16) {
    345          postFix = "q";
    346       } else
    347       if (reg.size == 12) {
    348          postFix = "t";
    349       }
    350       break;
    351    case FILE_PREDICATE:
    352       r = 'p'; col = TXT_REGISTER;
    353       if (reg.size == 2)
    354          postFix = "d";
    355       else
    356       if (reg.size == 4)
    357          postFix = "q";
    358       break;
    359    case FILE_FLAGS:
    360       r = 'c'; col = TXT_FLAGS;
    361       break;
    362    case FILE_ADDRESS:
    363       r = 'a'; col = TXT_REGISTER;
    364       break;
    365    default:
    366       assert(!"invalid file for lvalue");
    367       r = '?';
    368       break;
    369    }
    370 
    371    PRINT("%s%c%c%i%s", colour[col], p, r, idx, postFix);
    372 
    373    return pos;
    374 }
    375 
    376 int ImmediateValue::print(char *buf, size_t size, DataType ty) const
    377 {
    378    size_t pos = 0;
    379 
    380    PRINT("%s", colour[TXT_IMMD]);
    381 
    382    switch (ty) {
    383    case TYPE_F32: PRINT("%f", reg.data.f32); break;
    384    case TYPE_F64: PRINT("%f", reg.data.f64); break;
    385    case TYPE_U8:  PRINT("0x%02x", reg.data.u8); break;
    386    case TYPE_S8:  PRINT("%i", reg.data.s8); break;
    387    case TYPE_U16: PRINT("0x%04x", reg.data.u16); break;
    388    case TYPE_S16: PRINT("%i", reg.data.s16); break;
    389    case TYPE_U32: PRINT("0x%08x", reg.data.u32); break;
    390    case TYPE_S32: PRINT("%i", reg.data.s32); break;
    391    case TYPE_U64:
    392    case TYPE_S64:
    393    default:
    394       PRINT("0x%016lx", reg.data.u64);
    395       break;
    396    }
    397    return pos;
    398 }
    399 
    400 int Symbol::print(char *buf, size_t size, DataType ty) const
    401 {
    402    return print(buf, size, NULL, NULL, ty);
    403 }
    404 
    405 int Symbol::print(char *buf, size_t size,
    406                   Value *rel, Value *dimRel, DataType ty) const
    407 {
    408    size_t pos = 0;
    409    char c;
    410 
    411    if (ty == TYPE_NONE)
    412       ty = typeOfSize(reg.size);
    413 
    414    if (reg.file == FILE_SYSTEM_VALUE) {
    415       PRINT("%ssv[%s%s:%i%s", colour[TXT_MEM],
    416             colour[TXT_REGISTER],
    417             SemanticStr[reg.data.sv.sv], reg.data.sv.index, colour[TXT_MEM]);
    418       if (rel) {
    419          PRINT("%s+", colour[TXT_DEFAULT]);
    420          pos += rel->print(&buf[pos], size - pos);
    421       }
    422       PRINT("%s]", colour[TXT_MEM]);
    423       return pos;
    424    }
    425 
    426    switch (reg.file) {
    427    case FILE_MEMORY_CONST:  c = 'c'; break;
    428    case FILE_SHADER_INPUT:  c = 'a'; break;
    429    case FILE_SHADER_OUTPUT: c = 'o'; break;
    430    case FILE_MEMORY_GLOBAL: c = 'g'; break;
    431    case FILE_MEMORY_SHARED: c = 's'; break;
    432    case FILE_MEMORY_LOCAL:  c = 'l'; break;
    433    default:
    434       assert(!"invalid file");
    435       c = '?';
    436       break;
    437    }
    438 
    439    if (c == 'c')
    440       PRINT("%s%c%i[", colour[TXT_MEM], c, reg.fileIndex);
    441    else
    442       PRINT("%s%c[", colour[TXT_MEM], c);
    443 
    444    if (dimRel) {
    445       pos += dimRel->print(&buf[pos], size - pos, TYPE_S32);
    446       PRINT("%s][", colour[TXT_MEM]);
    447    }
    448 
    449    if (rel) {
    450       pos += rel->print(&buf[pos], size - pos);
    451       PRINT("%s%c", colour[TXT_DEFAULT], (reg.data.offset < 0) ? '-' : '+');
    452    } else {
    453       assert(reg.data.offset >= 0);
    454    }
    455    PRINT("%s0x%x%s]", colour[TXT_IMMD], abs(reg.data.offset), colour[TXT_MEM]);
    456 
    457    return pos;
    458 }
    459 
    460 void Instruction::print() const
    461 {
    462    #define BUFSZ 512
    463 
    464    const size_t size = BUFSZ;
    465 
    466    char buf[BUFSZ];
    467    int s, d;
    468    size_t pos = 0;
    469 
    470    PRINT("%s", colour[TXT_INSN]);
    471 
    472    if (join)
    473       PRINT("join ");
    474 
    475    if (predSrc >= 0) {
    476       const size_t pre = pos;
    477       if (getSrc(predSrc)->reg.file == FILE_PREDICATE) {
    478          if (cc == CC_NOT_P)
    479             PRINT("not");
    480       } else {
    481          PRINT("%s", CondCodeStr[cc]);
    482       }
    483       if (pos > pre)
    484          SPACE();
    485       pos += getSrc(predSrc)->print(&buf[pos], BUFSZ - pos);
    486       PRINT(" %s", colour[TXT_INSN]);
    487    }
    488 
    489    if (saturate)
    490       PRINT("sat ");
    491 
    492    if (asFlow()) {
    493       PRINT("%s", operationStr[op]);
    494       if (op == OP_CALL && asFlow()->builtin) {
    495          PRINT(" %sBUILTIN:%i", colour[TXT_BRA], asFlow()->target.builtin);
    496       } else
    497       if (op == OP_CALL && asFlow()->target.fn) {
    498          PRINT(" %s%s:%i", colour[TXT_BRA],
    499                asFlow()->target.fn->getName(),
    500                asFlow()->target.fn->getLabel());
    501       } else
    502       if (asFlow()->target.bb)
    503          PRINT(" %sBB:%i", colour[TXT_BRA], asFlow()->target.bb->getId());
    504    } else {
    505       PRINT("%s ", operationStr[op]);
    506       if (op == OP_LINTERP || op == OP_PINTERP)
    507          PRINT("%s ", interpStr[ipa]);
    508       if (subOp)
    509          PRINT("(SUBOP:%u) ", subOp);
    510       if (perPatch)
    511          PRINT("patch ");
    512       if (asTex())
    513          PRINT("%s ", asTex()->tex.target.getName());
    514       if (postFactor)
    515          PRINT("x2^%i ", postFactor);
    516       PRINT("%s%s", dnz ? "dnz " : (ftz ? "ftz " : ""),  DataTypeStr[dType]);
    517    }
    518 
    519    if (rnd != ROUND_N)
    520       PRINT(" %s", RoundModeStr[rnd]);
    521 
    522    if (defExists(1))
    523       PRINT(" {");
    524    for (d = 0; defExists(d); ++d) {
    525       SPACE();
    526       pos += getDef(d)->print(&buf[pos], size - pos);
    527    }
    528    if (d > 1)
    529       PRINT(" %s}", colour[TXT_INSN]);
    530    else
    531    if (!d && !asFlow())
    532       PRINT(" %s#", colour[TXT_INSN]);
    533 
    534    if (asCmp())
    535       PRINT(" %s%s", colour[TXT_INSN], CondCodeStr[asCmp()->setCond]);
    536 
    537    if (sType != dType)
    538       PRINT(" %s%s", colour[TXT_INSN], DataTypeStr[sType]);
    539 
    540    for (s = 0; srcExists(s); ++s) {
    541       if (s == predSrc || src(s).usedAsPtr)
    542          continue;
    543       const size_t pre = pos;
    544       SPACE();
    545       pos += src(s).mod.print(&buf[pos], BUFSZ - pos);
    546       if (pos > pre + 1)
    547          SPACE();
    548       if (src(s).isIndirect(0) || src(s).isIndirect(1))
    549          pos += getSrc(s)->asSym()->print(&buf[pos], BUFSZ - pos,
    550                                           getIndirect(s, 0),
    551                                           getIndirect(s, 1));
    552       else
    553          pos += getSrc(s)->print(&buf[pos], BUFSZ - pos, sType);
    554    }
    555    if (exit)
    556       PRINT("%s exit", colour[TXT_INSN]);
    557 
    558    PRINT("%s", colour[TXT_DEFAULT]);
    559 
    560    buf[MIN2(pos, BUFSZ - 1)] = 0;
    561 
    562    INFO("%s (%u)\n", buf, encSize);
    563 }
    564 
    565 class PrintPass : public Pass
    566 {
    567 public:
    568    PrintPass() : serial(0) { }
    569 
    570    virtual bool visit(Function *);
    571    virtual bool visit(BasicBlock *);
    572    virtual bool visit(Instruction *);
    573 
    574 private:
    575    int serial;
    576 };
    577 
    578 bool
    579 PrintPass::visit(Function *fn)
    580 {
    581    INFO("\n%s:%i\n", fn->getName(), fn->getLabel());
    582 
    583    return true;
    584 }
    585 
    586 bool
    587 PrintPass::visit(BasicBlock *bb)
    588 {
    589 #if 0
    590    INFO("---\n");
    591    for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next())
    592       INFO(" <- BB:%i (%s)\n",
    593            BasicBlock::get(ei.getNode())->getId(),
    594            ei.getEdge()->typeStr());
    595 #endif
    596    INFO("BB:%i (%u instructions) - ", bb->getId(), bb->getInsnCount());
    597 
    598    if (bb->idom())
    599       INFO("idom = BB:%i, ", bb->idom()->getId());
    600 
    601    INFO("df = { ");
    602    for (DLList::Iterator df = bb->getDF().iterator(); !df.end(); df.next())
    603       INFO("BB:%i ", BasicBlock::get(df)->getId());
    604 
    605    INFO("}\n");
    606 
    607    for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next())
    608       INFO(" -> BB:%i (%s)\n",
    609            BasicBlock::get(ei.getNode())->getId(),
    610            ei.getEdge()->typeStr());
    611 
    612    return true;
    613 }
    614 
    615 bool
    616 PrintPass::visit(Instruction *insn)
    617 {
    618    INFO("%3i: ", serial++);
    619    insn->print();
    620    return true;
    621 }
    622 
    623 void
    624 Function::print()
    625 {
    626    PrintPass pass;
    627    pass.run(this, true, false);
    628 }
    629 
    630 void
    631 Program::print()
    632 {
    633    PrintPass pass;
    634    init_colours();
    635    pass.run(this, true, false);
    636 }
    637 
    638 void
    639 Function::printLiveIntervals() const
    640 {
    641    INFO("printing live intervals ...\n");
    642 
    643    for (ArrayList::Iterator it = allLValues.iterator(); !it.end(); it.next()) {
    644       const Value *lval = Value::get(it)->asLValue();
    645       if (lval && !lval->livei.isEmpty()) {
    646          INFO("livei(%%%i): ", lval->id);
    647          lval->livei.print();
    648       }
    649    }
    650 }
    651 
    652 } // namespace nv50_ir
    653