nv50,nvc0: hold references to the framebuffer surfaces
[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 insert(insn);
225 return insn;
226 }
227
228 Instruction *
229 BuildUtil::mkTex(operation op, TexTarget targ, uint8_t tic, uint8_t tsc,
230 Value **def, Value **src)
231 {
232 TexInstruction *tex = new_TexInstruction(func, op);
233
234 for (int d = 0; d < 4 && def[d]; ++d)
235 tex->setDef(d, def[d]);
236 for (int s = 0; s < 4 && src[s]; ++s)
237 tex->setSrc(s, src[s]);
238
239 tex->setTexture(targ, tic, tsc);
240
241 return tex;
242 }
243
244 Instruction *
245 BuildUtil::mkQuadop(uint8_t q, Value *def, uint8_t l, Value *src0, Value *src1)
246 {
247 Instruction *quadop = mkOp2(OP_QUADOP, TYPE_F32, def, src0, src1);
248 quadop->subOp = q;
249 quadop->lanes = l;
250 return quadop;
251 }
252
253 Instruction *
254 BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc)
255 {
256 Instruction *insn;
257 LValue *def0 = getSSA();
258 LValue *def1 = getSSA();
259
260 mkMov(def0, trSrc)->setPredicate(CC_P, pred);
261 mkMov(def1, flSrc)->setPredicate(CC_NOT_P, pred);
262
263 insn = mkOp2(OP_UNION, typeOfSize(dst->reg.size), dst, def0, def1);
264
265 insert(insn);
266 return insn;
267 }
268
269 FlowInstruction *
270 BuildUtil::mkFlow(operation op, BasicBlock *targ, CondCode cc, Value *pred)
271 {
272 FlowInstruction *insn = new_FlowInstruction(func, op, targ);
273
274 if (pred)
275 insn->setPredicate(cc, pred);
276
277 insert(insn);
278 return insn;
279 }
280
281 void
282 BuildUtil::mkClobber(DataFile f, uint32_t rMask, int unit)
283 {
284 static const uint16_t baseSize2[16] =
285 {
286 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
287 0x0013, 0x1310, 0x1311, 0x0020, 0x1320, 0x0022, 0x2210, 0x0040,
288 };
289
290 int base = 0;
291
292 for (; rMask; rMask >>= 4, base += 4) {
293 const uint32_t mask = rMask & 0xf;
294 if (!mask)
295 continue;
296 int base1 = (baseSize2[mask] >> 0) & 0xf;
297 int size1 = (baseSize2[mask] >> 4) & 0xf;
298 int base2 = (baseSize2[mask] >> 8) & 0xf;
299 int size2 = (baseSize2[mask] >> 12) & 0xf;
300 Instruction *insn = mkOp(OP_NOP, TYPE_NONE, NULL);
301 if (1) { // size1 can't be 0
302 LValue *reg = new_LValue(func, f);
303 reg->reg.size = size1 << unit;
304 reg->reg.data.id = base + base1;
305 insn->setDef(0, reg);
306 }
307 if (size2) {
308 LValue *reg = new_LValue(func, f);
309 reg->reg.size = size2 << unit;
310 reg->reg.data.id = base + base2;
311 insn->setDef(1, reg);
312 }
313 }
314 }
315
316 ImmediateValue *
317 BuildUtil::mkImm(uint32_t u)
318 {
319 unsigned int pos = u32Hash(u);
320
321 while (imms[pos] && imms[pos]->reg.data.u32 != u)
322 pos = (pos + 1) % NV50_IR_BUILD_IMM_HT_SIZE;
323
324 ImmediateValue *imm = imms[pos];
325 if (!imm) {
326 imm = new_ImmediateValue(prog, u);
327 addImmediate(imm);
328 }
329 return imm;
330 }
331
332 ImmediateValue *
333 BuildUtil::mkImm(uint64_t u)
334 {
335 ImmediateValue *imm = new_ImmediateValue(prog, (uint32_t)0);
336
337 imm->reg.size = 8;
338 imm->reg.type = TYPE_U64;
339 imm->reg.data.u64 = u;
340
341 return imm;
342 }
343
344 ImmediateValue *
345 BuildUtil::mkImm(float f)
346 {
347 union {
348 float f32;
349 uint32_t u32;
350 } u;
351 u.f32 = f;
352 return mkImm(u.u32);
353 }
354
355 Value *
356 BuildUtil::loadImm(Value *dst, float f)
357 {
358 return mkOp1v(OP_MOV, TYPE_F32, dst ? dst : getScratch(), mkImm(f));
359 }
360
361 Value *
362 BuildUtil::loadImm(Value *dst, uint32_t u)
363 {
364 return mkOp1v(OP_MOV, TYPE_U32, dst ? dst : getScratch(), mkImm(u));
365 }
366
367 Value *
368 BuildUtil::loadImm(Value *dst, uint64_t u)
369 {
370 return mkOp1v(OP_MOV, TYPE_U64, dst ? dst : getScratch(8), mkImm(u));
371 }
372
373 Symbol *
374 BuildUtil::mkSymbol(DataFile file, int8_t fileIndex, DataType ty,
375 uint32_t baseAddr)
376 {
377 Symbol *sym = new_Symbol(prog, file, fileIndex);
378
379 sym->setOffset(baseAddr);
380 sym->reg.type = ty;
381 sym->reg.size = typeSizeof(ty);
382
383 return sym;
384 }
385
386 Symbol *
387 BuildUtil::mkSysVal(SVSemantic svName, uint32_t svIndex)
388 {
389 Symbol *sym = new_Symbol(prog, FILE_SYSTEM_VALUE, 0);
390
391 assert(svIndex < 4 ||
392 (svName == SV_CLIP_DISTANCE || svName == SV_TESS_FACTOR));
393
394 switch (svName) {
395 case SV_POSITION:
396 case SV_FACE:
397 case SV_YDIR:
398 case SV_POINT_SIZE:
399 case SV_POINT_COORD:
400 case SV_CLIP_DISTANCE:
401 case SV_TESS_FACTOR:
402 sym->reg.type = TYPE_F32;
403 break;
404 default:
405 sym->reg.type = TYPE_U32;
406 break;
407 }
408 sym->reg.size = typeSizeof(sym->reg.type);
409
410 sym->reg.data.sv.sv = svName;
411 sym->reg.data.sv.index = svIndex;
412
413 return sym;
414 }
415
416 void
417 BuildUtil::DataArray::init()
418 {
419 values = NULL;
420 baseAddr = 0;
421 arrayLen = 0;
422
423 vecDim = 4;
424 eltSize = 2;
425
426 file = FILE_GPR;
427 regOnly = true;
428 }
429
430 BuildUtil::DataArray::DataArray()
431 {
432 init();
433 }
434
435 BuildUtil::DataArray::DataArray(BuildUtil *bld) : up(bld)
436 {
437 init();
438 }
439
440 BuildUtil::DataArray::~DataArray()
441 {
442 if (values)
443 delete[] values;
444 }
445
446 void
447 BuildUtil::DataArray::setup(uint32_t base, int len, int v, int size,
448 DataFile f, int8_t fileIndex)
449 {
450 baseAddr = base;
451 arrayLen = len;
452
453 vecDim = v;
454 eltSize = size;
455
456 file = f;
457 regOnly = !isMemoryFile(f);
458
459 values = new Value * [arrayLen * vecDim];
460 if (values)
461 memset(values, 0, arrayLen * vecDim * sizeof(Value *));
462
463 if (!regOnly) {
464 baseSym = new_Symbol(up->getProgram(), file, fileIndex);
465 baseSym->setOffset(baseAddr);
466 baseSym->reg.size = size;
467 }
468 }
469
470 Value *
471 BuildUtil::DataArray::acquire(int i, int c)
472 {
473 const unsigned int idx = i * vecDim + c;
474
475 assert(idx < arrayLen * vecDim);
476
477 if (regOnly) {
478 const unsigned int idx = i * 4 + c; // vecDim always 4 if regOnly
479 if (!values[idx])
480 values[idx] = new_LValue(up->getFunction(), file);
481 return values[idx];
482 } else {
483 return up->getScratch();
484 }
485 }
486
487 Value *
488 BuildUtil::DataArray::load(int i, int c, Value *ptr)
489 {
490 const unsigned int idx = i * vecDim + c;
491
492 assert(idx < arrayLen * vecDim);
493
494 if (regOnly) {
495 if (!values[idx])
496 values[idx] = new_LValue(up->getFunction(), file);
497 return values[idx];
498 } else {
499 Symbol *sym = reinterpret_cast<Symbol *>(values[idx]);
500 if (!sym)
501 values[idx] = sym = this->mkSymbol(i, c, baseSym);
502 return up->mkLoad(typeOfSize(eltSize), sym, ptr);
503 }
504 }
505
506 void
507 BuildUtil::DataArray::store(int i, int c, Value *ptr, Value *value)
508 {
509 const unsigned int idx = i * vecDim + c;
510
511 assert(idx < arrayLen * vecDim);
512
513 if (regOnly) {
514 assert(!ptr);
515 assert(!values[idx] || values[idx] == value);
516 values[idx] = value;
517 } else {
518 Symbol *sym = reinterpret_cast<Symbol *>(values[idx]);
519 if (!sym)
520 values[idx] = sym = this->mkSymbol(i, c, baseSym);
521 up->mkStore(OP_STORE, typeOfSize(value->reg.size), sym, ptr, value);
522 }
523 }
524
525 Symbol *
526 BuildUtil::DataArray::mkSymbol(int i, int c, Symbol *base)
527 {
528 const unsigned int idx = i * vecDim + c;
529
530 Symbol *sym = new_Symbol(up->getProgram(), file, 0);
531
532 assert(base || (idx < arrayLen && c < vecDim));
533
534 sym->reg.size = eltSize;
535 sym->reg.type = typeOfSize(eltSize);
536
537 sym->setAddress(base, baseAddr + idx * eltSize);
538 return sym;
539 }
540
541 } // namespace nv50_ir