Path: blob/21.2-virgl/src/gallium/drivers/nouveau/codegen/nv50_ir_build_util.cpp
4574 views
/*1* Copyright 2011 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "codegen/nv50_ir.h"23#include "codegen/nv50_ir_build_util.h"2425namespace nv50_ir {2627BuildUtil::BuildUtil()28{29init(NULL);30}3132BuildUtil::BuildUtil(Program *prog)33{34init(prog);35}3637void38BuildUtil::init(Program *prog)39{40this->prog = prog;4142func = NULL;43bb = NULL;44pos = NULL;4546tail = false;4748memset(imms, 0, sizeof(imms));49immCount = 0;50}5152void53BuildUtil::addImmediate(ImmediateValue *imm)54{55if (immCount > (NV50_IR_BUILD_IMM_HT_SIZE * 3) / 4)56return;5758unsigned int pos = u32Hash(imm->reg.data.u32);5960while (imms[pos])61pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;62imms[pos] = imm;63immCount++;64}6566Instruction *67BuildUtil::mkOp1(operation op, DataType ty, Value *dst, Value *src)68{69Instruction *insn = new_Instruction(func, op, ty);7071insn->setDef(0, dst);72insn->setSrc(0, src);7374insert(insn);75return insn;76}7778Instruction *79BuildUtil::mkOp2(operation op, DataType ty, Value *dst,80Value *src0, Value *src1)81{82Instruction *insn = new_Instruction(func, op, ty);8384insn->setDef(0, dst);85insn->setSrc(0, src0);86insn->setSrc(1, src1);8788insert(insn);89return insn;90}9192Instruction *93BuildUtil::mkOp3(operation op, DataType ty, Value *dst,94Value *src0, Value *src1, Value *src2)95{96Instruction *insn = new_Instruction(func, op, ty);9798insn->setDef(0, dst);99insn->setSrc(0, src0);100insn->setSrc(1, src1);101insn->setSrc(2, src2);102103insert(insn);104return insn;105}106107Instruction *108BuildUtil::mkLoad(DataType ty, Value *dst, Symbol *mem, Value *ptr)109{110Instruction *insn = new_Instruction(func, OP_LOAD, ty);111112insn->setDef(0, dst);113insn->setSrc(0, mem);114if (ptr)115insn->setIndirect(0, 0, ptr);116117insert(insn);118return insn;119}120121Instruction *122BuildUtil::mkStore(operation op, DataType ty, Symbol *mem, Value *ptr,123Value *stVal)124{125Instruction *insn = new_Instruction(func, op, ty);126127insn->setSrc(0, mem);128insn->setSrc(1, stVal);129if (ptr)130insn->setIndirect(0, 0, ptr);131132insert(insn);133return insn;134}135136Instruction *137BuildUtil::mkFetch(Value *dst, DataType ty, DataFile file, int32_t offset,138Value *attrRel, Value *primRel)139{140Symbol *sym = mkSymbol(file, 0, ty, offset);141142Instruction *insn = mkOp1(OP_VFETCH, ty, dst, sym);143144insn->setIndirect(0, 0, attrRel);145insn->setIndirect(0, 1, primRel);146147// already inserted148return insn;149}150151Instruction *152BuildUtil::mkInterp(unsigned mode, Value *dst, int32_t offset, Value *rel)153{154operation op = OP_LINTERP;155DataType ty = TYPE_F32;156157if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_FLAT)158ty = TYPE_U32;159else160if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_PERSPECTIVE)161op = OP_PINTERP;162163Symbol *sym = mkSymbol(FILE_SHADER_INPUT, 0, ty, offset);164165Instruction *insn = mkOp1(op, ty, dst, sym);166insn->setIndirect(0, 0, rel);167insn->setInterpolate(mode);168return insn;169}170171Instruction *172BuildUtil::mkMov(Value *dst, Value *src, DataType ty)173{174Instruction *insn = new_Instruction(func, OP_MOV, ty);175176insn->setDef(0, dst);177insn->setSrc(0, src);178179insert(insn);180return insn;181}182183Instruction *184BuildUtil::mkMovToReg(int id, Value *src)185{186Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(src->reg.size));187188insn->setDef(0, new_LValue(func, FILE_GPR));189insn->getDef(0)->reg.data.id = id;190insn->setSrc(0, src);191192insert(insn);193return insn;194}195196Instruction *197BuildUtil::mkMovFromReg(Value *dst, int id)198{199Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(dst->reg.size));200201insn->setDef(0, dst);202insn->setSrc(0, new_LValue(func, FILE_GPR));203insn->getSrc(0)->reg.data.id = id;204205insert(insn);206return insn;207}208209Instruction *210BuildUtil::mkCvt(operation op,211DataType dstTy, Value *dst, DataType srcTy, Value *src)212{213Instruction *insn = new_Instruction(func, op, dstTy);214215insn->setType(dstTy, srcTy);216insn->setDef(0, dst);217insn->setSrc(0, src);218219insert(insn);220return insn;221}222223CmpInstruction *224BuildUtil::mkCmp(operation op, CondCode cc, DataType dstTy, Value *dst,225DataType srcTy, Value *src0, Value *src1, Value *src2)226{227CmpInstruction *insn = new_CmpInstruction(func, op);228229insn->setType((dst->reg.file == FILE_PREDICATE ||230dst->reg.file == FILE_FLAGS) ? TYPE_U8 : dstTy, srcTy);231insn->setCondition(cc);232insn->setDef(0, dst);233insn->setSrc(0, src0);234insn->setSrc(1, src1);235if (src2)236insn->setSrc(2, src2);237238if (dst->reg.file == FILE_FLAGS)239insn->flagsDef = 0;240241insert(insn);242return insn;243}244245TexInstruction *246BuildUtil::mkTex(operation op, TexTarget targ,247uint16_t tic, uint16_t tsc,248const std::vector<Value *> &def,249const std::vector<Value *> &src)250{251TexInstruction *tex = new_TexInstruction(func, op);252253for (size_t d = 0; d < def.size() && def[d]; ++d)254tex->setDef(d, def[d]);255for (size_t s = 0; s < src.size() && src[s]; ++s)256tex->setSrc(s, src[s]);257258tex->setTexture(targ, tic, tsc);259260insert(tex);261return tex;262}263264Instruction *265BuildUtil::mkQuadop(uint8_t q, Value *def, uint8_t l, Value *src0, Value *src1)266{267Instruction *quadop = mkOp2(OP_QUADOP, TYPE_F32, def, src0, src1);268quadop->subOp = q;269quadop->lanes = l;270return quadop;271}272273Instruction *274BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc)275{276LValue *def0 = getSSA();277LValue *def1 = getSSA();278279mkMov(def0, trSrc)->setPredicate(CC_P, pred);280mkMov(def1, flSrc)->setPredicate(CC_NOT_P, pred);281282return mkOp2(OP_UNION, typeOfSize(dst->reg.size), dst, def0, def1);283}284285Instruction *286BuildUtil::mkSplit(Value *h[2], uint8_t halfSize, Value *val)287{288Instruction *insn = NULL;289290const DataType fTy = typeOfSize(halfSize * 2);291292if (val->reg.file == FILE_IMMEDIATE)293val = mkMov(getSSA(halfSize * 2), val, fTy)->getDef(0);294295if (isMemoryFile(val->reg.file)) {296h[0] = cloneShallow(getFunction(), val);297h[1] = cloneShallow(getFunction(), val);298h[0]->reg.size = halfSize;299h[1]->reg.size = halfSize;300h[1]->reg.data.offset += halfSize;301} else {302h[0] = getSSA(halfSize, val->reg.file);303h[1] = getSSA(halfSize, val->reg.file);304insn = mkOp1(OP_SPLIT, fTy, h[0], val);305insn->setDef(1, h[1]);306}307return insn;308}309310FlowInstruction *311BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred)312{313FlowInstruction *insn = new_FlowInstruction(func, op, targ);314315if (pred)316insn->setPredicate(cc, pred);317318insert(insn);319return insn;320}321322void323BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit)324{325static const uint16_t baseSize2[16] =326{3270x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,3280x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,329};330331int base = 0;332333for (; rMask; rMask >>= 4, base += 4) {334const uint32_t mask = rMask & 0xf;335if (!mask)336continue;337int base1 = (baseSize2[mask] >> 0) & 0xf;338int size1 = (baseSize2[mask] >> 4) & 0xf;339int base2 = (baseSize2[mask] >> 8) & 0xf;340int size2 = (baseSize2[mask] >> 12) & 0xf;341Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL);342if (1) { // size1 can't be 0343LValue *reg = new_LValue(func, f);344reg->reg.size = size1 << unit;345reg->reg.data.id = base + base1;346insn->setDef(0, reg);347}348if (size2) {349LValue *reg = new_LValue(func, f);350reg->reg.size = size2 << unit;351reg->reg.data.id = base + base2;352insn->setDef(1, reg);353}354}355}356357ImmediateValue *358BuildUtil::mkImm(uint16_t u)359{360ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);361362imm->reg.size = 2;363imm->reg.type = TYPE_U16;364imm->reg.data.u32 = u;365366return imm;367}368369ImmediateValue *370BuildUtil::mkImm(uint32_t u)371{372unsigned int pos = u32Hash(u);373374while (imms[pos] && imms[pos]->reg.data.u32 != u)375pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;376377ImmediateValue *imm = imms[pos];378if (!imm) {379imm = new_ImmediateValue(prog, u);380addImmediate(imm);381}382return imm;383}384385ImmediateValue *386BuildUtil::mkImm(uint64_t u)387{388ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);389390imm->reg.size = 8;391imm->reg.type = TYPE_U64;392imm->reg.data.u64 = u;393394return imm;395}396397ImmediateValue *398BuildUtil::mkImm(float f)399{400union {401float f32;402uint32_t u32;403} u;404u.f32 = f;405return mkImm(u.u32);406}407408ImmediateValue *409BuildUtil::mkImm(double d)410{411return new_ImmediateValue(prog, d);412}413414Value *415BuildUtil::loadImm(Value *dst, float f)416{417return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f));418}419420Value *421BuildUtil::loadImm(Value *dst, double d)422{423return mkOp1v(OP_MOV, TYPE_F64, dst ? dst : getScratch(8), mkImm(d));424}425426Value *427BuildUtil::loadImm(Value *dst, uint16_t u)428{429return mkOp1v(OP_MOV, TYPE_U16, dst ? dst : getScratch(2), mkImm(u));430}431432Value *433BuildUtil::loadImm(Value *dst, uint32_t u)434{435return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u));436}437438Value *439BuildUtil::loadImm(Value *dst, uint64_t u)440{441return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u));442}443444Symbol *445BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty,446uint32_t baseAddr)447{448Symbol *sym = new_Symbol(prog, file, fileIndex);449450sym->setOffset(baseAddr);451sym->reg.type = ty;452sym->reg.size = typeSizeof(ty);453454return sym;455}456457Symbol *458BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex)459{460Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0);461462assert(svIndex < 4 || svName == SV_CLIP_DISTANCE);463464switch (svName) {465case SV_POSITION:466case SV_FACE:467case SV_YDIR:468case SV_POINT_SIZE:469case SV_POINT_COORD:470case SV_CLIP_DISTANCE:471case SV_TESS_OUTER:472case SV_TESS_INNER:473case SV_TESS_COORD:474sym->reg.type = TYPE_F32;475break;476default:477sym->reg.type = TYPE_U32;478break;479}480sym->reg.size = typeSizeof(sym->reg.type);481482sym->reg.data.sv.sv = svName;483sym->reg.data.sv.index = svIndex;484485return sym;486}487488Symbol *489BuildUtil::mkTSVal(TSSemantic tsName)490{491Symbol *sym = new_Symbol(prog, FILE_THREAD_STATE, 0);492sym->reg.type = TYPE_U32;493sym->reg.size = typeSizeof(sym->reg.type);494sym->reg.data.ts = tsName;495return sym;496}497498void499BuildUtil::DataArray::setup(unsigned array, unsigned arrayIdx,500uint32_t base, int len, int vecDim, int eltSize,501DataFile file, int8_t fileIdx)502{503this->array = array;504this->arrayIdx = arrayIdx;505this->baseAddr = base;506this->arrayLen = len;507this->vecDim = vecDim;508this->eltSize = eltSize;509this->file = file;510this->regOnly = !isMemoryFile(file);511512if (!regOnly) {513baseSym = new_Symbol(up->getProgram(), file, fileIdx);514baseSym->setOffset(baseAddr);515baseSym->reg.size = eltSize;516} else {517baseSym = NULL;518}519}520521Value *522BuildUtil::DataArray::acquire(ValueMap &m, int i, int c)523{524if (regOnly) {525Value *v = lookup(m, i, c);526if (!v)527v = insert(m, i, c, new_LValue(up->getFunction(), file));528529return v;530} else {531return up->getScratch(eltSize);532}533}534535Value *536BuildUtil::DataArray::load(ValueMap &m, int i, int c, Value *ptr)537{538if (regOnly) {539Value *v = lookup(m, i, c);540if (!v)541v = insert(m, i, c, new_LValue(up->getFunction(), file));542543return v;544} else {545Value *sym = lookup(m, i, c);546if (!sym)547sym = insert(m, i, c, mkSymbol(i, c));548549return up->mkLoadv(typeOfSize(eltSize), static_cast<Symbol *>(sym), ptr);550}551}552553void554BuildUtil::DataArray::store(ValueMap &m, int i, int c, Value *ptr, Value *value)555{556if (regOnly) {557assert(!ptr);558if (!lookup(m, i, c))559insert(m, i, c, value);560561assert(lookup(m, i, c) == value);562} else {563Value *sym = lookup(m, i, c);564if (!sym)565sym = insert(m, i, c, mkSymbol(i, c));566567const DataType stTy = typeOfSize(value->reg.size);568569up->mkStore(OP_STORE, stTy, static_cast<Symbol *>(sym), ptr, value);570}571}572573Symbol *574BuildUtil::DataArray::mkSymbol(int i, int c)575{576const unsigned int idx = i * vecDim + c;577Symbol *sym = new_Symbol(up->getProgram(), file, 0);578579assert(baseSym || (idx < arrayLen && c < vecDim));580581sym->reg.size = eltSize;582sym->reg.type = typeOfSize(eltSize);583sym->setAddress(baseSym, baseAddr + idx * eltSize);584return sym;585}586587588Instruction *589BuildUtil::split64BitOpPostRA(Function *fn, Instruction *i,590Value *zero,591Value *carry)592{593DataType hTy;594int srcNr;595596switch (i->dType) {597case TYPE_U64: hTy = TYPE_U32; break;598case TYPE_S64: hTy = TYPE_S32; break;599case TYPE_F64:600if (i->op == OP_MOV) {601hTy = TYPE_U32;602break;603}604FALLTHROUGH;605default:606return NULL;607}608609switch (i->op) {610case OP_MOV: srcNr = 1; break;611case OP_ADD:612case OP_SUB:613if (!carry)614return NULL;615srcNr = 2;616break;617case OP_SELP: srcNr = 3; break;618default:619// TODO when needed620return NULL;621}622623i->setType(hTy);624i->setDef(0, cloneShallow(fn, i->getDef(0)));625i->getDef(0)->reg.size = 4;626Instruction *lo = i;627Instruction *hi = cloneForward(fn, i);628lo->bb->insertAfter(lo, hi);629630hi->getDef(0)->reg.data.id++;631632for (int s = 0; s < srcNr; ++s) {633if (lo->getSrc(s)->reg.size < 8) {634if (s == 2)635hi->setSrc(s, lo->getSrc(s));636else637hi->setSrc(s, zero);638} else {639if (lo->getSrc(s)->refCount() > 1)640lo->setSrc(s, cloneShallow(fn, lo->getSrc(s)));641lo->getSrc(s)->reg.size /= 2;642hi->setSrc(s, cloneShallow(fn, lo->getSrc(s)));643644switch (hi->src(s).getFile()) {645case FILE_IMMEDIATE:646hi->getSrc(s)->reg.data.u64 >>= 32;647break;648case FILE_MEMORY_CONST:649case FILE_MEMORY_SHARED:650case FILE_SHADER_INPUT:651case FILE_SHADER_OUTPUT:652hi->getSrc(s)->reg.data.offset += 4;653break;654default:655assert(hi->src(s).getFile() == FILE_GPR);656hi->getSrc(s)->reg.data.id++;657break;658}659}660}661if (srcNr == 2) {662lo->setFlagsDef(1, carry);663hi->setFlagsSrc(hi->srcCount(), carry);664}665return hi;666}667668} // namespace nv50_ir669670671