| /* |
| * 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); |
| |
| 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(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, 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) { } |
| |
| 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); |
| |
| 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; |
| } |
| |
| 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__ |