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