nouveau: fix regression since float comparison instructions (v2)
[mesa.git] / src / gallium / drivers / nouveau / codegen / nv50_ir_build_util.h
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(uint32_t);
94 ImmediateValue *mkImm(uint64_t);
95
96 ImmediateValue *mkImm(int i) { return mkImm((uint32_t)i); }
97
98 Value *loadImm(Value *dst, float);
99 Value *loadImm(Value *dst, uint32_t);
100 Value *loadImm(Value *dst, uint64_t);
101
102 Value *loadImm(Value *dst, int i) { return loadImm(dst, (uint32_t)i); }
103
104 // returns high part of the operation
105 static Instruction *split64BitOpPostRA(Function *, Instruction *,
106 Value *zero, Value *carry);
107
108 struct Location
109 {
110 Location(unsigned array, unsigned arrayIdx, unsigned i, unsigned c)
111 : array(array), arrayIdx(arrayIdx), i(i), c(c) { }
112 Location(const Location &l)
113 : array(l.array), arrayIdx(l.arrayIdx), i(l.i), c(l.c) { }
114
115 bool operator==(const Location &l) const
116 {
117 return
118 array == l.array && arrayIdx == l.arrayIdx && i == l.i && c == l.c;
119 }
120
121 bool operator<(const Location &l) const
122 {
123 return array != l.array ? array < l.array :
124 arrayIdx != l.arrayIdx ? arrayIdx < l.arrayIdx :
125 i != l.i ? i < l.i :
126 c != l.c ? c < l.c :
127 false;
128 }
129
130 unsigned array, arrayIdx, i, c;
131 };
132
133 typedef bimap<Location, Value *> ValueMap;
134
135 class DataArray
136 {
137 public:
138 DataArray(BuildUtil *bld) : up(bld) { }
139
140 void setup(unsigned array, unsigned arrayIdx,
141 uint32_t base, int len, int vecDim, int eltSize,
142 DataFile file, int8_t fileIdx);
143
144 inline bool exists(ValueMap&, unsigned int i, unsigned int c);
145
146 Value *load(ValueMap&, int i, int c, Value *ptr);
147 void store(ValueMap&, int i, int c, Value *ptr, Value *value);
148 Value *acquire(ValueMap&, int i, int c);
149
150 private:
151 inline Value *lookup(ValueMap&, unsigned i, unsigned c);
152 inline Value *insert(ValueMap&, unsigned i, unsigned c, Value *v);
153
154 Symbol *mkSymbol(int i, int c);
155
156 private:
157 BuildUtil *up;
158 unsigned array, arrayIdx;
159
160 uint32_t baseAddr;
161 uint32_t arrayLen;
162 Symbol *baseSym;
163
164 uint8_t vecDim;
165 uint8_t eltSize; // in bytes
166
167 DataFile file;
168 bool regOnly;
169 };
170
171 Symbol *mkSymbol(DataFile file, int8_t fileIndex,
172 DataType ty, uint32_t baseAddress);
173
174 Symbol *mkSysVal(SVSemantic svName, uint32_t svIndex);
175
176 private:
177 void init(Program *);
178 void addImmediate(ImmediateValue *);
179 inline unsigned int u32Hash(uint32_t);
180
181 protected:
182 Program *prog;
183 Function *func;
184 Instruction *pos;
185 BasicBlock *bb;
186 bool tail;
187
188 #define NV50_IR_BUILD_IMM_HT_SIZE 256
189
190 ImmediateValue *imms[NV50_IR_BUILD_IMM_HT_SIZE];
191 unsigned int immCount;
192 };
193
194 unsigned int BuildUtil::u32Hash(uint32_t u)
195 {
196 return (u % 273) % NV50_IR_BUILD_IMM_HT_SIZE;
197 }
198
199 void BuildUtil::setProgram(Program *program)
200 {
201 prog = program;
202 }
203
204 void
205 BuildUtil::setPosition(BasicBlock *block, bool atTail)
206 {
207 bb = block;
208 prog = bb->getProgram();
209 func = bb->getFunction();
210 pos = NULL;
211 tail = atTail;
212 }
213
214 void
215 BuildUtil::setPosition(Instruction *i, bool after)
216 {
217 bb = i->bb;
218 prog = bb->getProgram();
219 func = bb->getFunction();
220 pos = i;
221 tail = after;
222 assert(bb);
223 }
224
225 LValue *
226 BuildUtil::getScratch(int size, DataFile f)
227 {
228 LValue *lval = new_LValue(func, f);
229 lval->reg.size = size;
230 return lval;
231 }
232
233 LValue *
234 BuildUtil::getSSA(int size, DataFile f)
235 {
236 LValue *lval = new_LValue(func, f);
237 lval->ssa = 1;
238 lval->reg.size = size;
239 return lval;
240 }
241
242 void BuildUtil::insert(Instruction *i)
243 {
244 if (!pos) {
245 tail ? bb->insertTail(i) : bb->insertHead(i);
246 } else {
247 if (tail) {
248 bb->insertAfter(pos, i);
249 pos = i;
250 } else {
251 bb->insertBefore(pos, i);
252 }
253 }
254 }
255
256 Instruction *
257 BuildUtil::mkOp(operation op, DataType ty, Value *dst)
258 {
259 Instruction *insn = new_Instruction(func, op, ty);
260 insn->setDef(0, dst);
261 insert(insn);
262 if (op == OP_DISCARD || op == OP_EXIT ||
263 op == OP_JOIN ||
264 op == OP_QUADON || op == OP_QUADPOP ||
265 op == OP_EMIT || op == OP_RESTART)
266 insn->fixed = 1;
267 return insn;
268 }
269
270 inline LValue *
271 BuildUtil::mkOp1v(operation op, DataType ty, Value *dst, Value *src)
272 {
273 mkOp1(op, ty, dst, src);
274 return dst->asLValue();
275 }
276
277 inline LValue *
278 BuildUtil::mkOp2v(operation op, DataType ty, Value *dst,
279 Value *src0, Value *src1)
280 {
281 mkOp2(op, ty, dst, src0, src1);
282 return dst->asLValue();
283 }
284
285 inline LValue *
286 BuildUtil::mkOp3v(operation op, DataType ty, Value *dst,
287 Value *src0, Value *src1, Value *src2)
288 {
289 mkOp3(op, ty, dst, src0, src1, src2);
290 return dst->asLValue();
291 }
292
293 inline LValue *
294 BuildUtil::mkLoadv(DataType ty, Symbol *mem, Value *ptr)
295 {
296 LValue *dst = getScratch();
297 mkLoad(ty, dst, mem, ptr);
298 return dst;
299 }
300
301 bool
302 BuildUtil::DataArray::exists(ValueMap &m, unsigned int i, unsigned int c)
303 {
304 assert(i < arrayLen && c < vecDim);
305 return !regOnly || m.r.count(Location(array, arrayIdx, i, c));
306 }
307
308 Value *
309 BuildUtil::DataArray::lookup(ValueMap &m, unsigned i, unsigned c)
310 {
311 ValueMap::r_iterator it = m.r.find(Location(array, arrayIdx, i, c));
312 return it != m.r.end() ? it->second : NULL;
313 }
314
315 Value *
316 BuildUtil::DataArray::insert(ValueMap &m, unsigned i, unsigned c, Value *v)
317 {
318 m.insert(Location(array, arrayIdx, i, c), v);
319 return v;
320 }
321
322 } // namespace nv50_ir
323
324 #endif // __NV50_IR_BUILD_UTIL_H__