2 * Copyright 2011 Christoph Bumiller
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
24 #include "nv50_ir_build_util.h"
28 BuildUtil::BuildUtil()
35 memset(imms
, 0, sizeof(imms
));
40 BuildUtil::addImmediate(ImmediateValue
*imm
)
42 if (immCount
> (NV50_IR_BUILD_IMM_HT_SIZE
* 3) / 4)
45 unsigned int pos
= u32Hash(imm
->reg
.data
.u32
);
48 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
54 BuildUtil::mkOp1(operation op
, DataType ty
, Value
*dst
, Value
*src
)
56 Instruction
*insn
= new_Instruction(func
, op
, ty
);
66 BuildUtil::mkOp2(operation op
, DataType ty
, Value
*dst
,
67 Value
*src0
, Value
*src1
)
69 Instruction
*insn
= new_Instruction(func
, op
, ty
);
72 insn
->setSrc(0, src0
);
73 insn
->setSrc(1, src1
);
80 BuildUtil::mkOp3(operation op
, DataType ty
, Value
*dst
,
81 Value
*src0
, Value
*src1
, Value
*src2
)
83 Instruction
*insn
= new_Instruction(func
, op
, ty
);
86 insn
->setSrc(0, src0
);
87 insn
->setSrc(1, src1
);
88 insn
->setSrc(2, src2
);
95 BuildUtil::mkLoad(DataType ty
, Symbol
*mem
, Value
*ptr
)
97 Instruction
*insn
= new_Instruction(func
, OP_LOAD
, ty
);
98 LValue
*def
= getScratch();
100 insn
->setDef(0, def
);
101 insn
->setSrc(0, mem
);
103 insn
->setIndirect(0, 0, ptr
);
110 BuildUtil::mkStore(operation op
, DataType ty
, Symbol
*mem
, Value
*ptr
,
113 Instruction
*insn
= new_Instruction(func
, op
, ty
);
115 insn
->setSrc(0, mem
);
116 insn
->setSrc(1, stVal
);
118 insn
->setIndirect(0, 0, ptr
);
125 BuildUtil::mkFetch(Value
*dst
, DataType ty
, DataFile file
, int32_t offset
,
126 Value
*attrRel
, Value
*primRel
)
128 Symbol
*sym
= mkSymbol(file
, 0, ty
, offset
);
130 Instruction
*insn
= mkOp1(OP_VFETCH
, ty
, dst
, sym
);
132 insn
->setIndirect(0, 0, attrRel
);
133 insn
->setIndirect(0, 1, primRel
);
140 BuildUtil::mkInterp(unsigned mode
, Value
*dst
, int32_t offset
, Value
*rel
)
142 operation op
= OP_LINTERP
;
143 DataType ty
= TYPE_F32
;
145 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_FLAT
)
148 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_PERSPECTIVE
)
151 Symbol
*sym
= mkSymbol(FILE_SHADER_INPUT
, 0, ty
, offset
);
153 Instruction
*insn
= mkOp1(op
, ty
, dst
, sym
);
154 insn
->setIndirect(0, 0, rel
);
159 BuildUtil::mkMov(Value
*dst
, Value
*src
, DataType ty
)
161 Instruction
*insn
= new_Instruction(func
, OP_MOV
, ty
);
163 insn
->setDef(0, dst
);
164 insn
->setSrc(0, src
);
171 BuildUtil::mkMovToReg(int id
, Value
*src
)
173 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(src
->reg
.size
));
175 insn
->setDef(0, new_LValue(func
, FILE_GPR
));
176 insn
->getDef(0)->reg
.data
.id
= id
;
177 insn
->setSrc(0, src
);
184 BuildUtil::mkMovFromReg(Value
*dst
, int id
)
186 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(dst
->reg
.size
));
188 insn
->setDef(0, dst
);
189 insn
->setSrc(0, new_LValue(func
, FILE_GPR
));
190 insn
->getSrc(0)->reg
.data
.id
= id
;
197 BuildUtil::mkCvt(operation op
,
198 DataType dstTy
, Value
*dst
, DataType srcTy
, Value
*src
)
200 Instruction
*insn
= new_Instruction(func
, op
, dstTy
);
202 insn
->setType(dstTy
, srcTy
);
203 insn
->setDef(0, dst
);
204 insn
->setSrc(0, src
);
211 BuildUtil::mkCmp(operation op
, CondCode cc
, DataType ty
, Value
*dst
,
212 Value
*src0
, Value
*src1
, Value
*src2
)
214 CmpInstruction
*insn
= new_CmpInstruction(func
, op
);
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
);
222 insn
->setSrc(2, src2
);
224 if (dst
->reg
.file
== FILE_FLAGS
)
232 BuildUtil::mkTex(operation op
, TexTarget targ
, uint8_t tic
, uint8_t tsc
,
233 Value
**def
, Value
**src
)
235 TexInstruction
*tex
= new_TexInstruction(func
, op
);
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
]);
242 tex
->setTexture(targ
, tic
, tsc
);
248 BuildUtil::mkQuadop(uint8_t q
, Value
*def
, uint8_t l
, Value
*src0
, Value
*src1
)
250 Instruction
*quadop
= mkOp2(OP_QUADOP
, TYPE_F32
, def
, src0
, src1
);
257 BuildUtil::mkSelect(Value
*pred
, Value
*dst
, Value
*trSrc
, Value
*flSrc
)
260 LValue
*def0
= getSSA();
261 LValue
*def1
= getSSA();
263 mkMov(def0
, trSrc
)->setPredicate(CC_P
, pred
);
264 mkMov(def1
, flSrc
)->setPredicate(CC_NOT_P
, pred
);
266 insn
= mkOp2(OP_UNION
, typeOfSize(dst
->reg
.size
), dst
, def0
, def1
);
273 BuildUtil::mkFlow(operation op
, BasicBlock
*targ
, CondCode cc
, Value
*pred
)
275 FlowInstruction
*insn
= new_FlowInstruction(func
, op
, targ
);
278 insn
->setPredicate(cc
, pred
);
285 BuildUtil::mkClobber(DataFile f
, uint32_t rMask
, int unit
)
287 static const uint16_t baseSize2
[16] =
289 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
290 0x0013, 0x1310, 0x1311, 0x0020, 0x1320, 0x0022, 0x2210, 0x0040,
295 for (; rMask
; rMask
>>= 4, base
+= 4) {
296 const uint32_t mask
= rMask
& 0xf;
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
);
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
);
320 BuildUtil::mkImm(uint32_t u
)
322 unsigned int pos
= u32Hash(u
);
324 while (imms
[pos
] && imms
[pos
]->reg
.data
.u32
!= u
)
325 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
327 ImmediateValue
*imm
= imms
[pos
];
329 imm
= new_ImmediateValue(prog
, u
);
336 BuildUtil::mkImm(uint64_t u
)
338 ImmediateValue
*imm
= new_ImmediateValue(prog
, (uint32_t)0);
341 imm
->reg
.type
= TYPE_U64
;
342 imm
->reg
.data
.u64
= u
;
348 BuildUtil::mkImm(float f
)
359 BuildUtil::loadImm(Value
*dst
, float f
)
361 return mkOp1v(OP_MOV
, TYPE_F32
, dst
? dst
: getScratch(), mkImm(f
));
365 BuildUtil::loadImm(Value
*dst
, uint32_t u
)
367 return mkOp1v(OP_MOV
, TYPE_U32
, dst
? dst
: getScratch(), mkImm(u
));
371 BuildUtil::loadImm(Value
*dst
, uint64_t u
)
373 return mkOp1v(OP_MOV
, TYPE_U64
, dst
? dst
: getScratch(8), mkImm(u
));
377 BuildUtil::mkSymbol(DataFile file
, int8_t fileIndex
, DataType ty
,
380 Symbol
*sym
= new_Symbol(prog
, file
, fileIndex
);
382 sym
->setOffset(baseAddr
);
384 sym
->reg
.size
= typeSizeof(ty
);
390 BuildUtil::mkSysVal(SVSemantic svName
, uint32_t svIndex
)
392 Symbol
*sym
= new_Symbol(prog
, FILE_SYSTEM_VALUE
, 0);
394 assert(svIndex
< 4 ||
395 (svName
== SV_CLIP_DISTANCE
|| svName
== SV_TESS_FACTOR
));
403 case SV_CLIP_DISTANCE
:
405 sym
->reg
.type
= TYPE_F32
;
408 sym
->reg
.type
= TYPE_U32
;
411 sym
->reg
.size
= typeSizeof(sym
->reg
.type
);
413 sym
->reg
.data
.sv
.sv
= svName
;
414 sym
->reg
.data
.sv
.index
= svIndex
;
420 BuildUtil::DataArray::init()
433 BuildUtil::DataArray::DataArray()
438 BuildUtil::DataArray::DataArray(BuildUtil
*bld
) : up(bld
)
443 BuildUtil::DataArray::~DataArray()
450 BuildUtil::DataArray::setup(uint32_t base
, int len
, int v
, int size
,
451 DataFile f
, int8_t fileIndex
)
460 regOnly
= !isMemoryFile(f
);
462 values
= new Value
* [arrayLen
* vecDim
];
464 memset(values
, 0, arrayLen
* vecDim
* sizeof(Value
*));
467 baseSym
= new_Symbol(up
->getProgram(), file
, fileIndex
);
468 baseSym
->setOffset(baseAddr
);
469 baseSym
->reg
.size
= size
;
474 BuildUtil::DataArray::acquire(int i
, int c
)
476 const unsigned int idx
= i
* vecDim
+ c
;
478 assert(idx
< arrayLen
* vecDim
);
481 const unsigned int idx
= i
* 4 + c
; // vecDim always 4 if regOnly
483 values
[idx
] = new_LValue(up
->getFunction(), file
);
486 return up
->getScratch();
491 BuildUtil::DataArray::load(int i
, int c
, Value
*ptr
)
493 const unsigned int idx
= i
* vecDim
+ c
;
495 assert(idx
< arrayLen
* vecDim
);
499 values
[idx
] = new_LValue(up
->getFunction(), file
);
502 Symbol
*sym
= reinterpret_cast<Symbol
*>(values
[idx
]);
504 values
[idx
] = sym
= this->mkSymbol(i
, c
, baseSym
);
505 return up
->mkLoad(typeOfSize(eltSize
), sym
, ptr
);
510 BuildUtil::DataArray::store(int i
, int c
, Value
*ptr
, Value
*value
)
512 const unsigned int idx
= i
* vecDim
+ c
;
514 assert(idx
< arrayLen
* vecDim
);
518 assert(!values
[idx
] || values
[idx
] == value
);
521 Symbol
*sym
= reinterpret_cast<Symbol
*>(values
[idx
]);
523 values
[idx
] = sym
= this->mkSymbol(i
, c
, baseSym
);
524 up
->mkStore(OP_STORE
, typeOfSize(value
->reg
.size
), sym
, ptr
, value
);
529 BuildUtil::DataArray::mkSymbol(int i
, int c
, Symbol
*base
)
531 const unsigned int idx
= i
* vecDim
+ c
;
533 Symbol
*sym
= new_Symbol(up
->getProgram(), file
, 0);
535 assert(base
|| (idx
< arrayLen
&& c
< vecDim
));
537 sym
->reg
.size
= eltSize
;
538 sym
->reg
.type
= typeOfSize(eltSize
);
540 sym
->setAddress(base
, baseAddr
+ idx
* eltSize
);
544 } // namespace nv50_ir