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.
23 #include "codegen/nv50_ir.h"
24 #include "codegen/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
);
166 insn
->setInterpolate(mode
);
171 BuildUtil::mkMov(Value
*dst
, Value
*src
, DataType ty
)
173 Instruction
*insn
= new_Instruction(func
, OP_MOV
, ty
);
175 insn
->setDef(0, dst
);
176 insn
->setSrc(0, src
);
183 BuildUtil::mkMovToReg(int id
, Value
*src
)
185 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(src
->reg
.size
));
187 insn
->setDef(0, new_LValue(func
, FILE_GPR
));
188 insn
->getDef(0)->reg
.data
.id
= id
;
189 insn
->setSrc(0, src
);
196 BuildUtil::mkMovFromReg(Value
*dst
, int id
)
198 Instruction
*insn
= new_Instruction(func
, OP_MOV
, typeOfSize(dst
->reg
.size
));
200 insn
->setDef(0, dst
);
201 insn
->setSrc(0, new_LValue(func
, FILE_GPR
));
202 insn
->getSrc(0)->reg
.data
.id
= id
;
209 BuildUtil::mkCvt(operation op
,
210 DataType dstTy
, Value
*dst
, DataType srcTy
, Value
*src
)
212 Instruction
*insn
= new_Instruction(func
, op
, dstTy
);
214 insn
->setType(dstTy
, srcTy
);
215 insn
->setDef(0, dst
);
216 insn
->setSrc(0, src
);
223 BuildUtil::mkCmp(operation op
, CondCode cc
, DataType dstTy
, Value
*dst
,
224 DataType srcTy
, Value
*src0
, Value
*src1
, Value
*src2
)
226 CmpInstruction
*insn
= new_CmpInstruction(func
, op
);
228 insn
->setType((dst
->reg
.file
== FILE_PREDICATE
||
229 dst
->reg
.file
== FILE_FLAGS
) ? TYPE_U8
: dstTy
, srcTy
);
230 insn
->setCondition(cc
);
231 insn
->setDef(0, dst
);
232 insn
->setSrc(0, src0
);
233 insn
->setSrc(1, src1
);
235 insn
->setSrc(2, src2
);
237 if (dst
->reg
.file
== FILE_FLAGS
)
245 BuildUtil::mkTex(operation op
, TexTarget targ
,
246 uint16_t tic
, uint16_t tsc
,
247 const std::vector
<Value
*> &def
,
248 const std::vector
<Value
*> &src
)
250 TexInstruction
*tex
= new_TexInstruction(func
, op
);
252 for (size_t d
= 0; d
< def
.size() && def
[d
]; ++d
)
253 tex
->setDef(d
, def
[d
]);
254 for (size_t s
= 0; s
< src
.size() && src
[s
]; ++s
)
255 tex
->setSrc(s
, src
[s
]);
257 tex
->setTexture(targ
, tic
, tsc
);
264 BuildUtil::mkQuadop(uint8_t q
, Value
*def
, uint8_t l
, Value
*src0
, Value
*src1
)
266 Instruction
*quadop
= mkOp2(OP_QUADOP
, TYPE_F32
, def
, src0
, src1
);
273 BuildUtil::mkSelect(Value
*pred
, Value
*dst
, Value
*trSrc
, Value
*flSrc
)
275 LValue
*def0
= getSSA();
276 LValue
*def1
= getSSA();
278 mkMov(def0
, trSrc
)->setPredicate(CC_P
, pred
);
279 mkMov(def1
, flSrc
)->setPredicate(CC_NOT_P
, pred
);
281 return mkOp2(OP_UNION
, typeOfSize(dst
->reg
.size
), dst
, def0
, def1
);
285 BuildUtil::mkSplit(Value
*h
[2], uint8_t halfSize
, Value
*val
)
287 Instruction
*insn
= NULL
;
289 const DataType fTy
= typeOfSize(halfSize
* 2);
291 if (val
->reg
.file
== FILE_IMMEDIATE
)
292 val
= mkMov(getSSA(halfSize
* 2), val
, fTy
)->getDef(0);
294 if (isMemoryFile(val
->reg
.file
)) {
295 h
[0] = cloneShallow(getFunction(), val
);
296 h
[1] = cloneShallow(getFunction(), val
);
297 h
[0]->reg
.size
= halfSize
;
298 h
[1]->reg
.size
= halfSize
;
299 h
[1]->reg
.data
.offset
+= halfSize
;
301 h
[0] = getSSA(halfSize
, val
->reg
.file
);
302 h
[1] = getSSA(halfSize
, val
->reg
.file
);
303 insn
= mkOp1(OP_SPLIT
, fTy
, h
[0], val
);
304 insn
->setDef(1, h
[1]);
310 BuildUtil::mkFlow(operation op
, void *targ
, CondCode cc
, Value
*pred
)
312 FlowInstruction
*insn
= new_FlowInstruction(func
, op
, targ
);
315 insn
->setPredicate(cc
, pred
);
322 BuildUtil::mkClobber(DataFile f
, uint32_t rMask
, int unit
)
324 static const uint16_t baseSize2
[16] =
326 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
327 0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
332 for (; rMask
; rMask
>>= 4, base
+= 4) {
333 const uint32_t mask
= rMask
& 0xf;
336 int base1
= (baseSize2
[mask
] >> 0) & 0xf;
337 int size1
= (baseSize2
[mask
] >> 4) & 0xf;
338 int base2
= (baseSize2
[mask
] >> 8) & 0xf;
339 int size2
= (baseSize2
[mask
] >> 12) & 0xf;
340 Instruction
*insn
= mkOp(OP_NOP
, TYPE_NONE
, NULL
);
341 if (1) { // size1 can't be 0
342 LValue
*reg
= new_LValue(func
, f
);
343 reg
->reg
.size
= size1
<< unit
;
344 reg
->reg
.data
.id
= base
+ base1
;
345 insn
->setDef(0, reg
);
348 LValue
*reg
= new_LValue(func
, f
);
349 reg
->reg
.size
= size2
<< unit
;
350 reg
->reg
.data
.id
= base
+ base2
;
351 insn
->setDef(1, reg
);
357 BuildUtil::mkImm(uint32_t u
)
359 unsigned int pos
= u32Hash(u
);
361 while (imms
[pos
] && imms
[pos
]->reg
.data
.u32
!= u
)
362 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
364 ImmediateValue
*imm
= imms
[pos
];
366 imm
= new_ImmediateValue(prog
, u
);
373 BuildUtil::mkImm(uint64_t u
)
375 ImmediateValue
*imm
= new_ImmediateValue(prog
, (uint32_t)0);
378 imm
->reg
.type
= TYPE_U64
;
379 imm
->reg
.data
.u64
= u
;
385 BuildUtil::mkImm(float f
)
396 BuildUtil::mkImm(double d
)
398 return new_ImmediateValue(prog
, d
);
402 BuildUtil::loadImm(Value
*dst
, float f
)
404 return mkOp1v(OP_MOV
, TYPE_F32
, dst
? dst
: getScratch(), mkImm(f
));
408 BuildUtil::loadImm(Value
*dst
, double d
)
410 return mkOp1v(OP_MOV
, TYPE_F64
, dst
? dst
: getScratch(8), mkImm(d
));
414 BuildUtil::loadImm(Value
*dst
, uint32_t u
)
416 return mkOp1v(OP_MOV
, TYPE_U32
, dst
? dst
: getScratch(), mkImm(u
));
420 BuildUtil::loadImm(Value
*dst
, uint64_t u
)
422 return mkOp1v(OP_MOV
, TYPE_U64
, dst
? dst
: getScratch(8), mkImm(u
));
426 BuildUtil::mkSymbol(DataFile file
, int8_t fileIndex
, DataType ty
,
429 Symbol
*sym
= new_Symbol(prog
, file
, fileIndex
);
431 sym
->setOffset(baseAddr
);
433 sym
->reg
.size
= typeSizeof(ty
);
439 BuildUtil::mkSysVal(SVSemantic svName
, uint32_t svIndex
)
441 Symbol
*sym
= new_Symbol(prog
, FILE_SYSTEM_VALUE
, 0);
443 assert(svIndex
< 4 || svName
== SV_CLIP_DISTANCE
);
451 case SV_CLIP_DISTANCE
:
455 sym
->reg
.type
= TYPE_F32
;
458 sym
->reg
.type
= TYPE_U32
;
461 sym
->reg
.size
= typeSizeof(sym
->reg
.type
);
463 sym
->reg
.data
.sv
.sv
= svName
;
464 sym
->reg
.data
.sv
.index
= svIndex
;
470 BuildUtil::DataArray::setup(unsigned array
, unsigned arrayIdx
,
471 uint32_t base
, int len
, int vecDim
, int eltSize
,
472 DataFile file
, int8_t fileIdx
)
475 this->arrayIdx
= arrayIdx
;
476 this->baseAddr
= base
;
477 this->arrayLen
= len
;
478 this->vecDim
= vecDim
;
479 this->eltSize
= eltSize
;
481 this->regOnly
= !isMemoryFile(file
);
484 baseSym
= new_Symbol(up
->getProgram(), file
, fileIdx
);
485 baseSym
->setOffset(baseAddr
);
486 baseSym
->reg
.size
= eltSize
;
493 BuildUtil::DataArray::acquire(ValueMap
&m
, int i
, int c
)
496 Value
*v
= lookup(m
, i
, c
);
498 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
502 return up
->getScratch(eltSize
);
507 BuildUtil::DataArray::load(ValueMap
&m
, int i
, int c
, Value
*ptr
)
510 Value
*v
= lookup(m
, i
, c
);
512 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
516 Value
*sym
= lookup(m
, i
, c
);
518 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
520 return up
->mkLoadv(typeOfSize(eltSize
), static_cast<Symbol
*>(sym
), ptr
);
525 BuildUtil::DataArray::store(ValueMap
&m
, int i
, int c
, Value
*ptr
, Value
*value
)
529 if (!lookup(m
, i
, c
))
530 insert(m
, i
, c
, value
);
532 assert(lookup(m
, i
, c
) == value
);
534 Value
*sym
= lookup(m
, i
, c
);
536 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
538 const DataType stTy
= typeOfSize(value
->reg
.size
);
540 up
->mkStore(OP_STORE
, stTy
, static_cast<Symbol
*>(sym
), ptr
, value
);
545 BuildUtil::DataArray::mkSymbol(int i
, int c
)
547 const unsigned int idx
= i
* vecDim
+ c
;
548 Symbol
*sym
= new_Symbol(up
->getProgram(), file
, 0);
550 assert(baseSym
|| (idx
< arrayLen
&& c
< vecDim
));
552 sym
->reg
.size
= eltSize
;
553 sym
->reg
.type
= typeOfSize(eltSize
);
554 sym
->setAddress(baseSym
, baseAddr
+ idx
* eltSize
);
560 BuildUtil::split64BitOpPostRA(Function
*fn
, Instruction
*i
,
568 case TYPE_U64
: hTy
= TYPE_U32
; break;
569 case TYPE_S64
: hTy
= TYPE_S32
; break;
571 if (i
->op
== OP_MOV
) {
581 case OP_MOV
: srcNr
= 1; break;
594 i
->setDef(0, cloneShallow(fn
, i
->getDef(0)));
595 i
->getDef(0)->reg
.size
= 4;
597 Instruction
*hi
= cloneForward(fn
, i
);
598 lo
->bb
->insertAfter(lo
, hi
);
600 hi
->getDef(0)->reg
.data
.id
++;
602 for (int s
= 0; s
< srcNr
; ++s
) {
603 if (lo
->getSrc(s
)->reg
.size
< 8) {
606 if (lo
->getSrc(s
)->refCount() > 1)
607 lo
->setSrc(s
, cloneShallow(fn
, lo
->getSrc(s
)));
608 lo
->getSrc(s
)->reg
.size
/= 2;
609 hi
->setSrc(s
, cloneShallow(fn
, lo
->getSrc(s
)));
611 switch (hi
->src(s
).getFile()) {
613 hi
->getSrc(s
)->reg
.data
.u64
>>= 32;
615 case FILE_MEMORY_CONST
:
616 case FILE_MEMORY_SHARED
:
617 case FILE_SHADER_INPUT
:
618 hi
->getSrc(s
)->reg
.data
.offset
+= 4;
621 assert(hi
->src(s
).getFile() == FILE_GPR
);
622 hi
->getSrc(s
)->reg
.data
.id
++;
628 lo
->setDef(1, carry
);
629 hi
->setFlagsSrc(hi
->srcCount(), carry
);
634 } // namespace nv50_ir