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#ifndef __NV50_IR_BUILD_UTIL__
24#define __NV50_IR_BUILD_UTIL__
25
26namespace nv50_ir {
27
28class BuildUtil
29{
30public:
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   LValue *mkLoad(DataType, Symbol *, Value *ptr);
62   Instruction *mkStore(operation, DataType, Symbol *, Value *ptr, Value *val);
63
64   Instruction *mkMov(Value *, Value *, DataType = TYPE_U32);
65   Instruction *mkMovToReg(int id, Value *);
66   Instruction *mkMovFromReg(Value *, int id);
67
68   Instruction *mkInterp(unsigned mode, Value *, int32_t offset, Value *rel);
69   Instruction *mkFetch(Value *, DataType, DataFile, int32_t offset,
70                        Value *attrRel, Value *primRel);
71
72   Instruction *mkCvt(operation, DataType, Value *, DataType, Value *);
73   CmpInstruction *mkCmp(operation, CondCode, DataType,
74			 Value *,
75			 Value *, Value *, Value * = NULL);
76   Instruction *mkTex(operation, TexTarget, uint8_t tic, uint8_t tsc,
77                      Value **def, Value **src);
78   Instruction *mkQuadop(uint8_t qop, Value *, uint8_t l, Value *, Value *);
79
80   FlowInstruction *mkFlow(operation, void *target, CondCode, Value *pred);
81
82   Instruction *mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc);
83
84   Instruction *mkSplit(Value *half[2], uint8_t halfSize, Value *);
85
86   void mkClobber(DataFile file, uint32_t regMask, int regUnitLog2);
87
88   ImmediateValue *mkImm(float);
89   ImmediateValue *mkImm(uint32_t);
90   ImmediateValue *mkImm(uint64_t);
91
92   ImmediateValue *mkImm(int i) { return mkImm((uint32_t)i); }
93
94   Value *loadImm(Value *dst, float);
95   Value *loadImm(Value *dst, uint32_t);
96   Value *loadImm(Value *dst, uint64_t);
97
98   Value *loadImm(Value *dst, int i) { return loadImm(dst, (uint32_t)i); }
99
100   struct Location
101   {
102      Location(unsigned array, unsigned arrayIdx, unsigned i, unsigned c)
103         : array(array), arrayIdx(arrayIdx), i(i), c(c) { }
104      Location(const Location &l)
105         : array(l.array), arrayIdx(l.arrayIdx), i(l.i), c(l.c) { }
106
107      bool operator==(const Location &l) const
108      {
109         return
110            array == l.array && arrayIdx == l.arrayIdx && i == l.i && c == l.c;
111      }
112
113      bool operator<(const Location &l) const
114      {
115         return array != l.array ? array < l.array :
116            arrayIdx != l.arrayIdx ? arrayIdx < l.arrayIdx :
117            i != l.i ? i < l.i :
118            c != l.c ? c < l.c :
119            false;
120      }
121
122      unsigned array, arrayIdx, i, c;
123   };
124
125   typedef bimap<Location, Value *> ValueMap;
126
127   class DataArray
128   {
129   public:
130      DataArray(BuildUtil *bld) : up(bld) { }
131
132      void setup(unsigned array, unsigned arrayIdx,
133                 uint32_t base, int len, int vecDim, int eltSize,
134                 DataFile file, int8_t fileIdx);
135
136      inline bool exists(ValueMap&, unsigned int i, unsigned int c);
137
138      Value *load(ValueMap&, int i, int c, Value *ptr);
139      void store(ValueMap&, int i, int c, Value *ptr, Value *value);
140      Value *acquire(ValueMap&, int i, int c);
141
142   private:
143      inline Value *lookup(ValueMap&, unsigned i, unsigned c);
144      inline Value *insert(ValueMap&, unsigned i, unsigned c, Value *v);
145
146      Symbol *mkSymbol(int i, int c);
147
148   private:
149      BuildUtil *up;
150      unsigned array, arrayIdx;
151
152      uint32_t baseAddr;
153      uint32_t arrayLen;
154      Symbol *baseSym;
155
156      uint8_t vecDim;
157      uint8_t eltSize; // in bytes
158
159      DataFile file;
160      bool regOnly;
161   };
162
163   Symbol *mkSymbol(DataFile file, int8_t fileIndex,
164                    DataType ty, uint32_t baseAddress);
165
166   Symbol *mkSysVal(SVSemantic svName, uint32_t svIndex);
167
168private:
169   void init(Program *);
170   void addImmediate(ImmediateValue *);
171   inline unsigned int u32Hash(uint32_t);
172
173protected:
174   Program *prog;
175   Function *func;
176   Instruction *pos;
177   BasicBlock *bb;
178   bool tail;
179
180#define NV50_IR_BUILD_IMM_HT_SIZE 256
181
182   ImmediateValue *imms[NV50_IR_BUILD_IMM_HT_SIZE];
183   unsigned int immCount;
184};
185
186unsigned int BuildUtil::u32Hash(uint32_t u)
187{
188   return (u % 273) % NV50_IR_BUILD_IMM_HT_SIZE;
189}
190
191void BuildUtil::setProgram(Program *program)
192{
193   prog = program;
194}
195
196void
197BuildUtil::setPosition(BasicBlock *block, bool atTail)
198{
199   bb = block;
200   prog = bb->getProgram();
201   func = bb->getFunction();
202   pos = NULL;
203   tail = atTail;
204}
205
206void
207BuildUtil::setPosition(Instruction *i, bool after)
208{
209   bb = i->bb;
210   prog = bb->getProgram();
211   func = bb->getFunction();
212   pos = i;
213   tail = after;
214   assert(bb);
215}
216
217LValue *
218BuildUtil::getScratch(int size, DataFile f)
219{
220   LValue *lval = new_LValue(func, f);
221   lval->reg.size = size;
222   return lval;
223}
224
225LValue *
226BuildUtil::getSSA(int size, DataFile f)
227{
228   LValue *lval = new_LValue(func, f);
229   lval->ssa = 1;
230   lval->reg.size = size;
231   return lval;
232}
233
234void BuildUtil::insert(Instruction *i)
235{
236   if (!pos) {
237      tail ? bb->insertTail(i) : bb->insertHead(i);
238   } else {
239      if (tail) {
240         bb->insertAfter(pos, i);
241         pos = i;
242      } else {
243         bb->insertBefore(pos, i);
244      }
245   }
246}
247
248Instruction *
249BuildUtil::mkOp(operation op, DataType ty, Value *dst)
250{
251   Instruction *insn = new_Instruction(func, op, ty);
252   insn->setDef(0, dst);
253   insert(insn);
254   if (op == OP_DISCARD || op == OP_EXIT ||
255       op == OP_JOIN ||
256       op == OP_QUADON || op == OP_QUADPOP ||
257       op == OP_EMIT || op == OP_RESTART)
258      insn->fixed = 1;
259   return insn;
260}
261
262inline LValue *
263BuildUtil::mkOp1v(operation op, DataType ty, Value *dst, Value *src)
264{
265   mkOp1(op, ty, dst, src);
266   return dst->asLValue();
267}
268
269inline LValue *
270BuildUtil::mkOp2v(operation op, DataType ty, Value *dst,
271                  Value *src0, Value *src1)
272{
273   mkOp2(op, ty, dst, src0, src1);
274   return dst->asLValue();
275}
276
277inline LValue *
278BuildUtil::mkOp3v(operation op, DataType ty, Value *dst,
279                  Value *src0, Value *src1, Value *src2)
280{
281   mkOp3(op, ty, dst, src0, src1, src2);
282   return dst->asLValue();
283}
284
285bool
286BuildUtil::DataArray::exists(ValueMap &m, unsigned int i, unsigned int c)
287{
288   assert(i < arrayLen && c < vecDim);
289   return !regOnly || m.r.count(Location(array, arrayIdx, i, c));
290}
291
292Value *
293BuildUtil::DataArray::lookup(ValueMap &m, unsigned i, unsigned c)
294{
295   ValueMap::r_iterator it = m.r.find(Location(array, arrayIdx, i, c));
296   return it != m.r.end() ? it->second : NULL;
297}
298
299Value *
300BuildUtil::DataArray::insert(ValueMap &m, unsigned i, unsigned c, Value *v)
301{
302   m.insert(Location(array, arrayIdx, i, c), v);
303   return v;
304}
305
306} // namespace nv50_ir
307
308#endif // __NV50_IR_BUILD_UTIL_H__
309