339 lines
9.6 KiB
C++
339 lines
9.6 KiB
C++
/*
|
|
* Copyright 2011 Christoph Bumiller
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef __NV50_IR_BUILD_UTIL__
|
|
#define __NV50_IR_BUILD_UTIL__
|
|
|
|
namespace nv50_ir {
|
|
|
|
class BuildUtil
|
|
{
|
|
public:
|
|
BuildUtil();
|
|
BuildUtil(Program *);
|
|
|
|
inline void setProgram(Program *);
|
|
inline Program *getProgram() const { return prog; }
|
|
inline Function *getFunction() const { return func; }
|
|
|
|
// keeps inserting at head/tail of block
|
|
inline void setPosition(BasicBlock *, bool tail);
|
|
// position advances only if @after is true
|
|
inline void setPosition(Instruction *, bool after);
|
|
|
|
inline BasicBlock *getBB() { return bb; }
|
|
|
|
inline void insert(Instruction *);
|
|
inline void remove(Instruction *i) { assert(i->bb == bb); bb->remove(i); }
|
|
|
|
inline LValue *getScratch(int size = 4, DataFile = FILE_GPR);
|
|
// scratch value for a single assignment:
|
|
inline LValue *getSSA(int size = 4, DataFile = FILE_GPR);
|
|
|
|
inline Instruction *mkOp(operation, DataType, Value *);
|
|
Instruction *mkOp1(operation, DataType, Value *, Value *);
|
|
Instruction *mkOp2(operation, DataType, Value *, Value *, Value *);
|
|
Instruction *mkOp3(operation, DataType, Value *, Value *, Value *, Value *);
|
|
|
|
LValue *mkOp1v(operation, DataType, Value *, Value *);
|
|
LValue *mkOp2v(operation, DataType, Value *, Value *, Value *);
|
|
LValue *mkOp3v(operation, DataType, Value *, Value *, Value *, Value *);
|
|
|
|
Instruction *mkLoad(DataType, Value *dst, Symbol *, Value *ptr);
|
|
Instruction *mkStore(operation, DataType, Symbol *, Value *ptr, Value *val);
|
|
|
|
LValue *mkLoadv(DataType, Symbol *, Value *ptr);
|
|
|
|
Instruction *mkMov(Value *, Value *, DataType = TYPE_U32);
|
|
Instruction *mkMovToReg(int id, Value *);
|
|
Instruction *mkMovFromReg(Value *, int id);
|
|
inline Instruction *mkBMov(Value *, Value *);
|
|
|
|
Instruction *mkInterp(unsigned mode, Value *, int32_t offset, Value *rel);
|
|
Instruction *mkFetch(Value *, DataType, DataFile, int32_t offset,
|
|
Value *attrRel, Value *primRel);
|
|
|
|
Instruction *mkCvt(operation, DataType, Value *, DataType, Value *);
|
|
CmpInstruction *mkCmp(operation, CondCode, DataType,
|
|
Value *,
|
|
DataType, Value *, Value *, Value * = NULL);
|
|
TexInstruction *mkTex(operation, TexTarget,
|
|
uint16_t tic, uint16_t tsc,
|
|
const std::vector<Value *> &def,
|
|
const std::vector<Value *> &src);
|
|
Instruction *mkQuadop(uint8_t qop, Value *, uint8_t l, Value *, Value *);
|
|
|
|
FlowInstruction *mkFlow(operation, void *target, CondCode, Value *pred);
|
|
|
|
Instruction *mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc);
|
|
|
|
Instruction *mkSplit(Value *half[2], uint8_t halfSize, Value *);
|
|
|
|
void mkClobber(DataFile file, uint32_t regMask, int regUnitLog2);
|
|
|
|
ImmediateValue *mkImm(float);
|
|
ImmediateValue *mkImm(double);
|
|
ImmediateValue *mkImm(uint16_t);
|
|
ImmediateValue *mkImm(uint32_t);
|
|
ImmediateValue *mkImm(uint64_t);
|
|
|
|
ImmediateValue *mkImm(int i) { return mkImm((uint32_t)i); }
|
|
|
|
Value *loadImm(Value *dst, float);
|
|
Value *loadImm(Value *dst, double);
|
|
Value *loadImm(Value *dst, uint16_t);
|
|
Value *loadImm(Value *dst, uint32_t);
|
|
Value *loadImm(Value *dst, uint64_t);
|
|
|
|
Value *loadImm(Value *dst, int i) { return loadImm(dst, (uint32_t)i); }
|
|
|
|
// returns high part of the operation
|
|
static Instruction *split64BitOpPostRA(Function *, Instruction *,
|
|
Value *zero, Value *carry);
|
|
|
|
struct Location
|
|
{
|
|
Location(unsigned array, unsigned arrayIdx, unsigned i, unsigned c)
|
|
: array(array), arrayIdx(arrayIdx), i(i), c(c) { }
|
|
Location(const Location &l)
|
|
: array(l.array), arrayIdx(l.arrayIdx), i(l.i), c(l.c) { }
|
|
|
|
bool operator==(const Location &l) const
|
|
{
|
|
return
|
|
array == l.array && arrayIdx == l.arrayIdx && i == l.i && c == l.c;
|
|
}
|
|
|
|
bool operator<(const Location &l) const
|
|
{
|
|
return array != l.array ? array < l.array :
|
|
arrayIdx != l.arrayIdx ? arrayIdx < l.arrayIdx :
|
|
i != l.i ? i < l.i :
|
|
c != l.c ? c < l.c :
|
|
false;
|
|
}
|
|
|
|
unsigned array, arrayIdx, i, c;
|
|
};
|
|
|
|
typedef bimap<Location, Value *> ValueMap;
|
|
|
|
class DataArray
|
|
{
|
|
public:
|
|
DataArray(BuildUtil *bld) : up(bld), array(0), arrayIdx(0), baseAddr(0),
|
|
arrayLen(0), baseSym(NULL), vecDim(0), eltSize(0), file(FILE_NULL),
|
|
regOnly(false) { }
|
|
|
|
void setup(unsigned array, unsigned arrayIdx,
|
|
uint32_t base, int len, int vecDim, int eltSize,
|
|
DataFile file, int8_t fileIdx);
|
|
|
|
inline bool exists(ValueMap&, unsigned int i, unsigned int c);
|
|
|
|
Value *load(ValueMap&, int i, int c, Value *ptr);
|
|
void store(ValueMap&, int i, int c, Value *ptr, Value *value);
|
|
Value *acquire(ValueMap&, int i, int c);
|
|
|
|
private:
|
|
inline Value *lookup(ValueMap&, unsigned i, unsigned c);
|
|
inline Value *insert(ValueMap&, unsigned i, unsigned c, Value *v);
|
|
|
|
Symbol *mkSymbol(int i, int c);
|
|
|
|
private:
|
|
BuildUtil *up;
|
|
unsigned array, arrayIdx;
|
|
|
|
uint32_t baseAddr;
|
|
uint32_t arrayLen;
|
|
Symbol *baseSym;
|
|
|
|
uint8_t vecDim;
|
|
uint8_t eltSize; // in bytes
|
|
|
|
DataFile file;
|
|
bool regOnly;
|
|
};
|
|
|
|
Symbol *mkSymbol(DataFile file, int8_t fileIndex,
|
|
DataType ty, uint32_t baseAddress);
|
|
|
|
Symbol *mkSysVal(SVSemantic svName, uint32_t svIndex);
|
|
Symbol *mkTSVal(TSSemantic tsName);
|
|
|
|
private:
|
|
void init(Program *);
|
|
void addImmediate(ImmediateValue *);
|
|
inline unsigned int u32Hash(uint32_t);
|
|
|
|
protected:
|
|
Program *prog;
|
|
Function *func;
|
|
Instruction *pos;
|
|
BasicBlock *bb;
|
|
bool tail;
|
|
|
|
#define NV50_IR_BUILD_IMM_HT_SIZE 256
|
|
|
|
ImmediateValue *imms[NV50_IR_BUILD_IMM_HT_SIZE];
|
|
unsigned int immCount;
|
|
};
|
|
|
|
unsigned int BuildUtil::u32Hash(uint32_t u)
|
|
{
|
|
return (u % 273) % NV50_IR_BUILD_IMM_HT_SIZE;
|
|
}
|
|
|
|
void BuildUtil::setProgram(Program *program)
|
|
{
|
|
prog = program;
|
|
}
|
|
|
|
void
|
|
BuildUtil::setPosition(BasicBlock *block, bool atTail)
|
|
{
|
|
bb = block;
|
|
prog = bb->getProgram();
|
|
func = bb->getFunction();
|
|
pos = NULL;
|
|
tail = atTail;
|
|
}
|
|
|
|
void
|
|
BuildUtil::setPosition(Instruction *i, bool after)
|
|
{
|
|
bb = i->bb;
|
|
prog = bb->getProgram();
|
|
func = bb->getFunction();
|
|
pos = i;
|
|
tail = after;
|
|
assert(bb);
|
|
}
|
|
|
|
LValue *
|
|
BuildUtil::getScratch(int size, DataFile f)
|
|
{
|
|
LValue *lval = new_LValue(func, f);
|
|
lval->reg.size = size;
|
|
return lval;
|
|
}
|
|
|
|
LValue *
|
|
BuildUtil::getSSA(int size, DataFile f)
|
|
{
|
|
LValue *lval = new_LValue(func, f);
|
|
lval->ssa = 1;
|
|
lval->reg.size = size;
|
|
return lval;
|
|
}
|
|
|
|
void BuildUtil::insert(Instruction *i)
|
|
{
|
|
if (!pos) {
|
|
tail ? bb->insertTail(i) : bb->insertHead(i);
|
|
} else {
|
|
if (tail) {
|
|
bb->insertAfter(pos, i);
|
|
pos = i;
|
|
} else {
|
|
bb->insertBefore(pos, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
Instruction *
|
|
BuildUtil::mkOp(operation op, DataType ty, Value *dst)
|
|
{
|
|
Instruction *insn = new_Instruction(func, op, ty);
|
|
insn->setDef(0, dst);
|
|
insert(insn);
|
|
if (op == OP_DISCARD || op == OP_EXIT ||
|
|
op == OP_JOIN ||
|
|
op == OP_QUADON || op == OP_QUADPOP ||
|
|
op == OP_EMIT || op == OP_RESTART)
|
|
insn->fixed = 1;
|
|
return insn;
|
|
}
|
|
|
|
inline LValue *
|
|
BuildUtil::mkOp1v(operation op, DataType ty, Value *dst, Value *src)
|
|
{
|
|
mkOp1(op, ty, dst, src);
|
|
return dst->asLValue();
|
|
}
|
|
|
|
inline LValue *
|
|
BuildUtil::mkOp2v(operation op, DataType ty, Value *dst,
|
|
Value *src0, Value *src1)
|
|
{
|
|
mkOp2(op, ty, dst, src0, src1);
|
|
return dst->asLValue();
|
|
}
|
|
|
|
inline LValue *
|
|
BuildUtil::mkOp3v(operation op, DataType ty, Value *dst,
|
|
Value *src0, Value *src1, Value *src2)
|
|
{
|
|
mkOp3(op, ty, dst, src0, src1, src2);
|
|
return dst->asLValue();
|
|
}
|
|
|
|
inline LValue *
|
|
BuildUtil::mkLoadv(DataType ty, Symbol *mem, Value *ptr)
|
|
{
|
|
LValue *dst = getScratch(typeSizeof(ty));
|
|
mkLoad(ty, dst, mem, ptr);
|
|
return dst;
|
|
}
|
|
|
|
inline Instruction *
|
|
BuildUtil::mkBMov(Value *dst, Value *src)
|
|
{
|
|
return mkCvt(OP_CVT, TYPE_U32, dst, TYPE_U32, src);
|
|
}
|
|
|
|
bool
|
|
BuildUtil::DataArray::exists(ValueMap &m, unsigned int i, unsigned int c)
|
|
{
|
|
assert(i < arrayLen && c < vecDim);
|
|
return !regOnly || m.r.count(Location(array, arrayIdx, i, c));
|
|
}
|
|
|
|
Value *
|
|
BuildUtil::DataArray::lookup(ValueMap &m, unsigned i, unsigned c)
|
|
{
|
|
ValueMap::r_iterator it = m.r.find(Location(array, arrayIdx, i, c));
|
|
return it != m.r.end() ? it->second : NULL;
|
|
}
|
|
|
|
Value *
|
|
BuildUtil::DataArray::insert(ValueMap &m, unsigned i, unsigned c, Value *v)
|
|
{
|
|
m.insert(Location(array, arrayIdx, i, c), v);
|
|
return v;
|
|
}
|
|
|
|
} // namespace nv50_ir
|
|
|
|
#endif // __NV50_IR_BUILD_UTIL_H__
|