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
26namespace nv50_ir {
27
28BuildUtil::BuildUtil()
29{
30   init(NULL);
31}
32
33BuildUtil::BuildUtil(Program *prog)
34{
35   init(prog);
36}
37
38void
39BuildUtil::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
51void
52BuildUtil::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
65Instruction *
66BuildUtil::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
77Instruction *
78BuildUtil::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
91Instruction *
92BuildUtil::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
106LValue *
107BuildUtil::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
121Instruction *
122BuildUtil::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
136Instruction *
137BuildUtil::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
151Instruction *
152BuildUtil::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
170Instruction *
171BuildUtil::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
182Instruction *
183BuildUtil::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
195Instruction *
196BuildUtil::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
208Instruction *
209BuildUtil::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
222CmpInstruction *
223BuildUtil::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
244Instruction *
245BuildUtil::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
260Instruction *
261BuildUtil::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
269Instruction *
270BuildUtil::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
281Instruction *
282BuildUtil::mkSplit(Value *h[2], uint8_t halfSize, Value *val)
283{
284   Instruction *insn = NULL;
285
286   const DataType fTy = typeOfSize(halfSize * 2);
287
288   if (val->reg.file == FILE_IMMEDIATE)
289      val = mkMov(getSSA(halfSize * 2), val, fTy)->getDef(0);
290
291   if (isMemoryFile(val->reg.file)) {
292      h[0] = cloneShallow(getFunction(), val);
293      h[1] = cloneShallow(getFunction(), val);
294      h[0]->reg.size = halfSize;
295      h[1]->reg.size = halfSize;
296      h[1]->reg.data.offset += halfSize;
297   } else {
298      h[0] = getSSA(halfSize, val->reg.file);
299      h[1] = getSSA(halfSize, val->reg.file);
300      insn = mkOp1(OP_SPLIT, fTy, h[0], val);
301      insn->setDef(1, h[1]);
302   }
303   return insn;
304}
305
306FlowInstruction *
307BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred)
308{
309   FlowInstruction *insn = new_FlowInstruction(func, op, targ);
310
311   if (pred)
312      insn->setPredicate(cc, pred);
313
314   insert(insn);
315   return insn;
316}
317
318void
319BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit)
320{
321   static const uint16_t baseSize2[16] =
322   {
323      0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
324      0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
325   };
326
327   int base = 0;
328
329   for (; rMask; rMask >>= 4, base += 4) {
330      const uint32_t mask = rMask & 0xf;
331      if (!mask)
332         continue;
333      int base1 = (baseSize2[mask] >>  0) & 0xf;
334      int size1 = (baseSize2[mask] >>  4) & 0xf;
335      int base2 = (baseSize2[mask] >>  8) & 0xf;
336      int size2 = (baseSize2[mask] >> 12) & 0xf;
337      Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL);
338      if (1) { // size1 can't be 0
339         LValue *reg = new_LValue(func, f);
340         reg->reg.size = size1 << unit;
341         reg->reg.data.id = base + base1;
342         insn->setDef(0, reg);
343      }
344      if (size2) {
345         LValue *reg = new_LValue(func, f);
346         reg->reg.size = size2 << unit;
347         reg->reg.data.id = base + base2;
348         insn->setDef(1, reg);
349      }
350   }
351}
352
353ImmediateValue *
354BuildUtil::mkImm(uint32_t u)
355{
356   unsigned int pos = u32Hash(u);
357
358   while (imms[pos] && imms[pos]->reg.data.u32 != u)
359      pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
360
361   ImmediateValue *imm = imms[pos];
362   if (!imm) {
363      imm = new_ImmediateValue(prog, u);
364      addImmediate(imm);
365   }
366   return imm;
367}
368
369ImmediateValue *
370BuildUtil::mkImm(uint64_t u)
371{
372   ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);
373
374   imm->reg.size = 8;
375   imm->reg.type = TYPE_U64;
376   imm->reg.data.u64 = u;
377
378   return imm;
379}
380
381ImmediateValue *
382BuildUtil::mkImm(float f)
383{
384   union {
385      float f32;
386      uint32_t u32;
387   } u;
388   u.f32 = f;
389   return mkImm(u.u32);
390}
391
392Value *
393BuildUtil::loadImm(Value *dst, float f)
394{
395   return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f));
396}
397
398Value *
399BuildUtil::loadImm(Value *dst, uint32_t u)
400{
401   return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u));
402}
403
404Value *
405BuildUtil::loadImm(Value *dst, uint64_t u)
406{
407   return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u));
408}
409
410Symbol *
411BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty,
412                    uint32_t baseAddr)
413{
414   Symbol *sym = new_Symbol(prog, file, fileIndex);
415
416   sym->setOffset(baseAddr);
417   sym->reg.type = ty;
418   sym->reg.size = typeSizeof(ty);
419
420   return sym;
421}
422
423Symbol *
424BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex)
425{
426   Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0);
427
428   assert(svIndex < 4 ||
429          (svName == SV_CLIP_DISTANCE || svName == SV_TESS_FACTOR));
430
431   switch (svName) {
432   case SV_POSITION:
433   case SV_FACE:
434   case SV_YDIR:
435   case SV_POINT_SIZE:
436   case SV_POINT_COORD:
437   case SV_CLIP_DISTANCE:
438   case SV_TESS_FACTOR:
439      sym->reg.type = TYPE_F32;
440      break;
441   default:
442      sym->reg.type = TYPE_U32;
443      break;
444   }
445   sym->reg.size = typeSizeof(sym->reg.type);
446
447   sym->reg.data.sv.sv = svName;
448   sym->reg.data.sv.index = svIndex;
449
450   return sym;
451}
452
453void
454BuildUtil::DataArray::setup(unsigned array, unsigned arrayIdx,
455                            uint32_t base, int len, int vecDim, int eltSize,
456                            DataFile file, int8_t fileIdx)
457{
458   this->array = array;
459   this->arrayIdx = arrayIdx;
460   this->baseAddr = base;
461   this->arrayLen = len;
462   this->vecDim = vecDim;
463   this->eltSize = eltSize;
464   this->file = file;
465   this->regOnly = !isMemoryFile(file);
466
467   if (!regOnly) {
468      baseSym = new_Symbol(up->getProgram(), file, fileIdx);
469      baseSym->setOffset(baseAddr);
470      baseSym->reg.size = eltSize;
471   } else {
472      baseSym = NULL;
473   }
474}
475
476Value *
477BuildUtil::DataArray::acquire(ValueMap &m, int i, int c)
478{
479   if (regOnly) {
480      Value *v = lookup(m, i, c);
481      if (!v)
482         v = insert(m, i, c, new_LValue(up->getFunction(), file));
483
484      return v;
485   } else {
486      return up->getScratch();
487   }
488}
489
490Value *
491BuildUtil::DataArray::load(ValueMap &m, int i, int c, Value *ptr)
492{
493   if (regOnly) {
494      Value *v = lookup(m, i, c);
495      if (!v)
496         v = insert(m, i, c, new_LValue(up->getFunction(), file));
497
498      return v;
499   } else {
500      Value *sym = lookup(m, i, c);
501      if (!sym)
502         sym = insert(m, i, c, mkSymbol(i, c));
503
504      return up->mkLoad(typeOfSize(eltSize), static_cast<Symbol *>(sym), ptr);
505   }
506}
507
508void
509BuildUtil::DataArray::store(ValueMap &m, int i, int c, Value *ptr, Value *value)
510{
511   if (regOnly) {
512      assert(!ptr);
513      if (!lookup(m, i, c))
514         insert(m, i, c, value);
515
516      assert(lookup(m, i, c) == value);
517   } else {
518      Value *sym = lookup(m, i, c);
519      if (!sym)
520         sym = insert(m, i, c, mkSymbol(i, c));
521
522      const DataType stTy = typeOfSize(value->reg.size);
523
524      up->mkStore(OP_STORE, stTy, static_cast<Symbol *>(sym), ptr, value);
525   }
526}
527
528Symbol *
529BuildUtil::DataArray::mkSymbol(int i, int c)
530{
531   const unsigned int idx = i * vecDim + c;
532   Symbol *sym = new_Symbol(up->getProgram(), file, 0);
533
534   assert(baseSym || (idx < arrayLen && c < vecDim));
535
536   sym->reg.size = eltSize;
537   sym->reg.type = typeOfSize(eltSize);
538   sym->setAddress(baseSym, baseAddr + idx * eltSize);
539   return sym;
540}
541
542} // namespace nv50_ir
543