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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
24 #include "nv50_ir_build_util.h"
28 BuildUtil::BuildUtil()
33 BuildUtil::BuildUtil(Program
*prog
)
39 BuildUtil::init(Program
*prog
)
47 memset(imms
, 0, sizeof(imms
));
52 BuildUtil::addImmediate(ImmediateValue
*imm
)
54 if (immCount
> (NV50_IR_BUILD_IMM_HT_SIZE
* 3) / 4)
57 unsigned int pos
= u32Hash(imm
->reg
.data
.u32
);
60 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
66 BuildUtil::mkOp1(operation op
, DataType ty
, Value
*dst
, Value
*src
)
68 Instruction
*insn
= new_Instruction(func
, op
, ty
);
78 BuildUtil::mkOp2(operation op
, DataType ty
, Value
*dst
,
79 Value
*src0
, Value
*src1
)
81 Instruction
*insn
= new_Instruction(func
, op
, ty
);
84 insn
->setSrc(0, src0
);
85 insn
->setSrc(1, src1
);
92 BuildUtil::mkOp3(operation op
, DataType ty
, Value
*dst
,
93 Value
*src0
, Value
*src1
, Value
*src2
)
95 Instruction
*insn
= new_Instruction(func
, op
, ty
);
98 insn
->setSrc(0, src0
);
99 insn
->setSrc(1, src1
);
100 insn
->setSrc(2, src2
);
107 BuildUtil::mkLoad(DataType ty
, Value
*dst
, Symbol
*mem
, Value
*ptr
)
109 Instruction
*insn
= new_Instruction(func
, OP_LOAD
, ty
);
111 insn
->setDef(0, dst
);
112 insn
->setSrc(0, mem
);
114 insn
->setIndirect(0, 0, ptr
);
121 BuildUtil::mkStore(operation op
, DataType ty
, Symbol
*mem
, Value
*ptr
,
124 Instruction
*insn
= new_Instruction(func
, op
, ty
);
126 insn
->setSrc(0, mem
);
127 insn
->setSrc(1, stVal
);
129 insn
->setIndirect(0, 0, ptr
);
136 BuildUtil::mkFetch(Value
*dst
, DataType ty
, DataFile file
, int32_t offset
,
137 Value
*attrRel
, Value
*primRel
)
139 Symbol
*sym
= mkSymbol(file
, 0, ty
, offset
);
141 Instruction
*insn
= mkOp1(OP_VFETCH
, ty
, dst
, sym
);
143 insn
->setIndirect(0, 0, attrRel
);
144 insn
->setIndirect(0, 1, primRel
);
151 BuildUtil::mkInterp(unsigned mode
, Value
*dst
, int32_t offset
, Value
*rel
)
153 operation op
= OP_LINTERP
;
154 DataType ty
= TYPE_F32
;
156 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_FLAT
)
159 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_PERSPECTIVE
)
162 Symbol
*sym
= mkSymbol(FILE_SHADER_INPUT
, 0, ty
, offset
);
164 Instruction
*insn
= mkOp1(op
, ty
, dst
, sym
);
165 insn
->setIndirect(0, 0, rel
);
170 BuildUtil::mkMov(Value
*dst
, Value
*src
, DataType ty
)
172 Instruction
*insn
= new_Instruction(func
, OP_MOV
, ty
);
174 insn
->setDef(0, dst
);
175 insn
->setSrc(0, src
);
182 BuildUtil::mkMovToReg(int id
, Value
*src
)
184 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(src
->reg
.size
));
186 insn
->setDef(0, new_LValue(func
, FILE_GPR
));
187 insn
->getDef(0)->reg
.data
.id
= id
;
188 insn
->setSrc(0, src
);
195 BuildUtil::mkMovFromReg(Value
*dst
, int id
)
197 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(dst
->reg
.size
));
199 insn
->setDef(0, dst
);
200 insn
->setSrc(0, new_LValue(func
, FILE_GPR
));
201 insn
->getSrc(0)->reg
.data
.id
= id
;
208 BuildUtil::mkCvt(operation op
,
209 DataType dstTy
, Value
*dst
, DataType srcTy
, Value
*src
)
211 Instruction
*insn
= new_Instruction(func
, op
, dstTy
);
213 insn
->setType(dstTy
, srcTy
);
214 insn
->setDef(0, dst
);
215 insn
->setSrc(0, src
);
222 BuildUtil::mkCmp(operation op
, CondCode cc
, DataType ty
, Value
*dst
,
223 Value
*src0
, Value
*src1
, Value
*src2
)
225 CmpInstruction
*insn
= new_CmpInstruction(func
, op
);
227 insn
->setType((dst
->reg
.file
== FILE_PREDICATE
||
228 dst
->reg
.file
== FILE_FLAGS
) ? TYPE_U8
: ty
, ty
);
229 insn
->setCondition(cc
);
230 insn
->setDef(0, dst
);
231 insn
->setSrc(0, src0
);
232 insn
->setSrc(1, src1
);
234 insn
->setSrc(2, src2
);
236 if (dst
->reg
.file
== FILE_FLAGS
)
244 BuildUtil::mkTex(operation op
, TexTarget targ
,
245 uint16_t tic
, uint16_t tsc
,
246 const std::vector
<Value
*> &def
,
247 const std::vector
<Value
*> &src
)
249 TexInstruction
*tex
= new_TexInstruction(func
, op
);
251 for (size_t d
= 0; d
< def
.size() && def
[d
]; ++d
)
252 tex
->setDef(d
, def
[d
]);
253 for (size_t s
= 0; s
< src
.size() && src
[s
]; ++s
)
254 tex
->setSrc(s
, src
[s
]);
256 tex
->setTexture(targ
, tic
, tsc
);
263 BuildUtil::mkQuadop(uint8_t q
, Value
*def
, uint8_t l
, Value
*src0
, Value
*src1
)
265 Instruction
*quadop
= mkOp2(OP_QUADOP
, TYPE_F32
, def
, src0
, src1
);
272 BuildUtil::mkSelect(Value
*pred
, Value
*dst
, Value
*trSrc
, Value
*flSrc
)
274 LValue
*def0
= getSSA();
275 LValue
*def1
= getSSA();
277 mkMov(def0
, trSrc
)->setPredicate(CC_P
, pred
);
278 mkMov(def1
, flSrc
)->setPredicate(CC_NOT_P
, pred
);
280 return mkOp2(OP_UNION
, typeOfSize(dst
->reg
.size
), dst
, def0
, def1
);
284 BuildUtil::mkSplit(Value
*h
[2], uint8_t halfSize
, Value
*val
)
286 Instruction
*insn
= NULL
;
288 const DataType fTy
= typeOfSize(halfSize
* 2);
290 if (val
->reg
.file
== FILE_IMMEDIATE
)
291 val
= mkMov(getSSA(halfSize
* 2), val
, fTy
)->getDef(0);
293 if (isMemoryFile(val
->reg
.file
)) {
294 h
[0] = cloneShallow(getFunction(), val
);
295 h
[1] = cloneShallow(getFunction(), val
);
296 h
[0]->reg
.size
= halfSize
;
297 h
[1]->reg
.size
= halfSize
;
298 h
[1]->reg
.data
.offset
+= halfSize
;
300 h
[0] = getSSA(halfSize
, val
->reg
.file
);
301 h
[1] = getSSA(halfSize
, val
->reg
.file
);
302 insn
= mkOp1(OP_SPLIT
, fTy
, h
[0], val
);
303 insn
->setDef(1, h
[1]);
309 BuildUtil::mkFlow(operation op
, void *targ
, CondCode cc
, Value
*pred
)
311 FlowInstruction
*insn
= new_FlowInstruction(func
, op
, targ
);
314 insn
->setPredicate(cc
, pred
);
321 BuildUtil::mkClobber(DataFile f
, uint32_t rMask
, int unit
)
323 static const uint16_t baseSize2
[16] =
325 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
326 0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
331 for (; rMask
; rMask
>>= 4, base
+= 4) {
332 const uint32_t mask
= rMask
& 0xf;
335 int base1
= (baseSize2
[mask
] >> 0) & 0xf;
336 int size1
= (baseSize2
[mask
] >> 4) & 0xf;
337 int base2
= (baseSize2
[mask
] >> 8) & 0xf;
338 int size2
= (baseSize2
[mask
] >> 12) & 0xf;
339 Instruction
*insn
= mkOp(OP_NOP
, TYPE_NONE
, NULL
);
340 if (1) { // size1 can't be 0
341 LValue
*reg
= new_LValue(func
, f
);
342 reg
->reg
.size
= size1
<< unit
;
343 reg
->reg
.data
.id
= base
+ base1
;
344 insn
->setDef(0, reg
);
347 LValue
*reg
= new_LValue(func
, f
);
348 reg
->reg
.size
= size2
<< unit
;
349 reg
->reg
.data
.id
= base
+ base2
;
350 insn
->setDef(1, reg
);
356 BuildUtil::mkImm(uint32_t u
)
358 unsigned int pos
= u32Hash(u
);
360 while (imms
[pos
] && imms
[pos
]->reg
.data
.u32
!= u
)
361 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
363 ImmediateValue
*imm
= imms
[pos
];
365 imm
= new_ImmediateValue(prog
, u
);
372 BuildUtil::mkImm(uint64_t u
)
374 ImmediateValue
*imm
= new_ImmediateValue(prog
, (uint32_t)0);
377 imm
->reg
.type
= TYPE_U64
;
378 imm
->reg
.data
.u64
= u
;
384 BuildUtil::mkImm(float f
)
395 BuildUtil::loadImm(Value
*dst
, float f
)
397 return mkOp1v(OP_MOV
, TYPE_F32
, dst
? dst
: getScratch(), mkImm(f
));
401 BuildUtil::loadImm(Value
*dst
, uint32_t u
)
403 return mkOp1v(OP_MOV
, TYPE_U32
, dst
? dst
: getScratch(), mkImm(u
));
407 BuildUtil::loadImm(Value
*dst
, uint64_t u
)
409 return mkOp1v(OP_MOV
, TYPE_U64
, dst
? dst
: getScratch(8), mkImm(u
));
413 BuildUtil::mkSymbol(DataFile file
, int8_t fileIndex
, DataType ty
,
416 Symbol
*sym
= new_Symbol(prog
, file
, fileIndex
);
418 sym
->setOffset(baseAddr
);
420 sym
->reg
.size
= typeSizeof(ty
);
426 BuildUtil::mkSysVal(SVSemantic svName
, uint32_t svIndex
)
428 Symbol
*sym
= new_Symbol(prog
, FILE_SYSTEM_VALUE
, 0);
430 assert(svIndex
< 4 ||
431 (svName
== SV_CLIP_DISTANCE
|| svName
== SV_TESS_FACTOR
));
439 case SV_CLIP_DISTANCE
:
441 sym
->reg
.type
= TYPE_F32
;
444 sym
->reg
.type
= TYPE_U32
;
447 sym
->reg
.size
= typeSizeof(sym
->reg
.type
);
449 sym
->reg
.data
.sv
.sv
= svName
;
450 sym
->reg
.data
.sv
.index
= svIndex
;
456 BuildUtil::DataArray::setup(unsigned array
, unsigned arrayIdx
,
457 uint32_t base
, int len
, int vecDim
, int eltSize
,
458 DataFile file
, int8_t fileIdx
)
461 this->arrayIdx
= arrayIdx
;
462 this->baseAddr
= base
;
463 this->arrayLen
= len
;
464 this->vecDim
= vecDim
;
465 this->eltSize
= eltSize
;
467 this->regOnly
= !isMemoryFile(file
);
470 baseSym
= new_Symbol(up
->getProgram(), file
, fileIdx
);
471 baseSym
->setOffset(baseAddr
);
472 baseSym
->reg
.size
= eltSize
;
479 BuildUtil::DataArray::acquire(ValueMap
&m
, int i
, int c
)
482 Value
*v
= lookup(m
, i
, c
);
484 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
488 return up
->getScratch();
493 BuildUtil::DataArray::load(ValueMap
&m
, int i
, int c
, Value
*ptr
)
496 Value
*v
= lookup(m
, i
, c
);
498 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
502 Value
*sym
= lookup(m
, i
, c
);
504 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
506 return up
->mkLoadv(typeOfSize(eltSize
), static_cast<Symbol
*>(sym
), ptr
);
511 BuildUtil::DataArray::store(ValueMap
&m
, int i
, int c
, Value
*ptr
, Value
*value
)
515 if (!lookup(m
, i
, c
))
516 insert(m
, i
, c
, value
);
518 assert(lookup(m
, i
, c
) == value
);
520 Value
*sym
= lookup(m
, i
, c
);
522 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
524 const DataType stTy
= typeOfSize(value
->reg
.size
);
526 up
->mkStore(OP_STORE
, stTy
, static_cast<Symbol
*>(sym
), ptr
, value
);
531 BuildUtil::DataArray::mkSymbol(int i
, int c
)
533 const unsigned int idx
= i
* vecDim
+ c
;
534 Symbol
*sym
= new_Symbol(up
->getProgram(), file
, 0);
536 assert(baseSym
|| (idx
< arrayLen
&& c
< vecDim
));
538 sym
->reg
.size
= eltSize
;
539 sym
->reg
.type
= typeOfSize(eltSize
);
540 sym
->setAddress(baseSym
, baseAddr
+ idx
* eltSize
);
546 BuildUtil::split64BitOpPostRA(Function
*fn
, Instruction
*i
,
554 case TYPE_U64
: hTy
= TYPE_U32
; break;
555 case TYPE_S64
: hTy
= TYPE_S32
; break;
561 case OP_MOV
: srcNr
= 1; break;
574 i
->setDef(0, cloneShallow(fn
, i
->getDef(0)));
575 i
->getDef(0)->reg
.size
= 4;
577 Instruction
*hi
= cloneForward(fn
, i
);
578 lo
->bb
->insertAfter(lo
, hi
);
580 hi
->getDef(0)->reg
.data
.id
++;
582 for (int s
= 0; s
< srcNr
; ++s
) {
583 if (lo
->getSrc(s
)->reg
.size
< 8) {
586 if (lo
->getSrc(s
)->refCount() > 1)
587 lo
->setSrc(s
, cloneShallow(fn
, lo
->getSrc(s
)));
588 lo
->getSrc(s
)->reg
.size
/= 2;
589 hi
->setSrc(s
, cloneShallow(fn
, lo
->getSrc(s
)));
591 switch (hi
->src(s
).getFile()) {
593 hi
->getSrc(s
)->reg
.data
.u64
>>= 32;
595 case FILE_MEMORY_CONST
:
596 case FILE_MEMORY_SHARED
:
597 case FILE_SHADER_INPUT
:
598 hi
->getSrc(s
)->reg
.data
.offset
+= 4;
601 assert(hi
->src(s
).getFile() == FILE_GPR
);
602 hi
->getSrc(s
)->reg
.data
.id
++;
608 lo
->setDef(1, carry
);
609 hi
->setFlagsSrc(hi
->srcCount(), carry
);
614 } // namespace nv50_ir