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_build_util.h"
     25 
     26 namespace nv50_ir {
     27 
     28 BuildUtil::BuildUtil()
     29 {
     30    init(NULL);
     31 }
     32 
     33 BuildUtil::BuildUtil(Program *prog)
     34 {
     35    init(prog);
     36 }
     37 
     38 void
     39 BuildUtil::init(Program *prog)
     40 {
     41    this->prog = prog;
     42 
     43    func = NULL;
     44    bb = NULL;
     45    pos = NULL;
     46 
     47    memset(imms, 0, sizeof(imms));
     48    immCount = 0;
     49 }
     50 
     51 void
     52 BuildUtil::addImmediate(ImmediateValue *imm)
     53 {
     54    if (immCount > (NV50_IR_BUILD_IMM_HT_SIZE * 3) / 4)
     55       return;
     56 
     57    unsigned int pos = u32Hash(imm->reg.data.u32);
     58 
     59    while (imms[pos])
     60       pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
     61    imms[pos] = imm;
     62    immCount++;
     63 }
     64 
     65 Instruction *
     66 BuildUtil::mkOp1(operation op, DataType ty, Value *dst, Value *src)
     67 {
     68    Instruction *insn = new_Instruction(func, op, ty);
     69 
     70    insn->setDef(0, dst);
     71    insn->setSrc(0, src);
     72 
     73    insert(insn);
     74    return insn;
     75 }
     76 
     77 Instruction *
     78 BuildUtil::mkOp2(operation op, DataType ty, Value *dst,
     79                  Value *src0, Value *src1)
     80 {
     81    Instruction *insn = new_Instruction(func, op, ty);
     82 
     83    insn->setDef(0, dst);
     84    insn->setSrc(0, src0);
     85    insn->setSrc(1, src1);
     86 
     87    insert(insn);
     88    return insn;
     89 }
     90 
     91 Instruction *
     92 BuildUtil::mkOp3(operation op, DataType ty, Value *dst,
     93                  Value *src0, Value *src1, Value *src2)
     94 {
     95    Instruction *insn = new_Instruction(func, op, ty);
     96 
     97    insn->setDef(0, dst);
     98    insn->setSrc(0, src0);
     99    insn->setSrc(1, src1);
    100    insn->setSrc(2, src2);
    101 
    102    insert(insn);
    103    return insn;
    104 }
    105 
    106 LValue *
    107 BuildUtil::mkLoad(DataType ty, Symbol *mem, Value *ptr)
    108 {
    109    Instruction *insn = new_Instruction(func, OP_LOAD, ty);
    110    LValue *def = getScratch();
    111 
    112    insn->setDef(0, def);
    113    insn->setSrc(0, mem);
    114    if (ptr)
    115       insn->setIndirect(0, 0, ptr);
    116 
    117    insert(insn);
    118    return def;
    119 }
    120 
    121 Instruction *
    122 BuildUtil::mkStore(operation op, DataType ty, Symbol *mem, Value *ptr,
    123                    Value *stVal)
    124 {
    125    Instruction *insn = new_Instruction(func, op, ty);
    126 
    127    insn->setSrc(0, mem);
    128    insn->setSrc(1, stVal);
    129    if (ptr)
    130       insn->setIndirect(0, 0, ptr);
    131 
    132    insert(insn);
    133    return insn;
    134 }
    135 
    136 Instruction *
    137 BuildUtil::mkFetch(Value *dst, DataType ty, DataFile file, int32_t offset,
    138                    Value *attrRel, Value *primRel)
    139 {
    140    Symbol *sym = mkSymbol(file, 0, ty, offset);
    141 
    142    Instruction *insn = mkOp1(OP_VFETCH, ty, dst, sym);
    143 
    144    insn->setIndirect(0, 0, attrRel);
    145    insn->setIndirect(0, 1, primRel);
    146 
    147    // already inserted
    148    return insn;
    149 }
    150 
    151 Instruction *
    152 BuildUtil::mkInterp(unsigned mode, Value *dst, int32_t offset, Value *rel)
    153 {
    154    operation op = OP_LINTERP;
    155    DataType ty = TYPE_F32;
    156 
    157    if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_FLAT)
    158       ty = TYPE_U32;
    159    else
    160    if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_PERSPECTIVE)
    161       op = OP_PINTERP;
    162 
    163    Symbol *sym = mkSymbol(FILE_SHADER_INPUT, 0, ty, offset);
    164 
    165    Instruction *insn = mkOp1(op, ty, dst, sym);
    166    insn->setIndirect(0, 0, rel);
    167    return insn;
    168 }
    169 
    170 Instruction *
    171 BuildUtil::mkMov(Value *dst, Value *src, DataType ty)
    172 {
    173    Instruction *insn = new_Instruction(func, OP_MOV, ty);
    174 
    175    insn->setDef(0, dst);
    176    insn->setSrc(0, src);
    177 
    178    insert(insn);
    179    return insn;
    180 }
    181 
    182 Instruction *
    183 BuildUtil::mkMovToReg(int id, Value *src)
    184 {
    185    Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(src->reg.size));
    186 
    187    insn->setDef(0, new_LValue(func, FILE_GPR));
    188    insn->getDef(0)->reg.data.id = id;
    189    insn->setSrc(0, src);
    190 
    191    insert(insn);
    192    return insn;
    193 }
    194 
    195 Instruction *
    196 BuildUtil::mkMovFromReg(Value *dst, int id)
    197 {
    198    Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(dst->reg.size));
    199 
    200    insn->setDef(0, dst);
    201    insn->setSrc(0, new_LValue(func, FILE_GPR));
    202    insn->getSrc(0)->reg.data.id = id;
    203 
    204    insert(insn);
    205    return insn;
    206 }
    207 
    208 Instruction *
    209 BuildUtil::mkCvt(operation op,
    210                  DataType dstTy, Value *dst, DataType srcTy, Value *src)
    211 {
    212    Instruction *insn = new_Instruction(func, op, dstTy);
    213 
    214    insn->setType(dstTy, srcTy);
    215    insn->setDef(0, dst);
    216    insn->setSrc(0, src);
    217 
    218    insert(insn);
    219    return insn;
    220 }
    221 
    222 CmpInstruction *
    223 BuildUtil::mkCmp(operation op, CondCode cc, DataType ty, Value *dst,
    224                  Value *src0, Value *src1, Value *src2)
    225 {
    226    CmpInstruction *insn = new_CmpInstruction(func, op);
    227 
    228    insn->setType((dst->reg.file == FILE_PREDICATE ||
    229                   dst->reg.file == FILE_FLAGS) ? TYPE_U8 : ty, ty);
    230    insn->setCondition(cc);
    231    insn->setDef(0, dst);
    232    insn->setSrc(0, src0);
    233    insn->setSrc(1, src1);
    234    if (src2)
    235       insn->setSrc(2, src2);
    236 
    237    if (dst->reg.file == FILE_FLAGS)
    238       insn->flagsDef = 0;
    239 
    240    insert(insn);
    241    return insn;
    242 }
    243 
    244 Instruction *
    245 BuildUtil::mkTex(operation op, TexTarget targ, uint8_t tic, uint8_t tsc,
    246                  Value **def, Value **src)
    247 {
    248    TexInstruction *tex = new_TexInstruction(func, op);
    249 
    250    for (int d = 0; d < 4 && def[d]; ++d)
    251       tex->setDef(d, def[d]);
    252    for (int s = 0; s < 4 && src[s]; ++s)
    253       tex->setSrc(s, src[s]);
    254 
    255    tex->setTexture(targ, tic, tsc);
    256 
    257    return tex;
    258 }
    259 
    260 Instruction *
    261 BuildUtil::mkQuadop(uint8_t q, Value *def, uint8_t l, Value *src0, Value *src1)
    262 {
    263    Instruction *quadop = mkOp2(OP_QUADOP, TYPE_F32, def, src0, src1);
    264    quadop->subOp = q;
    265    quadop->lanes = l;
    266    return quadop;
    267 }
    268 
    269 Instruction *
    270 BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc)
    271 {
    272    LValue *def0 = getSSA();
    273    LValue *def1 = getSSA();
    274 
    275    mkMov(def0, trSrc)->setPredicate(CC_P, pred);
    276    mkMov(def1, flSrc)->setPredicate(CC_NOT_P, pred);
    277 
    278    return mkOp2(OP_UNION, typeOfSize(dst->reg.size), dst, def0, def1);
    279 }
    280 
    281 Instruction *
    282 BuildUtil::mkSplit(Value *h[2], uint8_t halfSize, Value *val)
    283 {
    284    Instruction *insn = NULL;
    285 
    286    const DataType fTy = typeOfSize(halfSize * 2);
    287 
    288    if (val->reg.file == FILE_IMMEDIATE)
    289       val = mkMov(getSSA(halfSize * 2), val, fTy)->getDef(0);
    290 
    291    if (isMemoryFile(val->reg.file)) {
    292       h[0] = cloneShallow(getFunction(), val);
    293       h[1] = cloneShallow(getFunction(), val);
    294       h[0]->reg.size = halfSize;
    295       h[1]->reg.size = halfSize;
    296       h[1]->reg.data.offset += halfSize;
    297    } else {
    298       h[0] = getSSA(halfSize, val->reg.file);
    299       h[1] = getSSA(halfSize, val->reg.file);
    300       insn = mkOp1(OP_SPLIT, fTy, h[0], val);
    301       insn->setDef(1, h[1]);
    302    }
    303    return insn;
    304 }
    305 
    306 FlowInstruction *
    307 BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred)
    308 {
    309    FlowInstruction *insn = new_FlowInstruction(func, op, targ);
    310 
    311    if (pred)
    312       insn->setPredicate(cc, pred);
    313 
    314    insert(insn);
    315    return insn;
    316 }
    317 
    318 void
    319 BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit)
    320 {
    321    static const uint16_t baseSize2[16] =
    322    {
    323       0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
    324       0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
    325    };
    326 
    327    int base = 0;
    328 
    329    for (; rMask; rMask >>= 4, base += 4) {
    330       const uint32_t mask = rMask & 0xf;
    331       if (!mask)
    332          continue;
    333       int base1 = (baseSize2[mask] >>  0) & 0xf;
    334       int size1 = (baseSize2[mask] >>  4) & 0xf;
    335       int base2 = (baseSize2[mask] >>  8) & 0xf;
    336       int size2 = (baseSize2[mask] >> 12) & 0xf;
    337       Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL);
    338       if (1) { // size1 can't be 0
    339          LValue *reg = new_LValue(func, f);
    340          reg->reg.size = size1 << unit;
    341          reg->reg.data.id = base + base1;
    342          insn->setDef(0, reg);
    343       }
    344       if (size2) {
    345          LValue *reg = new_LValue(func, f);
    346          reg->reg.size = size2 << unit;
    347          reg->reg.data.id = base + base2;
    348          insn->setDef(1, reg);
    349       }
    350    }
    351 }
    352 
    353 ImmediateValue *
    354 BuildUtil::mkImm(uint32_t u)
    355 {
    356    unsigned int pos = u32Hash(u);
    357 
    358    while (imms[pos] && imms[pos]->reg.data.u32 != u)
    359       pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
    360 
    361    ImmediateValue *imm = imms[pos];
    362    if (!imm) {
    363       imm = new_ImmediateValue(prog, u);
    364       addImmediate(imm);
    365    }
    366    return imm;
    367 }
    368 
    369 ImmediateValue *
    370 BuildUtil::mkImm(uint64_t u)
    371 {
    372    ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);
    373 
    374    imm->reg.size = 8;
    375    imm->reg.type = TYPE_U64;
    376    imm->reg.data.u64 = u;
    377 
    378    return imm;
    379 }
    380 
    381 ImmediateValue *
    382 BuildUtil::mkImm(float f)
    383 {
    384    union {
    385       float f32;
    386       uint32_t u32;
    387    } u;
    388    u.f32 = f;
    389    return mkImm(u.u32);
    390 }
    391 
    392 Value *
    393 BuildUtil::loadImm(Value *dst, float f)
    394 {
    395    return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f));
    396 }
    397 
    398 Value *
    399 BuildUtil::loadImm(Value *dst, uint32_t u)
    400 {
    401    return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u));
    402 }
    403 
    404 Value *
    405 BuildUtil::loadImm(Value *dst, uint64_t u)
    406 {
    407    return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u));
    408 }
    409 
    410 Symbol *
    411 BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty,
    412                     uint32_t baseAddr)
    413 {
    414    Symbol *sym = new_Symbol(prog, file, fileIndex);
    415 
    416    sym->setOffset(baseAddr);
    417    sym->reg.type = ty;
    418    sym->reg.size = typeSizeof(ty);
    419 
    420    return sym;
    421 }
    422 
    423 Symbol *
    424 BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex)
    425 {
    426    Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0);
    427 
    428    assert(svIndex < 4 ||
    429           (svName == SV_CLIP_DISTANCE || svName == SV_TESS_FACTOR));
    430 
    431    switch (svName) {
    432    case SV_POSITION:
    433    case SV_FACE:
    434    case SV_YDIR:
    435    case SV_POINT_SIZE:
    436    case SV_POINT_COORD:
    437    case SV_CLIP_DISTANCE:
    438    case SV_TESS_FACTOR:
    439       sym->reg.type = TYPE_F32;
    440       break;
    441    default:
    442       sym->reg.type = TYPE_U32;
    443       break;
    444    }
    445    sym->reg.size = typeSizeof(sym->reg.type);
    446 
    447    sym->reg.data.sv.sv = svName;
    448    sym->reg.data.sv.index = svIndex;
    449 
    450    return sym;
    451 }
    452 
    453 void
    454 BuildUtil::DataArray::setup(unsigned array, unsigned arrayIdx,
    455                             uint32_t base, int len, int vecDim, int eltSize,
    456                             DataFile file, int8_t fileIdx)
    457 {
    458    this->array = array;
    459    this->arrayIdx = arrayIdx;
    460    this->baseAddr = base;
    461    this->arrayLen = len;
    462    this->vecDim = vecDim;
    463    this->eltSize = eltSize;
    464    this->file = file;
    465    this->regOnly = !isMemoryFile(file);
    466 
    467    if (!regOnly) {
    468       baseSym = new_Symbol(up->getProgram(), file, fileIdx);
    469       baseSym->setOffset(baseAddr);
    470       baseSym->reg.size = eltSize;
    471    } else {
    472       baseSym = NULL;
    473    }
    474 }
    475 
    476 Value *
    477 BuildUtil::DataArray::acquire(ValueMap &m, int i, int c)
    478 {
    479    if (regOnly) {
    480       Value *v = lookup(m, i, c);
    481       if (!v)
    482          v = insert(m, i, c, new_LValue(up->getFunction(), file));
    483 
    484       return v;
    485    } else {
    486       return up->getScratch();
    487    }
    488 }
    489 
    490 Value *
    491 BuildUtil::DataArray::load(ValueMap &m, int i, int c, Value *ptr)
    492 {
    493    if (regOnly) {
    494       Value *v = lookup(m, i, c);
    495       if (!v)
    496          v = insert(m, i, c, new_LValue(up->getFunction(), file));
    497 
    498       return v;
    499    } else {
    500       Value *sym = lookup(m, i, c);
    501       if (!sym)
    502          sym = insert(m, i, c, mkSymbol(i, c));
    503 
    504       return up->mkLoad(typeOfSize(eltSize), static_cast<Symbol *>(sym), ptr);
    505    }
    506 }
    507 
    508 void
    509 BuildUtil::DataArray::store(ValueMap &m, int i, int c, Value *ptr, Value *value)
    510 {
    511    if (regOnly) {
    512       assert(!ptr);
    513       if (!lookup(m, i, c))
    514          insert(m, i, c, value);
    515 
    516       assert(lookup(m, i, c) == value);
    517    } else {
    518       Value *sym = lookup(m, i, c);
    519       if (!sym)
    520          sym = insert(m, i, c, mkSymbol(i, c));
    521 
    522       const DataType stTy = typeOfSize(value->reg.size);
    523 
    524       up->mkStore(OP_STORE, stTy, static_cast<Symbol *>(sym), ptr, value);
    525    }
    526 }
    527 
    528 Symbol *
    529 BuildUtil::DataArray::mkSymbol(int i, int c)
    530 {
    531    const unsigned int idx = i * vecDim + c;
    532    Symbol *sym = new_Symbol(up->getProgram(), file, 0);
    533 
    534    assert(baseSym || (idx < arrayLen && c < vecDim));
    535 
    536    sym->reg.size = eltSize;
    537    sym->reg.type = typeOfSize(eltSize);
    538    sym->setAddress(baseSym, baseAddr + idx * eltSize);
    539    return sym;
    540 }
    541 
    542 } // namespace nv50_ir
    543