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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #ifndef __NV50_IR_BUILD_UTIL__ 24 #define __NV50_IR_BUILD_UTIL__ 25 26 namespace nv50_ir { 27 28 class BuildUtil 29 { 30 public: 31 BuildUtil(); 32 BuildUtil(Program *); 33 34 inline void setProgram(Program *); 35 inline Program *getProgram() const { return prog; } 36 inline Function *getFunction() const { return func; } 37 38 // keeps inserting at head/tail of block 39 inline void setPosition(BasicBlock *, bool tail); 40 // position advances only if @after is true 41 inline void setPosition(Instruction *, bool after); 42 43 inline BasicBlock *getBB() { return bb; } 44 45 inline void insert(Instruction *); 46 inline void remove(Instruction *i) { assert(i->bb == bb); bb->remove(i); } 47 48 inline LValue *getScratch(int size = 4, DataFile = FILE_GPR); 49 // scratch value for a single assignment: 50 inline LValue *getSSA(int size = 4, DataFile = FILE_GPR); 51 52 inline Instruction *mkOp(operation, DataType, Value *); 53 Instruction *mkOp1(operation, DataType, Value *, Value *); 54 Instruction *mkOp2(operation, DataType, Value *, Value *, Value *); 55 Instruction *mkOp3(operation, DataType, Value *, Value *, Value *, Value *); 56 57 LValue *mkOp1v(operation, DataType, Value *, Value *); 58 LValue *mkOp2v(operation, DataType, Value *, Value *, Value *); 59 LValue *mkOp3v(operation, DataType, Value *, Value *, Value *, Value *); 60 61 Instruction *mkLoad(DataType, Value *dst, Symbol *, Value *ptr); 62 Instruction *mkStore(operation, DataType, Symbol *, Value *ptr, Value *val); 63 64 LValue *mkLoadv(DataType, Symbol *, Value *ptr); 65 66 Instruction *mkMov(Value *, Value *, DataType = TYPE_U32); 67 Instruction *mkMovToReg(int id, Value *); 68 Instruction *mkMovFromReg(Value *, int id); 69 70 Instruction *mkInterp(unsigned mode, Value *, int32_t offset, Value *rel); 71 Instruction *mkFetch(Value *, DataType, DataFile, int32_t offset, 72 Value *attrRel, Value *primRel); 73 74 Instruction *mkCvt(operation, DataType, Value *, DataType, Value *); 75 CmpInstruction *mkCmp(operation, CondCode, DataType, 76 Value *, 77 DataType, Value *, Value *, Value * = NULL); 78 TexInstruction *mkTex(operation, TexTarget, 79 uint16_t tic, uint16_t tsc, 80 const std::vector<Value *> &def, 81 const std::vector<Value *> &src); 82 Instruction *mkQuadop(uint8_t qop, Value *, uint8_t l, Value *, Value *); 83 84 FlowInstruction *mkFlow(operation, void *target, CondCode, Value *pred); 85 86 Instruction *mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc); 87 88 Instruction *mkSplit(Value *half[2], uint8_t halfSize, Value *); 89 90 void mkClobber(DataFile file, uint32_t regMask, int regUnitLog2); 91 92 ImmediateValue *mkImm(float); 93 ImmediateValue *mkImm(double); 94 ImmediateValue *mkImm(uint32_t); 95 ImmediateValue *mkImm(uint64_t); 96 97 ImmediateValue *mkImm(int i) { return mkImm((uint32_t)i); } 98 99 Value *loadImm(Value *dst, float); 100 Value *loadImm(Value *dst, double); 101 Value *loadImm(Value *dst, uint32_t); 102 Value *loadImm(Value *dst, uint64_t); 103 104 Value *loadImm(Value *dst, int i) { return loadImm(dst, (uint32_t)i); } 105 106 // returns high part of the operation 107 static Instruction *split64BitOpPostRA(Function *, Instruction *, 108 Value *zero, Value *carry); 109 110 struct Location 111 { 112 Location(unsigned array, unsigned arrayIdx, unsigned i, unsigned c) 113 : array(array), arrayIdx(arrayIdx), i(i), c(c) { } 114 Location(const Location &l) 115 : array(l.array), arrayIdx(l.arrayIdx), i(l.i), c(l.c) { } 116 117 bool operator==(const Location &l) const 118 { 119 return 120 array == l.array && arrayIdx == l.arrayIdx && i == l.i && c == l.c; 121 } 122 123 bool operator<(const Location &l) const 124 { 125 return array != l.array ? array < l.array : 126 arrayIdx != l.arrayIdx ? arrayIdx < l.arrayIdx : 127 i != l.i ? i < l.i : 128 c != l.c ? c < l.c : 129 false; 130 } 131 132 unsigned array, arrayIdx, i, c; 133 }; 134 135 typedef bimap<Location, Value *> ValueMap; 136 137 class DataArray 138 { 139 public: 140 DataArray(BuildUtil *bld) : up(bld) { } 141 142 void setup(unsigned array, unsigned arrayIdx, 143 uint32_t base, int len, int vecDim, int eltSize, 144 DataFile file, int8_t fileIdx); 145 146 inline bool exists(ValueMap&, unsigned int i, unsigned int c); 147 148 Value *load(ValueMap&, int i, int c, Value *ptr); 149 void store(ValueMap&, int i, int c, Value *ptr, Value *value); 150 Value *acquire(ValueMap&, int i, int c); 151 152 private: 153 inline Value *lookup(ValueMap&, unsigned i, unsigned c); 154 inline Value *insert(ValueMap&, unsigned i, unsigned c, Value *v); 155 156 Symbol *mkSymbol(int i, int c); 157 158 private: 159 BuildUtil *up; 160 unsigned array, arrayIdx; 161 162 uint32_t baseAddr; 163 uint32_t arrayLen; 164 Symbol *baseSym; 165 166 uint8_t vecDim; 167 uint8_t eltSize; // in bytes 168 169 DataFile file; 170 bool regOnly; 171 }; 172 173 Symbol *mkSymbol(DataFile file, int8_t fileIndex, 174 DataType ty, uint32_t baseAddress); 175 176 Symbol *mkSysVal(SVSemantic svName, uint32_t svIndex); 177 178 private: 179 void init(Program *); 180 void addImmediate(ImmediateValue *); 181 inline unsigned int u32Hash(uint32_t); 182 183 protected: 184 Program *prog; 185 Function *func; 186 Instruction *pos; 187 BasicBlock *bb; 188 bool tail; 189 190 #define NV50_IR_BUILD_IMM_HT_SIZE 256 191 192 ImmediateValue *imms[NV50_IR_BUILD_IMM_HT_SIZE]; 193 unsigned int immCount; 194 }; 195 196 unsigned int BuildUtil::u32Hash(uint32_t u) 197 { 198 return (u % 273) % NV50_IR_BUILD_IMM_HT_SIZE; 199 } 200 201 void BuildUtil::setProgram(Program *program) 202 { 203 prog = program; 204 } 205 206 void 207 BuildUtil::setPosition(BasicBlock *block, bool atTail) 208 { 209 bb = block; 210 prog = bb->getProgram(); 211 func = bb->getFunction(); 212 pos = NULL; 213 tail = atTail; 214 } 215 216 void 217 BuildUtil::setPosition(Instruction *i, bool after) 218 { 219 bb = i->bb; 220 prog = bb->getProgram(); 221 func = bb->getFunction(); 222 pos = i; 223 tail = after; 224 assert(bb); 225 } 226 227 LValue * 228 BuildUtil::getScratch(int size, DataFile f) 229 { 230 LValue *lval = new_LValue(func, f); 231 lval->reg.size = size; 232 return lval; 233 } 234 235 LValue * 236 BuildUtil::getSSA(int size, DataFile f) 237 { 238 LValue *lval = new_LValue(func, f); 239 lval->ssa = 1; 240 lval->reg.size = size; 241 return lval; 242 } 243 244 void BuildUtil::insert(Instruction *i) 245 { 246 if (!pos) { 247 tail ? bb->insertTail(i) : bb->insertHead(i); 248 } else { 249 if (tail) { 250 bb->insertAfter(pos, i); 251 pos = i; 252 } else { 253 bb->insertBefore(pos, i); 254 } 255 } 256 } 257 258 Instruction * 259 BuildUtil::mkOp(operation op, DataType ty, Value *dst) 260 { 261 Instruction *insn = new_Instruction(func, op, ty); 262 insn->setDef(0, dst); 263 insert(insn); 264 if (op == OP_DISCARD || op == OP_EXIT || 265 op == OP_JOIN || 266 op == OP_QUADON || op == OP_QUADPOP || 267 op == OP_EMIT || op == OP_RESTART) 268 insn->fixed = 1; 269 return insn; 270 } 271 272 inline LValue * 273 BuildUtil::mkOp1v(operation op, DataType ty, Value *dst, Value *src) 274 { 275 mkOp1(op, ty, dst, src); 276 return dst->asLValue(); 277 } 278 279 inline LValue * 280 BuildUtil::mkOp2v(operation op, DataType ty, Value *dst, 281 Value *src0, Value *src1) 282 { 283 mkOp2(op, ty, dst, src0, src1); 284 return dst->asLValue(); 285 } 286 287 inline LValue * 288 BuildUtil::mkOp3v(operation op, DataType ty, Value *dst, 289 Value *src0, Value *src1, Value *src2) 290 { 291 mkOp3(op, ty, dst, src0, src1, src2); 292 return dst->asLValue(); 293 } 294 295 inline LValue * 296 BuildUtil::mkLoadv(DataType ty, Symbol *mem, Value *ptr) 297 { 298 LValue *dst = getScratch(typeSizeof(ty)); 299 mkLoad(ty, dst, mem, ptr); 300 return dst; 301 } 302 303 bool 304 BuildUtil::DataArray::exists(ValueMap &m, unsigned int i, unsigned int c) 305 { 306 assert(i < arrayLen && c < vecDim); 307 return !regOnly || m.r.count(Location(array, arrayIdx, i, c)); 308 } 309 310 Value * 311 BuildUtil::DataArray::lookup(ValueMap &m, unsigned i, unsigned c) 312 { 313 ValueMap::r_iterator it = m.r.find(Location(array, arrayIdx, i, c)); 314 return it != m.r.end() ? it->second : NULL; 315 } 316 317 Value * 318 BuildUtil::DataArray::insert(ValueMap &m, unsigned i, unsigned c, Value *v) 319 { 320 m.insert(Location(array, arrayIdx, i, c), v); 321 return v; 322 } 323 324 } // namespace nv50_ir 325 326 #endif // __NV50_IR_BUILD_UTIL_H__ 327