nv50/ir: fix off-by-ones in CSE and nvc0 insnCanLoad
[mesa.git] / src / gallium / drivers / nv50 / codegen / nv50_ir_build_util.cpp
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 #include "nv50_ir.h"
24 #include "nv50_ir_build_util.h"
25
26 namespace nv50_ir {
27
28 BuildUtil::BuildUtil()
29 {
30 init(NULL);
31 }
32
33 BuildUtil::BuildUtil(Program *prog)
34 {
35 init(prog);
36 }
37
38 void
39 BuildUtil::init(Program *prog)
40 {
41 this->prog = prog;
42
43 func = NULL;
44 bb = NULL;
45 pos = NULL;
46
47 memset(imms, 0, sizeof(imms));
48 immCount = 0;
49 }
50
51 void
52 BuildUtil::addImmediate(ImmediateValue *imm)
53 {
54 if (immCount > (NV50_IR_BUILD_IMM_HT_SIZE * 3) / 4)
55 return;
56
57 unsigned int pos = u32Hash(imm->reg.data.u32);
58
59 while (imms[pos])
60 pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
61 imms[pos] = imm;
62 immCount++;
63 }
64
65 Instruction *
66 BuildUtil::mkOp1(operation op, DataType ty, Value *dst, Value *src)
67 {
68 Instruction *insn = new_Instruction(func, op, ty);
69
70 insn->setDef(0, dst);
71 insn->setSrc(0, src);
72
73 insert(insn);
74 return insn;
75 }
76
77 Instruction *
78 BuildUtil::mkOp2(operation op, DataType ty, Value *dst,
79 Value *src0, Value *src1)
80 {
81 Instruction *insn = new_Instruction(func, op, ty);
82
83 insn->setDef(0, dst);
84 insn->setSrc(0, src0);
85 insn->setSrc(1, src1);
86
87 insert(insn);
88 return insn;
89 }
90
91 Instruction *
92 BuildUtil::mkOp3(operation op, DataType ty, Value *dst,
93 Value *src0, Value *src1, Value *src2)
94 {
95 Instruction *insn = new_Instruction(func, op, ty);
96
97 insn->setDef(0, dst);
98 insn->setSrc(0, src0);
99 insn->setSrc(1, src1);
100 insn->setSrc(2, src2);
101
102 insert(insn);
103 return insn;
104 }
105
106 LValue *
107 BuildUtil::mkLoad(DataType ty, Symbol *mem, Value *ptr)
108 {
109 Instruction *insn = new_Instruction(func, OP_LOAD, ty);
110 LValue *def = getScratch();
111
112 insn->setDef(0, def);
113 insn->setSrc(0, mem);
114 if (ptr)
115 insn->setIndirect(0, 0, ptr);
116
117 insert(insn);
118 return def;
119 }
120
121 Instruction *
122 BuildUtil::mkStore(operation op, DataType ty, Symbol *mem, Value *ptr,
123 Value *stVal)
124 {
125 Instruction *insn = new_Instruction(func, op, ty);
126
127 insn->setSrc(0, mem);
128 insn->setSrc(1, stVal);
129 if (ptr)
130 insn->setIndirect(0, 0, ptr);
131
132 insert(insn);
133 return insn;
134 }
135
136 Instruction *
137 BuildUtil::mkFetch(Value *dst, DataType ty, DataFile file, int32_t offset,
138 Value *attrRel, Value *primRel)
139 {
140 Symbol *sym = mkSymbol(file, 0, ty, offset);
141
142 Instruction *insn = mkOp1(OP_VFETCH, ty, dst, sym);
143
144 insn->setIndirect(0, 0, attrRel);
145 insn->setIndirect(0, 1, primRel);
146
147 // already inserted
148 return insn;
149 }
150
151 Instruction *
152 BuildUtil::mkInterp(unsigned mode, Value *dst, int32_t offset, Value *rel)
153 {
154 operation op = OP_LINTERP;
155 DataType ty = TYPE_F32;
156
157 if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_FLAT)
158 ty = TYPE_U32;
159 else
160 if ((mode & NV50_IR_INTERP_MODE_MASK) == NV50_IR_INTERP_PERSPECTIVE)
161 op = OP_PINTERP;
162
163 Symbol *sym = mkSymbol(FILE_SHADER_INPUT, 0, ty, offset);
164
165 Instruction *insn = mkOp1(op, ty, dst, sym);
166 insn->setIndirect(0, 0, rel);
167 return insn;
168 }
169
170 Instruction *
171 BuildUtil::mkMov(Value *dst, Value *src, DataType ty)
172 {
173 Instruction *insn = new_Instruction(func, OP_MOV, ty);
174
175 insn->setDef(0, dst);
176 insn->setSrc(0, src);
177
178 insert(insn);
179 return insn;
180 }
181
182 Instruction *
183 BuildUtil::mkMovToReg(int id, Value *src)
184 {
185 Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(src->reg.size));
186
187 insn->setDef(0, new_LValue(func, FILE_GPR));
188 insn->getDef(0)->reg.data.id = id;
189 insn->setSrc(0, src);
190
191 insert(insn);
192 return insn;
193 }
194
195 Instruction *
196 BuildUtil::mkMovFromReg(Value *dst, int id)
197 {
198 Instruction *insn = new_Instruction(func, OP_MOV, typeOfSize(dst->reg.size));
199
200 insn->setDef(0, dst);
201 insn->setSrc(0, new_LValue(func, FILE_GPR));
202 insn->getSrc(0)->reg.data.id = id;
203
204 insert(insn);
205 return insn;
206 }
207
208 Instruction *
209 BuildUtil::mkCvt(operation op,
210 DataType dstTy, Value *dst, DataType srcTy, Value *src)
211 {
212 Instruction *insn = new_Instruction(func, op, dstTy);
213
214 insn->setType(dstTy, srcTy);
215 insn->setDef(0, dst);
216 insn->setSrc(0, src);
217
218 insert(insn);
219 return insn;
220 }
221
222 CmpInstruction *
223 BuildUtil::mkCmp(operation op, CondCode cc, DataType ty, Value *dst,
224 Value *src0, Value *src1, Value *src2)
225 {
226 CmpInstruction *insn = new_CmpInstruction(func, op);
227
228 insn->setType((dst->reg.file == FILE_PREDICATE ||
229 dst->reg.file == FILE_FLAGS) ? TYPE_U8 : ty, ty);
230 insn->setCondition(cc);
231 insn->setDef(0, dst);
232 insn->setSrc(0, src0);
233 insn->setSrc(1, src1);
234 if (src2)
235 insn->setSrc(2, src2);
236
237 if (dst->reg.file == FILE_FLAGS)
238 insn->flagsDef = 0;
239
240 insert(insn);
241 return insn;
242 }
243
244 Instruction *
245 BuildUtil::mkTex(operation op, TexTarget targ, uint8_t tic, uint8_t tsc,
246 Value **def, Value **src)
247 {
248 TexInstruction *tex = new_TexInstruction(func, op);
249
250 for (int d = 0; d < 4 && def[d]; ++d)
251 tex->setDef(d, def[d]);
252 for (int s = 0; s < 4 && src[s]; ++s)
253 tex->setSrc(s, src[s]);
254
255 tex->setTexture(targ, tic, tsc);
256
257 return tex;
258 }
259
260 Instruction *
261 BuildUtil::mkQuadop(uint8_t q, Value *def, uint8_t l, Value *src0, Value *src1)
262 {
263 Instruction *quadop = mkOp2(OP_QUADOP, TYPE_F32, def, src0, src1);
264 quadop->subOp = q;
265 quadop->lanes = l;
266 return quadop;
267 }
268
269 Instruction *
270 BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc)
271 {
272 LValue *def0 = getSSA();
273 LValue *def1 = getSSA();
274
275 mkMov(def0, trSrc)->setPredicate(CC_P, pred);
276 mkMov(def1, flSrc)->setPredicate(CC_NOT_P, pred);
277
278 return mkOp2(OP_UNION, typeOfSize(dst->reg.size), dst, def0, def1);
279 }
280
281 FlowInstruction *
282 BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred)
283 {
284 FlowInstruction *insn = new_FlowInstruction(func, op, targ);
285
286 if (pred)
287 insn->setPredicate(cc, pred);
288
289 insert(insn);
290 return insn;
291 }
292
293 void
294 BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit)
295 {
296 static const uint16_t baseSize2[16] =
297 {
298 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
299 0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
300 };
301
302 int base = 0;
303
304 for (; rMask; rMask >>= 4, base += 4) {
305 const uint32_t mask = rMask & 0xf;
306 if (!mask)
307 continue;
308 int base1 = (baseSize2[mask] >> 0) & 0xf;
309 int size1 = (baseSize2[mask] >> 4) & 0xf;
310 int base2 = (baseSize2[mask] >> 8) & 0xf;
311 int size2 = (baseSize2[mask] >> 12) & 0xf;
312 Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL);
313 if (1) { // size1 can't be 0
314 LValue *reg = new_LValue(func, f);
315 reg->reg.size = size1 << unit;
316 reg->reg.data.id = base + base1;
317 insn->setDef(0, reg);
318 }
319 if (size2) {
320 LValue *reg = new_LValue(func, f);
321 reg->reg.size = size2 << unit;
322 reg->reg.data.id = base + base2;
323 insn->setDef(1, reg);
324 }
325 }
326 }
327
328 ImmediateValue *
329 BuildUtil::mkImm(uint32_t u)
330 {
331 unsigned int pos = u32Hash(u);
332
333 while (imms[pos] && imms[pos]->reg.data.u32 != u)
334 pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
335
336 ImmediateValue *imm = imms[pos];
337 if (!imm) {
338 imm = new_ImmediateValue(prog, u);
339 addImmediate(imm);
340 }
341 return imm;
342 }
343
344 ImmediateValue *
345 BuildUtil::mkImm(uint64_t u)
346 {
347 ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);
348
349 imm->reg.size = 8;
350 imm->reg.type = TYPE_U64;
351 imm->reg.data.u64 = u;
352
353 return imm;
354 }
355
356 ImmediateValue *
357 BuildUtil::mkImm(float f)
358 {
359 union {
360 float f32;
361 uint32_t u32;
362 } u;
363 u.f32 = f;
364 return mkImm(u.u32);
365 }
366
367 Value *
368 BuildUtil::loadImm(Value *dst, float f)
369 {
370 return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f));
371 }
372
373 Value *
374 BuildUtil::loadImm(Value *dst, uint32_t u)
375 {
376 return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u));
377 }
378
379 Value *
380 BuildUtil::loadImm(Value *dst, uint64_t u)
381 {
382 return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u));
383 }
384
385 Symbol *
386 BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty,
387 uint32_t baseAddr)
388 {
389 Symbol *sym = new_Symbol(prog, file, fileIndex);
390
391 sym->setOffset(baseAddr);
392 sym->reg.type = ty;
393 sym->reg.size = typeSizeof(ty);
394
395 return sym;
396 }
397
398 Symbol *
399 BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex)
400 {
401 Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0);
402
403 assert(svIndex < 4 ||
404 (svName == SV_CLIP_DISTANCE || svName == SV_TESS_FACTOR));
405
406 switch (svName) {
407 case SV_POSITION:
408 case SV_FACE:
409 case SV_YDIR:
410 case SV_POINT_SIZE:
411 case SV_POINT_COORD:
412 case SV_CLIP_DISTANCE:
413 case SV_TESS_FACTOR:
414 sym->reg.type = TYPE_F32;
415 break;
416 default:
417 sym->reg.type = TYPE_U32;
418 break;
419 }
420 sym->reg.size = typeSizeof(sym->reg.type);
421
422 sym->reg.data.sv.sv = svName;
423 sym->reg.data.sv.index = svIndex;
424
425 return sym;
426 }
427
428 void
429 BuildUtil::DataArray::setup(unsigned array, unsigned arrayIdx,
430 uint32_t base, int len, int vecDim, int eltSize,
431 DataFile file, int8_t fileIdx)
432 {
433 this->array = array;
434 this->arrayIdx = arrayIdx;
435 this->baseAddr = base;
436 this->arrayLen = len;
437 this->vecDim = vecDim;
438 this->eltSize = eltSize;
439 this->file = file;
440 this->regOnly = !isMemoryFile(file);
441
442 if (!regOnly) {
443 baseSym = new_Symbol(up->getProgram(), file, fileIdx);
444 baseSym->setOffset(baseAddr);
445 baseSym->reg.size = eltSize;
446 } else {
447 baseSym = NULL;
448 }
449 }
450
451 Value *
452 BuildUtil::DataArray::acquire(ValueMap &m, int i, int c)
453 {
454 if (regOnly) {
455 Value *v = lookup(m, i, c);
456 if (!v)
457 v = insert(m, i, c, new_LValue(up->getFunction(), file));
458
459 return v;
460 } else {
461 return up->getScratch();
462 }
463 }
464
465 Value *
466 BuildUtil::DataArray::load(ValueMap &m, int i, int c, Value *ptr)
467 {
468 if (regOnly) {
469 Value *v = lookup(m, i, c);
470 if (!v)
471 v = insert(m, i, c, new_LValue(up->getFunction(), file));
472
473 return v;
474 } else {
475 Value *sym = lookup(m, i, c);
476 if (!sym)
477 sym = insert(m, i, c, mkSymbol(i, c));
478
479 return up->mkLoad(typeOfSize(eltSize), static_cast<Symbol *>(sym), ptr);
480 }
481 }
482
483 void
484 BuildUtil::DataArray::store(ValueMap &m, int i, int c, Value *ptr, Value *value)
485 {
486 if (regOnly) {
487 assert(!ptr);
488 if (!lookup(m, i, c))
489 insert(m, i, c, value);
490
491 assert(lookup(m, i, c) == value);
492 } else {
493 Value *sym = lookup(m, i, c);
494 if (!sym)
495 sym = insert(m, i, c, mkSymbol(i, c));
496
497 const DataType stTy = typeOfSize(value->reg.size);
498
499 up->mkStore(OP_STORE, stTy, static_cast<Symbol *>(sym), ptr, value);
500 }
501 }
502
503 Symbol *
504 BuildUtil::DataArray::mkSymbol(int i, int c)
505 {
506 const unsigned int idx = i * vecDim + c;
507 Symbol *sym = new_Symbol(up->getProgram(), file, 0);
508
509 assert(baseSym || (idx < arrayLen && c < vecDim));
510
511 sym->reg.size = eltSize;
512 sym->reg.type = typeOfSize(eltSize);
513 sym->setAddress(baseSym, baseAddr + idx * eltSize);
514 return sym;
515 }
516
517 } // namespace nv50_ir