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()
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
, Symbol
*mem
, Value
*ptr
)
109 Instruction
*insn
= new_Instruction(func
, OP_LOAD
, ty
);
110 LValue
*def
= getScratch();
112 insn
->setDef(0, def
);
113 insn
->setSrc(0, mem
);
115 insn
->setIndirect(0, 0, ptr
);
122 BuildUtil::mkStore(operation op
, DataType ty
, Symbol
*mem
, Value
*ptr
,
125 Instruction
*insn
= new_Instruction(func
, op
, ty
);
127 insn
->setSrc(0, mem
);
128 insn
->setSrc(1, stVal
);
130 insn
->setIndirect(0, 0, ptr
);
137 BuildUtil::mkFetch(Value
*dst
, DataType ty
, DataFile file
, int32_t offset
,
138 Value
*attrRel
, Value
*primRel
)
140 Symbol
*sym
= mkSymbol(file
, 0, ty
, offset
);
142 Instruction
*insn
= mkOp1(OP_VFETCH
, ty
, dst
, sym
);
144 insn
->setIndirect(0, 0, attrRel
);
145 insn
->setIndirect(0, 1, primRel
);
152 BuildUtil::mkInterp(unsigned mode
, Value
*dst
, int32_t offset
, Value
*rel
)
154 operation op
= OP_LINTERP
;
155 DataType ty
= TYPE_F32
;
157 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_FLAT
)
160 if ((mode
& NV50_IR_INTERP_MODE_MASK
) == NV50_IR_INTERP_PERSPECTIVE
)
163 Symbol
*sym
= mkSymbol(FILE_SHADER_INPUT
, 0, ty
, offset
);
165 Instruction
*insn
= mkOp1(op
, ty
, dst
, sym
);
166 insn
->setIndirect(0, 0, rel
);
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 ty
, Value
*dst
,
224 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
: ty
, ty
);
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
, uint8_t tic
, uint8_t tsc
,
246 Value
**def
, Value
**src
)
248 TexInstruction
*tex
= new_TexInstruction(func
, op
);
250 for (int d
= 0; d
< 4 && def
[d
]; ++d
)
251 tex
->setDef(d
, def
[d
]);
252 for (int s
= 0; s
< 4 && src
[s
]; ++s
)
253 tex
->setSrc(s
, src
[s
]);
255 tex
->setTexture(targ
, tic
, tsc
);
261 BuildUtil::mkQuadop(uint8_t q
, Value
*def
, uint8_t l
, Value
*src0
, Value
*src1
)
263 Instruction
*quadop
= mkOp2(OP_QUADOP
, TYPE_F32
, def
, src0
, src1
);
270 BuildUtil::mkSelect(Value
*pred
, Value
*dst
, Value
*trSrc
, Value
*flSrc
)
272 LValue
*def0
= getSSA();
273 LValue
*def1
= getSSA();
275 mkMov(def0
, trSrc
)->setPredicate(CC_P
, pred
);
276 mkMov(def1
, flSrc
)->setPredicate(CC_NOT_P
, pred
);
278 return mkOp2(OP_UNION
, typeOfSize(dst
->reg
.size
), dst
, def0
, def1
);
282 BuildUtil::mkFlow(operation op
, void *targ
, CondCode cc
, Value
*pred
)
284 FlowInstruction
*insn
= new_FlowInstruction(func
, op
, targ
);
287 insn
->setPredicate(cc
, pred
);
294 BuildUtil::mkClobber(DataFile f
, uint32_t rMask
, int unit
)
296 static const uint16_t baseSize2
[16] =
298 0x0000, 0x0010, 0x0011, 0x0020, 0x0012, 0x1210, 0x1211, 0x1220,
299 0x0013, 0x1310, 0x1311, 0x1320, 0x0022, 0x2210, 0x2211, 0x0040,
304 for (; rMask
; rMask
>>= 4, base
+= 4) {
305 const uint32_t mask
= rMask
& 0xf;
308 int base1
= (baseSize2
[mask
] >> 0) & 0xf;
309 int size1
= (baseSize2
[mask
] >> 4) & 0xf;
310 int base2
= (baseSize2
[mask
] >> 8) & 0xf;
311 int size2
= (baseSize2
[mask
] >> 12) & 0xf;
312 Instruction
*insn
= mkOp(OP_NOP
, TYPE_NONE
, NULL
);
313 if (1) { // size1 can't be 0
314 LValue
*reg
= new_LValue(func
, f
);
315 reg
->reg
.size
= size1
<< unit
;
316 reg
->reg
.data
.id
= base
+ base1
;
317 insn
->setDef(0, reg
);
320 LValue
*reg
= new_LValue(func
, f
);
321 reg
->reg
.size
= size2
<< unit
;
322 reg
->reg
.data
.id
= base
+ base2
;
323 insn
->setDef(1, reg
);
329 BuildUtil::mkImm(uint32_t u
)
331 unsigned int pos
= u32Hash(u
);
333 while (imms
[pos
] && imms
[pos
]->reg
.data
.u32
!= u
)
334 pos
= (pos
+ 1) % NV50_IR_BUILD_IMM_HT_SIZE
;
336 ImmediateValue
*imm
= imms
[pos
];
338 imm
= new_ImmediateValue(prog
, u
);
345 BuildUtil::mkImm(uint64_t u
)
347 ImmediateValue
*imm
= new_ImmediateValue(prog
, (uint32_t)0);
350 imm
->reg
.type
= TYPE_U64
;
351 imm
->reg
.data
.u64
= u
;
357 BuildUtil::mkImm(float f
)
368 BuildUtil::loadImm(Value
*dst
, float f
)
370 return mkOp1v(OP_MOV
, TYPE_F32
, dst
? dst
: getScratch(), mkImm(f
));
374 BuildUtil::loadImm(Value
*dst
, uint32_t u
)
376 return mkOp1v(OP_MOV
, TYPE_U32
, dst
? dst
: getScratch(), mkImm(u
));
380 BuildUtil::loadImm(Value
*dst
, uint64_t u
)
382 return mkOp1v(OP_MOV
, TYPE_U64
, dst
? dst
: getScratch(8), mkImm(u
));
386 BuildUtil::mkSymbol(DataFile file
, int8_t fileIndex
, DataType ty
,
389 Symbol
*sym
= new_Symbol(prog
, file
, fileIndex
);
391 sym
->setOffset(baseAddr
);
393 sym
->reg
.size
= typeSizeof(ty
);
399 BuildUtil::mkSysVal(SVSemantic svName
, uint32_t svIndex
)
401 Symbol
*sym
= new_Symbol(prog
, FILE_SYSTEM_VALUE
, 0);
403 assert(svIndex
< 4 ||
404 (svName
== SV_CLIP_DISTANCE
|| svName
== SV_TESS_FACTOR
));
412 case SV_CLIP_DISTANCE
:
414 sym
->reg
.type
= TYPE_F32
;
417 sym
->reg
.type
= TYPE_U32
;
420 sym
->reg
.size
= typeSizeof(sym
->reg
.type
);
422 sym
->reg
.data
.sv
.sv
= svName
;
423 sym
->reg
.data
.sv
.index
= svIndex
;
429 BuildUtil::DataArray::setup(unsigned array
, unsigned arrayIdx
,
430 uint32_t base
, int len
, int vecDim
, int eltSize
,
431 DataFile file
, int8_t fileIdx
)
434 this->arrayIdx
= arrayIdx
;
435 this->baseAddr
= base
;
436 this->arrayLen
= len
;
437 this->vecDim
= vecDim
;
438 this->eltSize
= eltSize
;
440 this->regOnly
= !isMemoryFile(file
);
443 baseSym
= new_Symbol(up
->getProgram(), file
, fileIdx
);
444 baseSym
->setOffset(baseAddr
);
445 baseSym
->reg
.size
= eltSize
;
452 BuildUtil::DataArray::acquire(ValueMap
&m
, int i
, int c
)
455 Value
*v
= lookup(m
, i
, c
);
457 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
461 return up
->getScratch();
466 BuildUtil::DataArray::load(ValueMap
&m
, int i
, int c
, Value
*ptr
)
469 Value
*v
= lookup(m
, i
, c
);
471 v
= insert(m
, i
, c
, new_LValue(up
->getFunction(), file
));
475 Value
*sym
= lookup(m
, i
, c
);
477 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
479 return up
->mkLoad(typeOfSize(eltSize
), static_cast<Symbol
*>(sym
), ptr
);
484 BuildUtil::DataArray::store(ValueMap
&m
, int i
, int c
, Value
*ptr
, Value
*value
)
488 if (!lookup(m
, i
, c
))
489 insert(m
, i
, c
, value
);
491 assert(lookup(m
, i
, c
) == value
);
493 Value
*sym
= lookup(m
, i
, c
);
495 sym
= insert(m
, i
, c
, mkSymbol(i
, c
));
497 const DataType stTy
= typeOfSize(value
->reg
.size
);
499 up
->mkStore(OP_STORE
, stTy
, static_cast<Symbol
*>(sym
), ptr
, value
);
504 BuildUtil::DataArray::mkSymbol(int i
, int c
)
506 const unsigned int idx
= i
* vecDim
+ c
;
507 Symbol
*sym
= new_Symbol(up
->getProgram(), file
, 0);
509 assert(baseSym
|| (idx
< arrayLen
&& c
< vecDim
));
511 sym
->reg
.size
= eltSize
;
512 sym
->reg
.type
= typeOfSize(eltSize
);
513 sym
->setAddress(baseSym
, baseAddr
+ idx
* eltSize
);
517 } // namespace nv50_ir