in projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp [1902:4509]
void DxbcConverter::ConvertInstructions(D3D10ShaderBinary::CShaderCodeParser &Parser) {
if (m_pPR->GetShaderModel()->IsGS()) {
// Set GS active stream mask.
if (m_pPR->GetActiveStreamMask() == 0
&& !m_pPR->GetOutputSignature().GetElements().empty())
m_pPR->SetStreamActive(0, true);
// Make sure GS instance count is at least 1
if (m_pPR->GetGSInstanceCount() == 0)
m_pPR->SetGSInstanceCount(1);
}
// Add entry function declaration.
m_pPR->SetEntryFunctionName("main");
FunctionType *pEntryFuncType = FunctionType::get(Type::getVoidTy(m_Ctx), false);
Function *pFunction = Function::Create(pEntryFuncType, GlobalValue::LinkageTypes::ExternalLinkage,
m_pPR->GetEntryFunctionName(), m_pModule.get());
pFunction->setCallingConv(CallingConv::C);
m_pPR->SetEntryFunction(pFunction);
// Create main entry function.
BasicBlock *pBB = BasicBlock::Create(m_Ctx, "entry", pFunction);
m_pBuilder = std::make_unique< IRBuilder<> >(pBB);
FastMathFlags FMF;
if (!m_pPR->m_ShaderFlags.GetDisableMathRefactoring()) {
FMF.setUnsafeAlgebra();
}
m_pBuilder->SetFastMathFlags(FMF);
// Empty instruction stream.
if (Parser.EndOfShader()) {
m_pBuilder->CreateRetVoid();
return;
}
m_pUnusedF32 = UndefValue::get(Type::getFloatTy(m_Ctx));
m_pUnusedI32 = UndefValue::get(Type::getInt32Ty(m_Ctx));
// Create entry function scope.
DXASSERT_NOMSG(m_ScopeStack.IsEmpty());
(void)m_ScopeStack.Push(Scope::Function, nullptr);
m_ScopeStack.Top().SetEntry(true);
DeclareIndexableRegisters();
// Parse DXBC instructions and emit DXIL equivalents.
Value *pHullLoopInductionVar = nullptr;
m_bControlPointPhase = false;
bool bMustCloseHullLoop = false;
m_bPatchConstantPhase = false;
bool bInsertResourceHandles = true;
unsigned ForkJoinPhaseIndex = 0;
D3D10ShaderBinary::CInstruction Inst;
bool bPasshThroughCP = false;
bool bDoneParsing = false;
for (;;) {
AdvanceDxbcInstructionStream(Parser, Inst, bDoneParsing);
// Terminate HS phase (HullLoop), if necessary.
if (m_bPatchConstantPhase) {
bool bTerminateHullLoop = false;
if (bDoneParsing || bMustCloseHullLoop) {
bTerminateHullLoop = true;
} else {
switch (Inst.OpCode()) {
case D3D11_SB_OPCODE_HS_FORK_PHASE:
case D3D11_SB_OPCODE_HS_JOIN_PHASE:
case D3D10_SB_OPCODE_LABEL:
bTerminateHullLoop = true;
break;
}
}
if (bTerminateHullLoop) {
IFTBOOL(m_ScopeStack.Top().Kind == Scope::HullLoop, E_FAIL);
// Hull shader control point phase fork/join.
Scope &HullScope = m_ScopeStack.Top();
// Increment HullLoop instance ID.
Value *pOldInstID = m_pBuilder->CreateLoad(HullScope.pInductionVar);
Value *pNewInstID = m_pBuilder->CreateAdd(pOldInstID, m_pOP->GetU32Const(1));
(void)m_pBuilder->CreateStore(pNewInstID, HullScope.pInductionVar);
// Insert backedge cbranch to HullLoop and AfterHullLoop BBs.
Value *pCond = m_pBuilder->CreateICmpULT(pNewInstID, m_pOP->GetU32Const(HullScope.HullLoopTripCount));
m_pBuilder->CreateCondBr(pCond, HullScope.pHullLoopBB, HullScope.pPostScopeBB);
m_pPR->GetPatchConstantFunction()->getBasicBlockList().push_back(HullScope.pPostScopeBB);
m_pBuilder->SetInsertPoint(HullScope.pPostScopeBB);
m_ScopeStack.Pop();
// Skip dead instructions to the next phase, label or EOS.
for( ; !bDoneParsing ; ) {
if (Inst.OpCode() == D3D11_SB_OPCODE_HS_FORK_PHASE ||
Inst.OpCode() == D3D11_SB_OPCODE_HS_JOIN_PHASE ||
Inst.OpCode() == D3D10_SB_OPCODE_LABEL)
break;
AdvanceDxbcInstructionStream(Parser, Inst, bDoneParsing);
}
}
bMustCloseHullLoop = false;
}
// Terminate function, if necessary.
{
bool bTerminateFunc = false;
if (bDoneParsing) {
bTerminateFunc = true;
} else {
switch (Inst.OpCode()) {
case D3D11_SB_OPCODE_HS_FORK_PHASE:
case D3D11_SB_OPCODE_HS_JOIN_PHASE:
if (!m_bPatchConstantPhase)
bTerminateFunc = true;
break;
case D3D10_SB_OPCODE_LABEL:
bTerminateFunc = true;
break;
}
}
if (bTerminateFunc) {
Scope &Scope = m_ScopeStack.FindParentFunction();
IFTBOOL(Scope.Kind == Scope::Function, DXC_E_INCORRECT_DXBC);
m_pBuilder->CreateRetVoid();
m_ScopeStack.Pop();
IFT(m_ScopeStack.IsEmpty());
m_bPatchConstantPhase = false;
}
}
if (bDoneParsing)
break;
m_PreciseMask = CMask(Inst.GetPreciseMask());
// Fix up output register masks.
// DXBC instruction conversion relies on the output mask(s) determining
// what components need to be written.
// Some output operand types have write mask that is 0 -- fix this.
for (unsigned i = 0; i < std::min(Inst.m_NumOperands, (UINT)2); i++) {
D3D10ShaderBinary::COperandBase &O = Inst.m_Operands[i];
switch (O.m_Type) {
case D3D10_SB_OPERAND_TYPE_OUTPUT_DEPTH:
case D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL:
case D3D11_SB_OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL:
case D3D11_SB_OPERAND_TYPE_OUTPUT_STENCIL_REF:
case D3D10_SB_OPERAND_TYPE_OUTPUT_COVERAGE_MASK:
DXASSERT_DXBC(O.m_WriteMask == 0);
O.SetMask(D3D10_SB_OPERAND_4_COMPONENT_MASK_X);
break;
}
}
if (bInsertResourceHandles) {
InsertSM50ResourceHandles();
bInsertResourceHandles = false;
}
switch (Inst.OpCode()) {
//
// Declarations.
//
case D3D10_SB_OPCODE_DCL_RESOURCE:
case D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER:
case D3D10_SB_OPCODE_DCL_SAMPLER:
case D3D10_SB_OPCODE_DCL_INDEX_RANGE:
case D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
case D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE:
case D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
case D3D10_SB_OPCODE_DCL_INPUT:
case D3D10_SB_OPCODE_DCL_INPUT_SGV:
case D3D10_SB_OPCODE_DCL_INPUT_SIV:
case D3D10_SB_OPCODE_DCL_INPUT_PS:
case D3D10_SB_OPCODE_DCL_INPUT_PS_SGV:
case D3D10_SB_OPCODE_DCL_INPUT_PS_SIV:
case D3D10_SB_OPCODE_DCL_OUTPUT:
case D3D10_SB_OPCODE_DCL_OUTPUT_SGV:
case D3D10_SB_OPCODE_DCL_OUTPUT_SIV:
case D3D10_SB_OPCODE_DCL_TEMPS:
case D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP:
break;
case D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS:
break;
case D3D11_SB_OPCODE_DCL_STREAM:
case D3D11_SB_OPCODE_DCL_FUNCTION_BODY:
case D3D11_SB_OPCODE_DCL_FUNCTION_TABLE:
case D3D11_SB_OPCODE_DCL_INTERFACE:
case D3D11_SB_OPCODE_HS_DECLS:
case D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
case D3D11_SB_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
case D3D11_SB_OPCODE_DCL_TESS_DOMAIN:
case D3D11_SB_OPCODE_DCL_TESS_PARTITIONING:
case D3D11_SB_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
case D3D11_SB_OPCODE_DCL_HS_MAX_TESSFACTOR:
case D3D11_SB_OPCODE_DCL_THREAD_GROUP:
case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
case D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
case D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
case D3D11_SB_OPCODE_DCL_RESOURCE_RAW:
case D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED:
case D3D11_SB_OPCODE_DCL_GS_INSTANCE_COUNT:
break;
//
// Immediate constant buffer.
//
case D3D10_SB_OPCODE_CUSTOMDATA:
if (Inst.m_CustomData.Type == D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER) {
unsigned Size = Inst.m_CustomData.DataSizeInBytes >> 2;
DXASSERT_DXBC(m_pIcbGV == nullptr && Inst.m_CustomData.DataSizeInBytes == Size*4);
llvm::Constant *pIcbData = ConstantDataArray::get(m_Ctx, ArrayRef<float>((float*)Inst.m_CustomData.pData, Size));
m_pIcbGV = new GlobalVariable(*m_pModule, pIcbData->getType(), true, GlobalValue::InternalLinkage,
pIcbData, "dx.icb", nullptr,
GlobalVariable::NotThreadLocal, DXIL::kImmediateCBufferAddrSpace);
}
break;
//
// Mov, movc, swapc, dmov, dmovc.
//
case D3D10_SB_OPCODE_MOV: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType DstType = InferOperandType(Inst, 0, WriteMask);
CompType SrcType = InferOperandType(Inst, 1, WriteMask);
// For mov, movc, and swapc, use integer operation type unless
// operand modifiers imply floating point.
CompType OperationType = CompType::getI32();
if (!DstType.IsInvalid())
OperationType = DstType.GetBaseCompType();
else if (!SrcType.IsInvalid())
OperationType = SrcType;
if (Inst.m_Operands[1].Modifier() != D3D10_SB_OPERAND_MODIFIER_NONE || Inst.m_bSaturate) {
OperationType = CompType::getF32();
}
OperandValue In;
LoadOperand(In, Inst, 1, WriteMask, OperationType);
StoreOperand(In, Inst, 0, WriteMask, OperationType);
break;
}
case D3D10_SB_OPCODE_MOVC: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType DstType = InferOperandType(Inst, 0, WriteMask);
CompType Src2Type = InferOperandType(Inst, 2, WriteMask);
CompType Src3Type = InferOperandType(Inst, 3, WriteMask);
CompType OperationType = CompType::getI32();
if (Src2Type == Src3Type && !Src2Type.IsInvalid())
OperationType = Src2Type;
else if (!DstType.IsInvalid())
OperationType = DstType.GetBaseCompType();
else if (!Src2Type.IsInvalid())
OperationType = Src2Type;
else if (!Src3Type.IsInvalid())
OperationType = Src3Type;
if (Inst.m_Operands[2].Modifier() != D3D10_SB_OPERAND_MODIFIER_NONE ||
Inst.m_Operands[3].Modifier() != D3D10_SB_OPERAND_MODIFIER_NONE ||
Inst.m_bSaturate) {
OperationType = CompType::getF32();
}
OperandValue In1, In2, In3, Out;
LoadOperand(In1, Inst, 1, WriteMask, CompType::getI1());
LoadOperand(In2, Inst, 2, WriteMask, OperationType);
LoadOperand(In3, Inst, 3, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateSelect(In1[c], In2[c], In3[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
case D3D11_SB_OPCODE_SWAPC: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask | Inst.m_Operands[1].m_WriteMask);
CMask Dst1Mask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CMask Dst2Mask = CMask::FromDXBC(Inst.m_Operands[1].m_WriteMask);
CompType Dst1Type = InferOperandType(Inst, 0, WriteMask);
CompType Dst2Type = InferOperandType(Inst, 1, WriteMask);
CompType Src2Type = InferOperandType(Inst, 3, WriteMask);
CompType Src3Type = InferOperandType(Inst, 4, WriteMask);
CompType OperationType = CompType::getI32();
if (Src2Type == Src3Type && !Src2Type.IsInvalid())
OperationType = Src2Type;
else if (!Dst1Type.IsInvalid())
OperationType = Dst1Type.GetBaseCompType();
else if (!Dst2Type.IsInvalid())
OperationType = Dst2Type.GetBaseCompType();
else if (!Src2Type.IsInvalid())
OperationType = Src2Type;
else if (!Src3Type.IsInvalid())
OperationType = Src3Type;
if (Inst.m_Operands[3].Modifier() != D3D10_SB_OPERAND_MODIFIER_NONE ||
Inst.m_Operands[4].Modifier() != D3D10_SB_OPERAND_MODIFIER_NONE ||
Inst.m_bSaturate) {
OperationType = CompType::getF32();
}
OperandValue In1, In2, In3, Out1, Out2;
LoadOperand(In1, Inst, 2, WriteMask, CompType::getI1());
LoadOperand(In2, Inst, 3, WriteMask, OperationType);
LoadOperand(In3, Inst, 4, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!Dst1Mask.IsSet(c)) continue;
Out1[c] = m_pBuilder->CreateSelect(In1[c], In3[c], In2[c]);
}
StoreOperand(Out1, Inst, 0, Dst1Mask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!Dst2Mask.IsSet(c)) continue;
Out2[c] = m_pBuilder->CreateSelect(In1[c], In2[c], In3[c]);
}
StoreOperand(Out2, Inst, 1, Dst2Mask, OperationType);
break;
}
//
// Floating point unary.
//
case D3D10_SB_OPCODE_EXP: ConvertUnary(OP::OpCode::Exp, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_FRC: ConvertUnary(OP::OpCode::Frc, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_LOG: ConvertUnary(OP::OpCode::Log, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_SQRT: ConvertUnary(OP::OpCode::Sqrt, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_RSQ: ConvertUnary(OP::OpCode::Rsqrt, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_ROUND_NE: ConvertUnary(OP::OpCode::Round_ne, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_ROUND_NI: ConvertUnary(OP::OpCode::Round_ni, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_ROUND_PI: ConvertUnary(OP::OpCode::Round_pi, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_ROUND_Z: ConvertUnary(OP::OpCode::Round_z, CompType::getF32(), Inst); break;
case D3D11_SB_OPCODE_RCP: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType OperationType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[0].m_MinPrecision);
OperandValue In, Out;
LoadOperand(In, Inst, 1, WriteMask, OperationType);
Value *One = m_pOP->GetFloatConst(1.0f);
if (OperationType.Is16Bit())
One = ConstantFP::get(m_pBuilder->getHalfTy(), 1.0);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateBinOp(Instruction::BinaryOps::FDiv, One, In[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
case D3D10_SB_OPCODE_SINCOS:
{
CMask WriteMaskSin;
CMask WriteMaskCos;
CompType OperationType;
if (Inst.m_Operands[0].m_Type != D3D10_SB_OPERAND_TYPE_NULL) {
WriteMaskSin = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
OperationType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[0].m_MinPrecision);
}
if (Inst.m_Operands[1].m_Type != D3D10_SB_OPERAND_TYPE_NULL) {
WriteMaskCos = CMask::FromDXBC(Inst.m_Operands[1].m_WriteMask);
CompType OperationTypeCos = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[1].m_MinPrecision);
DXASSERT_DXBC(OperationType.GetKind() == CompType::Kind::Invalid || OperationType == OperationTypeCos);
OperationType = OperationTypeCos;
}
CMask WriteMaskAll = WriteMaskSin | WriteMaskCos;
Type *pOperationType = OperationType.GetLLVMType(m_Ctx);
OperandValue In;
LoadOperand(In, Inst, 2, WriteMaskAll, OperationType);
if (Inst.m_Operands[0].m_Type != D3D10_SB_OPERAND_TYPE_NULL) {
OperandValue Out;
Function *pFunc = m_pOP->GetOpFunc(OP::OpCode::Sin, pOperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMaskSin.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateCall(pFunc, { m_pOP->GetU32Const((unsigned)OP::OpCode::Sin), In[c] });
}
StoreOperand(Out, Inst, 0, WriteMaskSin, OperationType);
}
if (Inst.m_Operands[1].m_Type != D3D10_SB_OPERAND_TYPE_NULL) {
OperandValue Out;
Function *pFunc = m_pOP->GetOpFunc(OP::OpCode::Cos, pOperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMaskCos.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateCall(pFunc, { m_pOP->GetU32Const((unsigned)OP::OpCode::Cos), In[c] });
}
StoreOperand(Out, Inst, 1, WriteMaskCos, OperationType);
}
break;
}
//
// Integer unary.
//
case D3D11_SB_OPCODE_BFREV: ConvertUnary(OP::OpCode::Bfrev, CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_COUNTBITS: ConvertUnary(OP::OpCode::Countbits, CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_FIRSTBIT_HI: ConvertUnary(OP::OpCode::FirstbitHi, CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_FIRSTBIT_LO: ConvertUnary(OP::OpCode::FirstbitLo, CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_FIRSTBIT_SHI: ConvertUnary(OP::OpCode::FirstbitSHi, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_INEG: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType OperationType = DXBC::GetCompTypeWithMinPrec(CompType::getI32(), Inst.m_Operands[0].m_MinPrecision);
OperandValue In, Out;
LoadOperand(In, Inst, 1, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateNeg(In[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
case D3D10_SB_OPCODE_NOT: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType OperationType = DXBC::GetCompTypeWithMinPrec(CompType::getI32(), Inst.m_Operands[0].m_MinPrecision);
OperandValue In, Out;
LoadOperand(In, Inst, 1, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateNot(In[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
//
// Floating point binary.
//
case D3D10_SB_OPCODE_ADD: ConvertBinary(Instruction::FAdd, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_MUL: ConvertBinary(Instruction::FMul, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_DIV: ConvertBinary(Instruction::FDiv, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_MAX: ConvertBinary(OP::OpCode::FMax, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_MIN: ConvertBinary(OP::OpCode::FMin, CompType::getF32(), Inst); break;
//
// Integer binary.
//
case D3D10_SB_OPCODE_IADD: ConvertBinary(Instruction::Add, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_IMAX: ConvertBinary(OP::OpCode::IMax, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_IMIN: ConvertBinary(OP::OpCode::IMin, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_UMAX: ConvertBinary(OP::OpCode::UMax, CompType::getU32(), Inst); break;
case D3D10_SB_OPCODE_UMIN: ConvertBinary(OP::OpCode::UMin, CompType::getU32(), Inst); break;
case D3D10_SB_OPCODE_AND: ConvertBinary(Instruction::And, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_OR: ConvertBinary(Instruction::Or, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_XOR: ConvertBinary(Instruction::Xor, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_ISHL: ConvertBinary(Instruction::Shl, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_ISHR: ConvertBinary(Instruction::AShr, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_USHR: ConvertBinary(Instruction::LShr, CompType::getI32(), Inst); break;
//
// Integer binary with two outputs.
//
case D3D10_SB_OPCODE_IMUL: ConvertBinaryWithTwoOuts(OP::OpCode::IMul, Inst); break;
case D3D10_SB_OPCODE_UMUL: ConvertBinaryWithTwoOuts(OP::OpCode::UMul, Inst); break;
case D3D10_SB_OPCODE_UDIV: ConvertBinaryWithTwoOuts(OP::OpCode::UDiv, Inst); break;
//
// Integer binary with carry.
//
case D3D11_SB_OPCODE_UADDC: ConvertBinaryWithCarry(OP::OpCode::UAddc, Inst); break;
case D3D11_SB_OPCODE_USUBB: ConvertBinaryWithCarry(OP::OpCode::USubb, Inst); break;
//
// Floating point tertiary.
//
case D3D10_SB_OPCODE_MAD: ConvertTertiary(OP::OpCode::FMad, CompType::getF32(), Inst); break;
//
// Integer tertiary.
//
case D3D10_SB_OPCODE_IMAD: ConvertTertiary(OP::OpCode::IMad, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_UMAD: ConvertTertiary(OP::OpCode::UMad, CompType::getI32(), Inst); break;
case D3D11_1_SB_OPCODE_MSAD: ConvertTertiary(OP::OpCode::Msad, CompType::getI32(), Inst); break;
case D3D11_SB_OPCODE_IBFE: ConvertTertiary(OP::OpCode::Ibfe, CompType::getI32(), Inst); break;
case D3D11_SB_OPCODE_UBFE: ConvertTertiary(OP::OpCode::Ubfe, CompType::getI32(), Inst); break;
//
// Quaternary int.
//
case D3D11_SB_OPCODE_BFI: ConvertQuaternary(OP::OpCode::Bfi, CompType::getI32(), Inst); break;
//
// Logical comparison.
//
case D3D10_SB_OPCODE_EQ: ConvertComparison(CmpInst::FCMP_OEQ, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_NE: ConvertComparison(CmpInst::FCMP_UNE, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_LT: ConvertComparison(CmpInst::FCMP_OLT, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_GE: ConvertComparison(CmpInst::FCMP_OGE, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_IEQ: ConvertComparison(CmpInst::ICMP_EQ, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_INE: ConvertComparison(CmpInst::ICMP_NE, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_ILT: ConvertComparison(CmpInst::ICMP_SLT, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_IGE: ConvertComparison(CmpInst::ICMP_SGE, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_ULT: ConvertComparison(CmpInst::ICMP_ULT, CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_UGE: ConvertComparison(CmpInst::ICMP_UGE, CompType::getI32(), Inst); break;
//
// Dot product.
//
case D3D10_SB_OPCODE_DP2: ConvertDotProduct(OP::OpCode::Dot2, 2, CMask::MakeMask(1,1,0,0), Inst); break;
case D3D10_SB_OPCODE_DP3: ConvertDotProduct(OP::OpCode::Dot3, 3, CMask::MakeMask(1,1,1,0), Inst); break;
case D3D10_SB_OPCODE_DP4: ConvertDotProduct(OP::OpCode::Dot4, 4, CMask::MakeMask(1,1,1,1), Inst); break;
//
// Type conversions.
//
case D3D10_SB_OPCODE_ITOF: ConvertCast(CompType::getI32(), CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_UTOF: ConvertCast(CompType::getU32(), CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_FTOI: ConvertCast(CompType::getF32(), CompType::getI32(), Inst); break;
case D3D10_SB_OPCODE_FTOU: ConvertCast(CompType::getF32(), CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_F32TOF16: {
const unsigned DstIdx = 0;
const unsigned SrcIdx = 1;
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[DstIdx].m_WriteMask);
if (!WriteMask.IsZero()) {
OperandValue In, Out;
LoadOperand(In, Inst, SrcIdx, WriteMask, CompType::getF32());
OP::OpCode OpCode = OP::OpCode::LegacyF32ToF16;
CompType DstType = CompType::getU32();
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
Args[1] = In[c];
Out[c] = m_pBuilder->CreateCall(F, Args);
}
StoreOperand(Out, Inst, DstIdx, WriteMask, DstType);
}
break;
}
case D3D11_SB_OPCODE_F16TOF32: {
const unsigned DstIdx = 0;
const unsigned SrcIdx = 1;
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[DstIdx].m_WriteMask);
if (!WriteMask.IsZero()) {
OperandValue In, Out;
D3D10_SB_OPERAND_MODIFIER SrcModifier = Inst.m_Operands[SrcIdx].m_Modifier;
Inst.m_Operands[SrcIdx].m_Modifier = D3D10_SB_OPERAND_MODIFIER_NONE;
LoadOperand(In, Inst, SrcIdx, WriteMask, CompType::getU32());
OP::OpCode OpCode = OP::OpCode::LegacyF16ToF32;
CompType DstType = CompType::getF32();
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!WriteMask.IsSet(c)) continue;
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
Args[1] = In[c];
Value *pResult = m_pBuilder->CreateCall(F, Args);
// Special-case: propagate source operand modifiers to result.
if (SrcModifier & D3D10_SB_OPERAND_MODIFIER_ABS) {
Function *Fabs = m_pOP->GetOpFunc(OP::OpCode::FAbs, pResult->getType());
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::FAbs);
Args[1] = pResult;
pResult = m_pBuilder->CreateCall(Fabs, Args);
}
if (SrcModifier & D3D10_SB_OPERAND_MODIFIER_NEG) {
pResult = MarkPrecise(m_pBuilder->CreateFNeg(MarkPrecise(pResult, c)), c);
}
Out[c] = pResult;
}
StoreOperand(Out, Inst, DstIdx, WriteMask, CompType::getF32());
}
break;
}
//
// Double-precision operations.
//
case D3D11_SB_OPCODE_DADD: ConvertBinary(Instruction::FAdd, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DMAX: ConvertBinary(OP::OpCode::FMax, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DMIN: ConvertBinary(OP::OpCode::FMin, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DMUL: ConvertBinary(Instruction::FMul, CompType::getF64(), Inst); break;
case D3D11_1_SB_OPCODE_DDIV: ConvertBinary(Instruction::FDiv, CompType::getF64(), Inst); break;
case D3D11_1_SB_OPCODE_DFMA: ConvertTertiary(OP::OpCode::Fma, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DEQ: ConvertComparison(CmpInst::FCMP_OEQ, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DGE: ConvertComparison(CmpInst::FCMP_OGE, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DLT: ConvertComparison(CmpInst::FCMP_OLT, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DNE: ConvertComparison(CmpInst::FCMP_UNE, CompType::getF64(), Inst); break;
case D3D11_SB_OPCODE_DMOV: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
OperandValue In;
LoadOperand(In, Inst, 1, WriteMask, CompType::getF64());
StoreOperand(In, Inst, 0, WriteMask, CompType::getF64());
break;
}
case D3D11_SB_OPCODE_DMOVC: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType OperationType = CompType::getF64();
OperandValue In1, In2, In3, Out;
LoadOperand(In1, Inst, 1, CMask(1, 1, 0, 0), CompType::getI1());
LoadOperand(In2, Inst, 2, WriteMask, OperationType);
LoadOperand(In3, Inst, 3, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c += 2) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateSelect(In1[c>>1], In2[c], In3[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
case D3D11_1_SB_OPCODE_DRCP: {
CMask WriteMask = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask);
CompType OperationType = CompType::getF64();
OperandValue In, Out;
LoadOperand(In, Inst, 1, WriteMask, OperationType);
for (BYTE c = 0; c < DXBC::kWidth; c += 2) {
if (!WriteMask.IsSet(c)) continue;
Out[c] = m_pBuilder->CreateBinOp(Instruction::BinaryOps::FDiv, m_pOP->GetDoubleConst(1.0), In[c]);
}
StoreOperand(Out, Inst, 0, WriteMask, OperationType);
break;
}
case D3D11_SB_OPCODE_DTOF: ConvertFromDouble(CompType::getF32(), Inst); break;
case D3D11_1_SB_OPCODE_DTOI: ConvertFromDouble(CompType::getI32(), Inst); break;
case D3D11_1_SB_OPCODE_DTOU: ConvertFromDouble(CompType::getU32(), Inst); break;
case D3D11_SB_OPCODE_FTOD: ConvertToDouble (CompType::getF32(), Inst); break;
case D3D11_1_SB_OPCODE_ITOD: ConvertToDouble (CompType::getI32(), Inst); break;
case D3D11_1_SB_OPCODE_UTOD: ConvertToDouble (CompType::getU32(), Inst); break;
//
// Resource operations.
//
case D3D10_SB_OPCODE_SAMPLE:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_CLAMP_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::Sample;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpClamp = 4 + (bHasFeedback ? 1 : 0);
Value *Args[11];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
// Clamp.
Args[10] = m_pOP->GetFloatConst(0.f);
if (bHasFeedback) {
if (Inst.m_Operands[uOpClamp].m_Type != D3D10_SB_OPERAND_TYPE_IMMEDIATE32 ||
Inst.m_Operands[uOpClamp].m_Valuef[0] != 0.f) {
OperandValue InClamp;
LoadOperand(InClamp, Inst, uOpClamp, CMask::MakeXMask(), CompType::getF32());
Args[10] = InClamp[0];
}
}
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_SAMPLE_B:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_B_CLAMP_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::SampleBias;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpBias = 4 + (bHasFeedback ? 1 : 0);
const unsigned uOpClamp = uOpBias + 1;
Value *Args[12];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
OperandValue InBias;
LoadOperand(InBias, Inst, uOpBias, CMask::MakeXMask(), CompType::getF32());
Args[10] = InBias[0];
// Clamp.
Args[11] = m_pOP->GetFloatConst(0.f);
if (bHasFeedback) {
if (Inst.m_Operands[uOpClamp].m_Type != D3D10_SB_OPERAND_TYPE_IMMEDIATE32 ||
Inst.m_Operands[uOpClamp].m_Valuef[0] != 0.f) {
OperandValue InClamp;
LoadOperand(InClamp, Inst, uOpClamp, CMask::MakeXMask(), CompType::getF32());
Args[11] = InClamp[0];
}
}
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_SAMPLE_L:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_L_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::SampleLevel;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpLevel = 4 + (bHasFeedback ? 1 : 0);
Value *Args[11];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
OperandValue InLevel;
LoadOperand(InLevel, Inst, uOpLevel, CMask::MakeXMask(), CompType::getF32());
Args[10] = InLevel[0];
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_SAMPLE_D:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_D_CLAMP_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::SampleGrad;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpSRV = DXBC::GetResourceSlot(Inst.OpCode());
const unsigned uOpDx = 4 + (bHasFeedback ? 1 : 0);
const unsigned uOpDy = uOpDx + 1;
const unsigned uOpClamp = uOpDy + 1;
const DxilResource &R = GetSRVFromOperand(Inst, uOpSRV);
Value *Args[17];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
OperandValue InDx, InDy;
CMask DxDyMask = CMask::MakeFirstNCompMask(DXBC::GetNumResCoords(R.GetKind()));
LoadOperand(InDx, Inst, uOpDx, DxDyMask, CompType::getF32());
Args[10] = DxDyMask.IsSet(0) ? InDx[0] : m_pUnusedF32;
Args[11] = DxDyMask.IsSet(1) ? InDx[1] : m_pUnusedF32;
Args[12] = DxDyMask.IsSet(2) ? InDx[2] : m_pUnusedF32;
LoadOperand(InDy, Inst, uOpDy, DxDyMask, CompType::getF32());
Args[13] = DxDyMask.IsSet(0) ? InDy[0] : m_pUnusedF32;
Args[14] = DxDyMask.IsSet(1) ? InDy[1] : m_pUnusedF32;
Args[15] = DxDyMask.IsSet(2) ? InDy[2] : m_pUnusedF32;
// Clamp.
Args[16] = m_pOP->GetFloatConst(0.f);
if (bHasFeedback) {
if (Inst.m_Operands[uOpClamp].m_Type != D3D10_SB_OPERAND_TYPE_IMMEDIATE32 ||
Inst.m_Operands[uOpClamp].m_Valuef[0] != 0.f) {
OperandValue InClamp;
LoadOperand(InClamp, Inst, uOpClamp, CMask::MakeXMask(), CompType::getF32());
Args[16] = InClamp[0];
}
}
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_SAMPLE_C:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_C_CLAMP_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::SampleCmp;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpCmp = 4 + (bHasFeedback ? 1 : 0);
const unsigned uOpClamp = uOpCmp + 1;
Value *Args[12];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
OperandValue InCmp;
LoadOperand(InCmp, Inst, uOpCmp, CMask::MakeXMask(), CompType::getF32());
Args[10] = InCmp[0];
// Clamp.
Args[11] = m_pOP->GetFloatConst(0.f);
if (bHasFeedback) {
if (Inst.m_Operands[uOpClamp].m_Type != D3D10_SB_OPERAND_TYPE_IMMEDIATE32 ||
Inst.m_Operands[uOpClamp].m_Valuef[0] != 0.f) {
OperandValue InClamp;
LoadOperand(InClamp, Inst, uOpClamp, CMask::MakeXMask(), CompType::getF32());
Args[11] = InClamp[0];
}
}
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_SAMPLE_C_LZ:
case D3DWDDM1_3_SB_OPCODE_SAMPLE_C_LZ_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::SampleCmpLevelZero;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpCmp = 4 + (bHasFeedback ? 1 : 0);
Value *Args[11];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
OperandValue InCmp;
LoadOperand(InCmp, Inst, uOpCmp, CMask::MakeXMask(), CompType::getF32());
Args[10] = InCmp[0];
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_SB_OPCODE_LD:
case D3D10_SB_OPCODE_LD_MS:
case D3DWDDM1_3_SB_OPCODE_LD_FEEDBACK:
case D3DWDDM1_3_SB_OPCODE_LD_MS_FEEDBACK: {
bool bIsTexture2DMS = Inst.OpCode() == D3D10_SB_OPCODE_LD_MS ||
Inst.OpCode() == D3DWDDM1_3_SB_OPCODE_LD_MS_FEEDBACK;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpStatus = 1;
const unsigned uOpCoord = uOpStatus + (bHasFeedback ? 1 : 0);
const unsigned uOpRes = uOpCoord + 1;
const unsigned uOpSampleCount = uOpRes + 1;
DXASSERT_DXBC(Inst.m_Operands[uOpRes].m_Type == D3D10_SB_OPERAND_TYPE_RESOURCE);
// Resource.
OperandValue InSRV;
const DxilResource &R = LoadSRVOperand(InSRV, Inst, uOpRes, CMask::MakeXMask(), CompType::getInvalid());
// Return type.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
// Create Load call.
Value *pOpRet;
if (R.GetKind() != DxilResource::Kind::TypedBuffer) {
OP::OpCode OpCode = OP::OpCode::TextureLoad;
// Coordinates.
OperandValue InCoord;
CMask CoordMask = CMask::MakeFirstNCompMask(DXBC::GetNumResCoords(R.GetKind()));
// MIP level.
if (!bIsTexture2DMS) {
CoordMask.Set(3);
}
LoadOperand(InCoord, Inst, uOpCoord, CoordMask, CompType::getI32());
Value *Args[9];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InSRV[0]; // Texture SRV handle
if (!bIsTexture2DMS) {
Args[2] = InCoord[3]; // MIP level
} else {
BYTE Comp = Inst.m_Operands[uOpSampleCount].m_ComponentName;
OperandValue InSampleCount;
LoadOperand(InSampleCount, Inst, uOpSampleCount, CMask::MakeCompMask(Comp), CompType::getI32());
Args[2] = InSampleCount[Comp]; // Sample count
}
// Coordinates.
Args[3] = CoordMask.IsSet(0) ? InCoord[0] : m_pUnusedI32; // Coordinate 0
Args[4] = CoordMask.IsSet(1) ? InCoord[1] : m_pUnusedI32; // Coordinate 1
Args[5] = CoordMask.IsSet(2) ? InCoord[2] : m_pUnusedI32; // Coordinate 2
// Offsets.
CMask OffsetMask = CMask::MakeFirstNCompMask(DXBC::GetNumResOffsets(R.GetKind()));
Args[6] = OffsetMask.IsSet(0) ? m_pOP->GetU32Const(Inst.m_TexelOffset[0]) : m_pUnusedI32; // Offset 0
Args[7] = OffsetMask.IsSet(1) ? m_pOP->GetU32Const(Inst.m_TexelOffset[1]) : m_pUnusedI32; // Offset 1
Args[8] = OffsetMask.IsSet(2) ? m_pOP->GetU32Const(Inst.m_TexelOffset[2]) : m_pUnusedI32; // Offset 2
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
pOpRet = m_pBuilder->CreateCall(F, Args);
} else {
// R.GetKind() == DxilResource::TypedBuffer
OP::OpCode OpCode = OP::OpCode::BufferLoad;
Value *Args[4];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InSRV[0]; // Buffer SRV handle
Args[2] = GetCoordValue(Inst, uOpCoord); // Coord 0: in elements
Args[3] = m_pUnusedI32; // Coord 1: unused
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
pOpRet = m_pBuilder->CreateCall(F, Args);
}
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_LD_UAV_TYPED:
case D3DWDDM1_3_SB_OPCODE_LD_UAV_TYPED_FEEDBACK: {
bool bHasStatus = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpStatus = 1;
const unsigned uOpCoord = uOpStatus + (bHasStatus ? 1 : 0);
const unsigned uOpUAV = uOpCoord + 1;
DXASSERT_DXBC(Inst.m_Operands[uOpUAV].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
const DxilResource &R = m_pPR->GetUAV(m_UAVRangeMap[Inst.m_Operands[uOpUAV].m_Index[0].m_RegIndex]);
// Resource.
OperandValue InUAV;
LoadOperand(InUAV, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// Return type.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
// Create Load call.
Value *pOpRet;
if (R.GetKind() != DxilResource::Kind::TypedBuffer) {
OP::OpCode OpCode = OP::OpCode::TextureLoad;
// Coordinates.
OperandValue InCoord;
CMask CoordMask = CMask::MakeFirstNCompMask(DXBC::GetNumResCoords(R.GetKind()));
LoadOperand(InCoord, Inst, uOpCoord, CoordMask, CompType::getI32());
Value *Args[9];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWTexture UAV handle
Args[2] = m_pUnusedI32; // MIP level.
// Coordinates.
Args[3] = CoordMask.IsSet(0) ? InCoord[0] : m_pUnusedI32; // Coordinate 0
Args[4] = CoordMask.IsSet(1) ? InCoord[1] : m_pUnusedI32; // Coordinate 1
Args[5] = CoordMask.IsSet(2) ? InCoord[2] : m_pUnusedI32; // Coordinate 2
// Offsets.
Args[6] = m_pUnusedI32; // Offset 0
Args[7] = m_pUnusedI32; // Offset 1
Args[8] = m_pUnusedI32; // Offset 2
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
pOpRet = m_pBuilder->CreateCall(F, Args);
} else {
// R.GetKind() == DxilResource::TypedBuffer
OP::OpCode OpCode = OP::OpCode::BufferLoad;
Value *Args[4];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWBuffer UAV handle
Args[2] = GetCoordValue(Inst, uOpCoord); // Coord 0: in elements
Args[3] = m_pUnusedI32; // Coord 1: undef
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
pOpRet = m_pBuilder->CreateCall(F, Args);
}
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_STORE_UAV_TYPED: {
const unsigned uOpUAV = 0;
const unsigned uOpCoord = uOpUAV + 1;
const unsigned uOpValue = uOpCoord + 1;
DXASSERT_DXBC(Inst.m_Operands[uOpUAV].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
const DxilResource &R = m_pPR->GetUAV(m_UAVRangeMap[Inst.m_Operands[uOpUAV].m_Index[0].m_RegIndex]);
OperandValue InUAV, InCoord, InValue;
// Resource.
LoadOperand(InUAV, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// Coordinates.
CMask CoordMask = CMask::MakeFirstNCompMask(DXBC::GetNumResCoords(R.GetKind()));
LoadOperand(InCoord, Inst, uOpCoord, CoordMask, CompType::getI32());
// Value type.
CompType ValueType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpUAV].m_MinPrecision);
Type *pValueType = ValueType.GetLLVMType(m_Ctx);
// Value.
CMask ValueMask = CMask::FromDXBC(Inst.m_Operands[uOpUAV].m_WriteMask);
LoadOperand(InValue, Inst, uOpValue, ValueMask, ValueType);
// Create Store call.
if (R.GetKind() != DxilResource::Kind::TypedBuffer) {
OP::OpCode OpCode = OP::OpCode::TextureStore;
Value *Args[10];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWTexture UAV handle
// Coordinates.
Args[2] = CoordMask.IsSet(0) ? InCoord[0] : m_pUnusedI32; // Coordinate 0
Args[3] = CoordMask.IsSet(1) ? InCoord[1] : m_pUnusedI32; // Coordinate 1
Args[4] = CoordMask.IsSet(2) ? InCoord[2] : m_pUnusedI32; // Coordinate 2
// Value.
Args[5] = ValueMask.IsSet(0) ? InValue[0] : m_pUnusedI32; // Value 0
Args[6] = ValueMask.IsSet(1) ? InValue[1] : m_pUnusedI32; // Value 1
Args[7] = ValueMask.IsSet(2) ? InValue[2] : m_pUnusedI32; // Value 2
Args[8] = ValueMask.IsSet(3) ? InValue[3] : m_pUnusedI32; // Value 3
Args[9] = m_pOP->GetU8Const(ValueMask.ToByte()); // Value mask
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
MarkPrecise(m_pBuilder->CreateCall(F, Args));
} else {
// R.GetKind() == DxilResource::TypedBuffer
OP::OpCode OpCode = OP::OpCode::BufferStore;
Value *Args[9];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWBuffer UAV handle
Args[2] = InCoord[0]; // Coord 0: in elements
Args[3] = m_pUnusedI32; // Coord 1: unused
Args[4] = ValueMask.IsSet(0) ? InValue[0] : m_pUnusedI32; // Value 0
Args[5] = ValueMask.IsSet(1) ? InValue[1] : m_pUnusedI32; // Value 1
Args[6] = ValueMask.IsSet(2) ? InValue[2] : m_pUnusedI32; // Value 2
Args[7] = ValueMask.IsSet(3) ? InValue[3] : m_pUnusedI32; // Value 3
Args[8] = m_pOP->GetU8Const(ValueMask.ToByte()); // Value mask
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
MarkPrecise(m_pBuilder->CreateCall(F, Args));
}
break;
}
case D3D11_SB_OPCODE_LD_RAW:
case D3DWDDM1_3_SB_OPCODE_LD_RAW_FEEDBACK: {
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpStatus = 1;
const unsigned uOpByteOffset = uOpStatus + (bHasFeedback ? 1 : 0);
const unsigned uOpRes = uOpByteOffset + 1;
// Byte offset.
Value *pByteOffset = GetCoordValue(Inst, uOpByteOffset);
if (Inst.m_Operands[uOpRes].m_Type != D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY) {
OP::OpCode OpCode = OP::OpCode::BufferLoad;
OperandValue InRes, InByteOffset;
// Resource.
LoadOperand(InRes, Inst, uOpRes, CMask::MakeXMask(), CompType::getInvalid());
// Create Load call.
Value *Args[4];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // [RW]ByteAddressBuffer UAV/SRV handle
Args[2] = pByteOffset; // Coord 0: in bytes
Args[3] = m_pUnusedI32; // Coord 1: unused
CompType DstType = CompType::getI32();
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
} else {
const unsigned uOpTGSM = uOpRes;
CompType SrcType = CompType::getI32();
ConvertLoadTGSM(Inst, uOpTGSM, uOpOutput, SrcType, pByteOffset);
}
break;
}
case D3D11_SB_OPCODE_STORE_RAW: {
const unsigned uOpRes = 0;
const unsigned uOpByteOffset = uOpRes + 1;
const unsigned uOpValue = uOpByteOffset + 1;
// Byte offset.
Value *pByteOffset = GetCoordValue(Inst, uOpByteOffset);
if (Inst.m_Operands[uOpRes].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) {
const unsigned uOpUAV = uOpRes;
OP::OpCode OpCode = OP::OpCode::BufferStore;
DXASSERT_DXBC(Inst.m_Operands[uOpUAV].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
OperandValue InUAV, InByteOffset, InValue;
// Resource.
LoadOperand(InUAV, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// Value type.
CompType ValueType = CompType::getI32();
Type *pValueType = ValueType.GetLLVMType(m_Ctx);
// Value.
CMask ValueMask = CMask::FromDXBC(Inst.m_Operands[uOpUAV].m_WriteMask);
LoadOperand(InValue, Inst, uOpValue, ValueMask, ValueType);
// Create Store call.
Value *Args[9];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWByteAddressBuffer UAV handle
Args[2] = pByteOffset; // Coord 0: in bytes
Args[3] = m_pUnusedI32; // Coord 1: undef
Args[4] = ValueMask.IsSet(0) ? InValue[0] : m_pUnusedI32; // Value 0
Args[5] = ValueMask.IsSet(1) ? InValue[1] : m_pUnusedI32; // Value 1
Args[6] = ValueMask.IsSet(2) ? InValue[2] : m_pUnusedI32; // Value 2
Args[7] = ValueMask.IsSet(3) ? InValue[3] : m_pUnusedI32; // Value 3
Args[8] = m_pOP->GetU8Const(ValueMask.ToByte()); // Value mask
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
MarkPrecise(m_pBuilder->CreateCall(F, Args));
} else {
const unsigned uOpTGSM = uOpRes;
CompType ValueType = CompType::getI32();
ConvertStoreTGSM(Inst, uOpTGSM, uOpValue, ValueType, pByteOffset);
}
break;
}
case D3D11_SB_OPCODE_LD_STRUCTURED:
case D3DWDDM1_3_SB_OPCODE_LD_STRUCTURED_FEEDBACK: {
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpStatus = 1;
const unsigned uOpElementOffset = uOpStatus + (bHasFeedback ? 1 : 0);
const unsigned uOpStructByteOffset = uOpElementOffset + 1;
const unsigned uOpRes = uOpStructByteOffset + 1;
if (Inst.m_Operands[uOpRes].m_Type != D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY) {
OP::OpCode OpCode = OP::OpCode::BufferLoad;
OperandValue InRes, InElementOffset, InStructByteOffset;
// Resource.
LoadOperand(InRes, Inst, uOpRes, CMask::MakeXMask(), CompType::getInvalid());
// Create Load call.
Value *Args[4];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // [RW]ByteAddressBuffer UAV/SRV handle
Args[2] = GetCoordValue(Inst, uOpElementOffset); // Coord 1: element index
Args[3] = GetCoordValue(Inst, uOpStructByteOffset); // Coord 2: byte offset within the element
CompType DstType = CompType::getI32();
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
} else {
const unsigned uOpTGSM = uOpRes;
DXASSERT_DXBC(Inst.m_Operands[uOpTGSM].m_Type == D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY);
const TGSMEntry &R = m_TGSMMap[Inst.m_Operands[uOpTGSM].m_Index[0].m_RegIndex];
CompType SrcType = CompType::getF32();
// Byte offset.
Value *pByteOffset = GetByteOffset(Inst, uOpElementOffset, uOpStructByteOffset, R.Stride);
ConvertLoadTGSM(Inst, uOpTGSM, uOpOutput, SrcType, pByteOffset);
}
break;
}
case D3D11_SB_OPCODE_STORE_STRUCTURED: {
const unsigned uOpRes = 0;
const unsigned uOpElementOffset = uOpRes + 1;
const unsigned uOpStructByteOffset = uOpElementOffset + 1;
const unsigned uOpValue = uOpStructByteOffset + 1;
if (Inst.m_Operands[0].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) {
OP::OpCode OpCode = OP::OpCode::BufferStore;
const unsigned uOpUAV = uOpRes;
DXASSERT_DXBC(Inst.m_Operands[uOpUAV].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
OperandValue InUAV, InElementOffset, InStructByteOffset, InValue;
// Resource.
LoadOperand(InUAV, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// Value type.
CompType ValueType = CompType::getI32();
Type *pValueType = ValueType.GetLLVMType(m_Ctx);
// Value.
CMask ValueMask = CMask::FromDXBC(Inst.m_Operands[uOpUAV].m_WriteMask);
LoadOperand(InValue, Inst, uOpValue, ValueMask, ValueType);
// Create Store call.
Value *Args[9];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // RWByteAddressBuffer UAV handle
Args[2] = GetCoordValue(Inst, uOpElementOffset); // Coord 1: element index
Args[3] = GetCoordValue(Inst, uOpStructByteOffset); // Coord 2: byte offset within the element
Args[4] = ValueMask.IsSet(0) ? InValue[0] : m_pUnusedI32; // Value 0
Args[5] = ValueMask.IsSet(1) ? InValue[1] : m_pUnusedI32; // Value 1
Args[6] = ValueMask.IsSet(2) ? InValue[2] : m_pUnusedI32; // Value 2
Args[7] = ValueMask.IsSet(3) ? InValue[3] : m_pUnusedI32; // Value 3
Args[8] = m_pOP->GetU8Const(ValueMask.ToByte()); // Value mask
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
MarkPrecise(m_pBuilder->CreateCall(F, Args));
} else {
const unsigned uOpTGSM = uOpRes;
const TGSMEntry &R = m_TGSMMap[Inst.m_Operands[uOpTGSM].m_Index[0].m_RegIndex];
CompType ValueType = CompType::getF32();
// Byte offset.
Value *pByteOffset = GetByteOffset(Inst, uOpElementOffset, uOpStructByteOffset, R.Stride);
ConvertStoreTGSM(Inst, uOpTGSM, uOpValue, ValueType, pByteOffset);
}
break;
}
//
// Atomic operations.
//
case D3D11_SB_OPCODE_ATOMIC_AND:
case D3D11_SB_OPCODE_ATOMIC_OR:
case D3D11_SB_OPCODE_ATOMIC_XOR:
case D3D11_SB_OPCODE_ATOMIC_IADD:
case D3D11_SB_OPCODE_ATOMIC_IMAX:
case D3D11_SB_OPCODE_ATOMIC_IMIN:
case D3D11_SB_OPCODE_ATOMIC_UMAX:
case D3D11_SB_OPCODE_ATOMIC_UMIN:
case D3D11_SB_OPCODE_IMM_ATOMIC_IADD:
case D3D11_SB_OPCODE_IMM_ATOMIC_AND:
case D3D11_SB_OPCODE_IMM_ATOMIC_OR:
case D3D11_SB_OPCODE_IMM_ATOMIC_XOR:
case D3D11_SB_OPCODE_IMM_ATOMIC_EXCH:
case D3D11_SB_OPCODE_IMM_ATOMIC_IMAX:
case D3D11_SB_OPCODE_IMM_ATOMIC_IMIN:
case D3D11_SB_OPCODE_IMM_ATOMIC_UMAX:
case D3D11_SB_OPCODE_IMM_ATOMIC_UMIN:
case D3D11_SB_OPCODE_ATOMIC_CMP_STORE:
case D3D11_SB_OPCODE_IMM_ATOMIC_CMP_EXCH: {
bool bHasReturn = DXBC::AtomicBinOpHasReturn(Inst.OpCode());
bool bHasCompare = DXBC::IsCompareExchAtomicBinOp(Inst.OpCode());
const unsigned uOpRes = bHasReturn ? 1 : 0;
const unsigned uOpCoord = uOpRes + 1;
const unsigned uOpCompareValue = uOpCoord + (bHasCompare ? 1 : 0);
const unsigned uOpValue = uOpCompareValue + 1;
if (Inst.m_Operands[uOpRes].m_Type == D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW) {
const unsigned uOpUAV = uOpRes;
const DxilResource &R = m_pPR->GetUAV(m_UAVRangeMap[Inst.m_Operands[uOpUAV].m_Index[0].m_RegIndex]);
OperandValue InUAV, InCoord, InCompareValue, InValue;
// Resource.
LoadOperand(InUAV, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// Coordinates.
CMask CoordMask = CMask::MakeFirstNCompMask(DxilResource::GetNumCoords(R.GetKind()));
LoadOperand(InCoord, Inst, uOpCoord, CoordMask, CompType::getI32());
Value *pOffset[3];
pOffset[0] = InCoord[0];
pOffset[1] = CoordMask.IsSet(1) ? InCoord[1] : m_pUnusedI32;
pOffset[2] = CoordMask.IsSet(2) ? InCoord[2] : m_pUnusedI32;
// Value type.
CompType ValueType = CompType::getI32();
Type *pValueType = ValueType.GetLLVMType(m_Ctx);
// Compare value.
if (bHasCompare) {
LoadOperand(InCompareValue, Inst, uOpCompareValue, CMask::MakeXMask(), ValueType);
}
// Value.
LoadOperand(InValue, Inst, uOpValue, CMask::MakeXMask(), ValueType);
// Create atomic call.
Value *pOpRet;
if (!bHasCompare) {
OP::OpCode OpCode = OP::OpCode::AtomicBinOp;
Value *Args[7];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // Typed (uint/int) UAV handle
Args[2] = m_pOP->GetU32Const((unsigned)DXBC::GetAtomicBinOp(Inst.OpCode())); // Atomic operation kind.
Args[3] = pOffset[0]; // Offset 0, in elements
Args[4] = pOffset[1]; // Offset 1
Args[5] = pOffset[2]; // Offset 2
Args[6] = InValue[0]; // New value
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
pOpRet = m_pBuilder->CreateCall(F, Args);
} else {
OP::OpCode OpCode = OP::OpCode::AtomicCompareExchange;
Value *Args[7];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InUAV[0]; // Typed (uint/int) UAV handle
Args[2] = pOffset[0]; // Offset 0, in elements
Args[3] = pOffset[1]; // Offset 1
Args[4] = pOffset[2]; // Offset 2
Args[5] = InCompareValue[0]; // Compare value
Args[6] = InValue[0]; // New value
Function *F = m_pOP->GetOpFunc(OpCode, pValueType);
pOpRet = m_pBuilder->CreateCall(F, Args);
}
StoreBroadcastOutput(Inst, pOpRet, ValueType);
} else {
const unsigned uOpTGSM = uOpRes;
DXASSERT_DXBC(Inst.m_Operands[uOpTGSM].m_Type == D3D11_SB_OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY);
const TGSMEntry &R = m_TGSMMap[Inst.m_Operands[uOpTGSM].m_Index[0].m_RegIndex];
OperandValue InElementOffset, InCompareValue, InValue;
// Byte offset.
CMask ElementOffsetMask = CMask::MakeFirstNCompMask(R.Stride == 1 ? 1 : 2);
LoadOperand(InElementOffset, Inst, uOpCoord, ElementOffsetMask, CompType::getI32());
Value *pByteOffset = InElementOffset[0];
if (R.Stride > 1) { // Structured TGSM.
Value *pOffset2 = InElementOffset[1];
Value *pStride = m_pOP->GetU32Const(R.Stride);
pByteOffset = m_pBuilder->CreateAdd(m_pBuilder->CreateMul(pByteOffset, pStride), pOffset2);
}
// Value type.
CompType ValueType = CompType::getI32();
// Compare value.
if (bHasCompare) {
LoadOperand(InCompareValue, Inst, uOpCompareValue, CMask::MakeXMask(), ValueType);
}
CompType DstType = CompType::getI32();
Type *pDstType = Type::getInt32PtrTy(m_Ctx, DXIL::kTGSMAddrSpace);
// Value.
LoadOperand(InValue, Inst, uOpValue, CMask::MakeXMask(), ValueType);
// Create GEP.
Value *pGEPIndices[2] = { m_pOP->GetU32Const(0), pByteOffset };
Value *pPtrI8 = m_pBuilder->CreateGEP(R.pVar, pGEPIndices);
Value *pPtr = m_pBuilder->CreatePointerCast(pPtrI8, pDstType);
// Generate atomic instruction.
Value *pRetVal;
if (!bHasCompare) {
pRetVal = m_pBuilder->CreateAtomicRMW(DXBC::GetLlvmAtomicBinOp(Inst.OpCode()), pPtr, InValue[0], AtomicOrdering::Monotonic);
} else {
pRetVal = m_pBuilder->CreateAtomicCmpXchg(pPtr, InCompareValue[0], InValue[0], AtomicOrdering::Monotonic, AtomicOrdering::Monotonic);
Type *RetTypeFields[2] = { Type::getInt32Ty(m_Ctx), Type::getInt1Ty(m_Ctx) };
pRetVal = m_pBuilder->CreateExtractValue(pRetVal, 0);
}
StoreBroadcastOutput(Inst, pRetVal, ValueType);
}
break;
}
case D3D10_1_SB_OPCODE_GATHER4:
case D3DWDDM1_3_SB_OPCODE_GATHER4_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::TextureGather;
const unsigned uOpOutput = 0;
const unsigned uOpSRV = DXBC::GetResourceSlot(Inst.OpCode());
const unsigned uOpSampler = uOpSRV + 1;
const DxilResource &R = GetSRVFromOperand(Inst, uOpSRV);
Value *Args[10];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
// Offset.
bool bUseOffset = (R.GetKind() == DxilResource::Kind::Texture2D) ||
(R.GetKind() == DxilResource::Kind::Texture2DArray);
if (!bUseOffset) {
Args[7] = m_pUnusedI32;
Args[8] = m_pUnusedI32;
}
// Channel.
unsigned uChannel = Inst.m_Operands[uOpSampler].m_ComponentName;
Args[9] = m_pOP->GetU32Const(uChannel);
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_GATHER4_C:
case D3DWDDM1_3_SB_OPCODE_GATHER4_C_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::TextureGatherCmp;
const unsigned uOpOutput = 0;
const unsigned uOpSRV = DXBC::GetResourceSlot(Inst.OpCode());
const unsigned uOpSampler = uOpSRV + 1;
const unsigned uOpCmp = uOpSampler + 1;
const DxilResource &R = GetSRVFromOperand(Inst, uOpSRV);
Value *Args[11];
LoadCommonSampleInputs(Inst, &Args[0]);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
// Offset.
bool bUseOffset = (R.GetKind() == DxilResource::Kind::Texture2D) ||
(R.GetKind() == DxilResource::Kind::Texture2DArray);
if (!bUseOffset) {
Args[7] = m_pUnusedI32;
Args[8] = m_pUnusedI32;
}
// Channel.
unsigned uChannel = Inst.m_Operands[uOpSampler].m_ComponentName;
Args[9] = m_pOP->GetU32Const(uChannel);
// Comparison value.
OperandValue InCmp;
LoadOperand(InCmp, Inst, uOpCmp, CMask::MakeXMask(), CompType::getF32());
Args[10] = InCmp[0];
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_GATHER4_PO:
case D3DWDDM1_3_SB_OPCODE_GATHER4_PO_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::TextureGather;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpCoord = uOpOutput + 1 + (bHasFeedback ? 1 : 0);
const unsigned uOpOffset = uOpCoord + 1;
const unsigned uOpSRV = DXBC::GetResourceSlot(Inst.OpCode());
const unsigned uOpSampler = uOpSRV + 1;
const DxilResource &R = GetSRVFromOperand(Inst, uOpSRV);
Value *Args[10];
LoadCommonSampleInputs(Inst, &Args[0], false);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
// Programmable offset.
OperandValue InOffset;
LoadOperand(InOffset, Inst, uOpOffset, CMask::MakeFirstNCompMask(2), CompType::getI32());
Args[7] = InOffset[0];
Args[8] = InOffset[1];
// Channel.
unsigned uChannel = Inst.m_Operands[uOpSampler].m_ComponentName;
Args[9] = m_pOP->GetU32Const(uChannel);
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_GATHER4_PO_C:
case D3DWDDM1_3_SB_OPCODE_GATHER4_PO_C_FEEDBACK: {
OP::OpCode OpCode = OP::OpCode::TextureGatherCmp;
bool bHasFeedback = DXBC::HasFeedback(Inst.OpCode());
const unsigned uOpOutput = 0;
const unsigned uOpCoord = uOpOutput + 1 + (bHasFeedback ? 1 : 0);
const unsigned uOpOffset = uOpCoord + 1;
const unsigned uOpSRV = DXBC::GetResourceSlot(Inst.OpCode());
const unsigned uOpSampler = uOpSRV + 1;
const unsigned uOpCmp = uOpSampler + 1;
const DxilResource &R = GetSRVFromOperand(Inst, uOpSRV);
Value *Args[11];
LoadCommonSampleInputs(Inst, &Args[0], false);
// Other arguments.
Args[0] = m_pOP->GetU32Const((unsigned)OpCode);
// Programmable offset.
OperandValue InOffset;
LoadOperand(InOffset, Inst, uOpOffset, CMask::MakeFirstNCompMask(2), CompType::getI32());
Args[7] = InOffset[0];
Args[8] = InOffset[1];
// Channel.
unsigned uChannel = Inst.m_Operands[uOpSampler].m_ComponentName;
Args[9] = m_pOP->GetU32Const(uChannel);
// Comparison value.
OperandValue InCmp;
LoadOperand(InCmp, Inst, uOpCmp, CMask::MakeXMask(), CompType::getF32());
Args[10] = InCmp[0];
// Function call.
CompType DstType = DXBC::GetCompTypeWithMinPrec(R.GetCompType().GetBaseCompType(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreResRetOutputAndStatus(Inst, pOpRet, DstType);
break;
}
case D3D10_1_SB_OPCODE_SAMPLE_POS: {
const unsigned uOpOutput = 0;
const unsigned uOpResOrRast = uOpOutput + 1;
const unsigned uOpSample = uOpResOrRast + 1;
// Sample.
OperandValue InSample;
LoadOperand(InSample, Inst, uOpSample, CMask::MakeXMask(), CompType::getI32());
Value *pOpRet;
if (Inst.m_Operands[uOpResOrRast].m_Type == D3D10_SB_OPERAND_TYPE_RESOURCE) {
// Resource.
OP::OpCode OpCode = OP::OpCode::Texture2DMSGetSamplePosition;
OperandValue InRes;
LoadOperand(InRes, Inst, uOpResOrRast, CMask::MakeXMask(), CompType::getInvalid());
// Create SamplePosition call.
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // Resource handle
Args[2] = InSample[0]; // Sample index
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
pOpRet = m_pBuilder->CreateCall(F, Args);
} else {
// Render target.
OP::OpCode OpCode = OP::OpCode::RenderTargetGetSamplePosition;
// Create SamplePosition call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InSample[0]; // Sample index
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
pOpRet = m_pBuilder->CreateCall(F, Args);
}
StoreSamplePosOutput(Inst, pOpRet);
break;
}
case D3DWDDM1_3_SB_OPCODE_CHECK_ACCESS_FULLY_MAPPED: {
OP::OpCode OpCode = OP::OpCode::CheckAccessFullyMapped;
OperandValue InStatus;
LoadOperand(InStatus, Inst, 1, CMask::MakeXMask(), CompType::getI32());
// Create CheckAccessFullyMapped call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InStatus[Inst.m_Operands[0].m_ComponentName]; // Status
Function *F = m_pOP->GetOpFunc(OpCode, Type::getInt32Ty(m_Ctx));
Value *pRetValue = m_pBuilder->CreateCall(F, Args);
pRetValue = CastDxbcValue(pRetValue, CompType::getI1(), CompType::getI32());
StoreBroadcastOutput(Inst, pRetValue, CompType::getI32());
break;
}
case D3D10_SB_OPCODE_RESINFO: {
OP::OpCode OpCode = OP::OpCode::GetDimensions;
const unsigned uOpOutput = 0;
const unsigned uOpMipLevel = uOpOutput + 1;
const unsigned uOpRes = uOpMipLevel + 1;
// MipLevel.
OperandValue InMipLevel;
LoadOperand(InMipLevel, Inst, uOpMipLevel, CMask::MakeXMask(), CompType::getI32());
// Resource.
OperandValue InRes;
LoadOperand(InRes, Inst, uOpRes, CMask::MakeXMask(), CompType::getInvalid());
// Create GetDimensions call.
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // Resource handle
Args[2] = InMipLevel[0]; // MipLevel
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreGetDimensionsOutput(Inst, pOpRet);
break;
}
case D3D11_SB_OPCODE_BUFINFO: {
OP::OpCode OpCode = OP::OpCode::GetDimensions;
const unsigned uOpOutput = 0;
const unsigned uOpRes = uOpOutput + 1;
// Resource.
OperandValue InRes;
LoadOperand(InRes, Inst, uOpRes, CMask::MakeXMask(), CompType::getInvalid());
// Create GetDimensions call.
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // Resource handle
Args[2] = m_pUnusedI32; // MipLevel (undefined)
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
Value *pOpWidth = m_pBuilder->CreateExtractValue(pOpRet, 0);
// Store output.
StoreBroadcastOutput(Inst, pOpWidth, CompType::getI32());
break;
}
case D3D10_1_SB_OPCODE_SAMPLE_INFO: {
const unsigned uOpOutput = 0;
const unsigned uOpResOrRast = uOpOutput + 1;
bool bDxbcRetFloat = true;
if (Inst.m_InstructionReturnType == D3D10_SB_INSTRUCTION_RETURN_UINT) {
bDxbcRetFloat = false;
}
// Return type.
CompType DstType;
if (bDxbcRetFloat) {
DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
} else {
DstType = DXBC::GetCompTypeWithMinPrec(CompType::getI32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
}
Value *pRetValue;
if (Inst.m_Operands[uOpResOrRast].m_Type == D3D10_SB_OPERAND_TYPE_RESOURCE) {
// Resource.
OP::OpCode OpCode = OP::OpCode::GetDimensions;
OperandValue InRes;
LoadOperand(InRes, Inst, uOpResOrRast, CMask::MakeXMask(), CompType::getInvalid());
// Create GetDimensions call.
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // Resource handle
Args[2] = m_pOP->GetU32Const(0); // MipLevel
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
pRetValue = m_pBuilder->CreateExtractValue(pOpRet, 3);
} else {
OP::OpCode OpCode = OP::OpCode::RenderTargetGetSampleCount;
// Create SampleCount call.
Value *Args[1];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
pRetValue = m_pBuilder->CreateCall(F, Args);
}
Value *pZeroValue;
if (bDxbcRetFloat) {
pRetValue = m_pBuilder->CreateCast(Instruction::CastOps::UIToFP, pRetValue, Type::getFloatTy(m_Ctx));
pZeroValue = m_pOP->GetFloatConst(0.f);
} else {
pZeroValue = m_pOP->GetU32Const(0);
}
// Store output.
CMask OutputMask = CMask::FromDXBC(Inst.m_Operands[uOpOutput].m_WriteMask);
if (!OutputMask.IsZero()) {
OperandValue Out;
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!OutputMask.IsSet(c)) continue;
BYTE Comp = Inst.m_Operands[uOpResOrRast].m_Swizzle[c];
if (Comp == 0) {
Out[c] = pRetValue;
} else {
Out[c] = pZeroValue;
}
}
StoreOperand(Out, Inst, uOpOutput, OutputMask, DstType);
}
break;
}
case D3D11_SB_OPCODE_IMM_ATOMIC_ALLOC:
case D3D11_SB_OPCODE_IMM_ATOMIC_CONSUME: {
OP::OpCode OpCode = OP::OpCode::BufferUpdateCounter;
const unsigned uOpOutput = 0;
const unsigned uOpUAV = uOpOutput + 1;
bool bInc = Inst.OpCode() == D3D11_SB_OPCODE_IMM_ATOMIC_ALLOC;
// Resource.
OperandValue InRes;
LoadOperand(InRes, Inst, uOpUAV, CMask::MakeXMask(), CompType::getInvalid());
// SetHasCounter.
SetHasCounter(Inst, uOpUAV);
// Create BufferUpdateCounter call.
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InRes[0]; // Resource handle
Args[2] = m_pOP->GetI8Const(bInc ? 1 : -1); // Inc or Dec
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getI32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
Value *pOpRet = m_pBuilder->CreateCall(F, Args);
StoreBroadcastOutput(Inst, pOpRet, DstType);
break;
}
case D3D11_SB_OPCODE_SYNC: {
OP::OpCode OpCode = OP::OpCode::Barrier;
DXIL::BarrierMode BMode = DXBC::GetBarrierMode(Inst.m_SyncFlags.bThreadsInGroup,
Inst.m_SyncFlags.bUnorderedAccessViewMemoryGlobal,
Inst.m_SyncFlags.bUnorderedAccessViewMemoryGroup,
Inst.m_SyncFlags.bThreadGroupSharedMemory);
// Create BufferUpdateCounter call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = m_pOP->GetU32Const((unsigned)BMode); // Barrier mode
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
MarkPrecise(m_pBuilder->CreateCall(F, Args));
break;
}
//
// Control-flow operations.
//
case D3D10_SB_OPCODE_IF: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Create If-scope.
Scope &Scope = m_ScopeStack.Push(Scope::If, m_pBuilder->GetInsertBlock());
// Prepare condition.
Scope.pCond = LoadZNZCondition(Inst, 0);
// Create then-branch BB and set it as active.
Scope.pThenBB = BasicBlock::Create(m_Ctx, Twine("if") + Twine(Scope.NameIndex) + Twine(".then"), pFunction);
m_pBuilder->SetInsertPoint(Scope.pThenBB);
// Create endif BB.
Scope.pPostScopeBB = BasicBlock::Create(m_Ctx, Twine("if") + Twine(Scope.NameIndex) + Twine(".end"));
break;
}
case D3D10_SB_OPCODE_ELSE: {
// Get If-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::If, E_FAIL);
// Terminate then-branch.
CreateBranchIfNeeded(m_pBuilder->GetInsertBlock(), Scope.pPostScopeBB);
// Create else-branch BB and set it as active.
Scope.pElseBB = BasicBlock::Create(m_Ctx, Twine("if") + Twine(Scope.NameIndex) + Twine(".else"), pFunction);
m_pBuilder->SetInsertPoint(Scope.pElseBB);
break;
}
case D3D10_SB_OPCODE_ENDIF: {
// Get If-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::If, E_FAIL);
// Terminate else-branch.
CreateBranchIfNeeded(m_pBuilder->GetInsertBlock(), Scope.pPostScopeBB);
// Insert IF cbranch.
m_pBuilder->SetInsertPoint(Scope.pPreScopeBB);
if (Scope.pElseBB != nullptr) {
m_pBuilder->CreateCondBr(Scope.pCond, Scope.pThenBB, Scope.pElseBB);
} else {
m_pBuilder->CreateCondBr(Scope.pCond, Scope.pThenBB, Scope.pPostScopeBB);
}
// Set endif BB as active.
pFunction->getBasicBlockList().push_back(Scope.pPostScopeBB);
m_pBuilder->SetInsertPoint(Scope.pPostScopeBB);
// Finish If-scope.
m_ScopeStack.Pop();
break;
}
case D3D10_SB_OPCODE_LOOP: {
DXASSERT_DXBC(Inst.m_NumOperands == 0);
// Create Loop-scope.
Scope &Scope = m_ScopeStack.Push(Scope::Loop, m_pBuilder->GetInsertBlock());
// Create Loop and EndLoop BBs.
Scope.pLoopBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex), pFunction);
Scope.pPostScopeBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex) + Twine(".end"));
// Insert branch to Loop BB.
m_pBuilder->CreateBr(Scope.pLoopBB);
// Set Loop BB as active.
m_pBuilder->SetInsertPoint(Scope.pLoopBB);
break;
}
case D3D10_SB_OPCODE_ENDLOOP: {
// Get Loop-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::Loop, E_FAIL);
// Insert back-edge.
CreateBranchIfNeeded(m_pBuilder->GetInsertBlock(), Scope.pLoopBB);
// Set EndLoop BB as active.
pFunction->getBasicBlockList().push_back(Scope.pPostScopeBB);
m_pBuilder->SetInsertPoint(Scope.pPostScopeBB);
// Finish Loop-scope.
m_ScopeStack.Pop();
break;
}
case D3D10_SB_OPCODE_SWITCH: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Create Switch-scope.
Scope &Scope = m_ScopeStack.Push(Scope::Switch, m_pBuilder->GetInsertBlock());
// Prepare selector.
BYTE Comp = (BYTE)Inst.m_Operands[0].m_ComponentName;
CMask ReadMask = CMask::MakeCompMask(Comp);
OperandValue In1;
LoadOperand(In1, Inst, 0, ReadMask, CompType::getI32());
Scope.pSelector = In1[Comp];
// Create 1st casegroup BB and set it as active.
BasicBlock *pBB = BasicBlock::Create(m_Ctx, Twine("switch") + Twine(Scope.NameIndex) +
Twine(".casegroup") + Twine(Scope.CaseGroupIndex++), pFunction);
m_pBuilder->SetInsertPoint(pBB);
// Create endswitch BB.
Scope.pPostScopeBB = BasicBlock::Create(m_Ctx, Twine("switch") + Twine(Scope.NameIndex) + Twine(".end"));
break;
}
case D3D10_SB_OPCODE_CASE: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Get Switch-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::Switch, E_FAIL);
// Retrieve selector value.
const D3D10ShaderBinary::COperandBase &O = Inst.m_Operands[0];
DXASSERT_DXBC(O.m_Type == D3D10_SB_OPERAND_TYPE_IMMEDIATE32 && O.m_NumComponents == D3D10_SB_OPERAND_1_COMPONENT);
int CaseValue = O.m_Value[0];
// Remember case clause.
pair<unsigned, BasicBlock*> Case(CaseValue, m_pBuilder->GetInsertBlock());
Scope.SwitchCases.emplace_back(Case);
break;
}
case D3D10_SB_OPCODE_DEFAULT: {
DXASSERT_DXBC(Inst.m_NumOperands == 0);
// Get Switch-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::Switch, E_FAIL);
// Remember default clause.
Scope.pDefaultBB = m_pBuilder->GetInsertBlock();
break;
}
case D3D10_SB_OPCODE_ENDSWITCH: {
// Get Switch-scope.
Scope &Scope = m_ScopeStack.Top();
IFTBOOL(Scope.Kind == Scope::Switch, E_FAIL);
// Terminate case/default BB.
CreateBranchIfNeeded(m_pBuilder->GetInsertBlock(), Scope.pPostScopeBB);
// Insert switch branch.
m_pBuilder->SetInsertPoint(Scope.pPreScopeBB);
BasicBlock *pDefaultBB = Scope.pDefaultBB != nullptr ? Scope.pDefaultBB : Scope.pPostScopeBB;
SwitchInst *pSwitch = m_pBuilder->CreateSwitch(Scope.pSelector, pDefaultBB);
for (size_t i = 0; i < Scope.SwitchCases.size(); i++) {
auto &Case = Scope.SwitchCases[i];
if (Case.second == Scope.pDefaultBB) continue;
pSwitch->addCase(m_pBuilder->getInt32(Case.first), Case.second);
}
// Rename casegroups BBs.
SwitchInst *pSwI = dyn_cast<SwitchInst>(Scope.pPreScopeBB->getTerminator());
DXASSERT_NOMSG(pSwI != nullptr);
BasicBlock *pPrevCaseBB = nullptr;
unsigned CaseGroupIdx = 0;
for (auto itCase = pSwI->case_begin(), endCase = pSwI->case_end(); itCase != endCase; ++itCase) {
BasicBlock *pCaseBB = itCase.getCaseSuccessor();
if (pCaseBB != pPrevCaseBB) {
pCaseBB->setName(Twine("switch") + Twine(Scope.NameIndex) + Twine(".casegroup") + Twine(CaseGroupIdx++));
pPrevCaseBB = pCaseBB;
}
}
// Rename default BB.
if (Scope.pDefaultBB != nullptr) {
Scope.pDefaultBB->setName(Twine("switch") + Twine(Scope.NameIndex) + Twine(".default"));
}
// Set endswitch BB as active.
pFunction->getBasicBlockList().push_back(Scope.pPostScopeBB);
m_pBuilder->SetInsertPoint(Scope.pPostScopeBB);
// Finish Switch-scope.
m_ScopeStack.Pop();
break;
}
case D3D10_SB_OPCODE_CONTINUE: {
DXASSERT_DXBC(Inst.m_NumOperands == 0);
// Find parent scope.
Scope &Scope = m_ScopeStack.FindParentLoop();
// Create a new basic block.
BasicBlock *pNextBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex) +
Twine(".continue") + Twine(Scope.ContinueIndex++), pFunction);
// Insert branch to Loop BB.
m_pBuilder->CreateBr(Scope.pLoopBB);
// Set Next BB as active.
m_pBuilder->SetInsertPoint(pNextBB);
break;
}
case D3D10_SB_OPCODE_CONTINUEC: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Prepare condition.
Value *pCond = LoadZNZCondition(Inst, 0);
// Find parent scope.
Scope &Scope = m_ScopeStack.FindParentLoop();
// Create a new basic block.
BasicBlock *pNextBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex) +
Twine(".continuec") + Twine(Scope.ContinueIndex++), pFunction);
// Insert cbranch to Loop and Next BBs.
m_pBuilder->CreateCondBr(pCond, Scope.pLoopBB, pNextBB);
// Set Next BB as active.
m_pBuilder->SetInsertPoint(pNextBB);
break;
}
case D3D10_SB_OPCODE_BREAK: {
DXASSERT_DXBC(Inst.m_NumOperands == 0);
// Find parent scope.
Scope &Scope = m_ScopeStack.FindParentLoopOrSwitch();
// Create a new basic block.
BasicBlock *pNextBB;
if (Scope.Kind == Scope::Loop) {
pNextBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex) +
Twine(".break") + Twine(Scope.LoopBreakIndex++), pFunction);
} else {
if (m_ScopeStack.Top().Kind == Scope::Switch) {
pNextBB = BasicBlock::Create(m_Ctx, Twine("switch") + Twine(Scope.NameIndex) +
Twine(".tmpcasegroup") + Twine(Scope.CaseGroupIndex++), pFunction);
} else {
pNextBB = BasicBlock::Create(m_Ctx, Twine("switch") + Twine(Scope.NameIndex) +
Twine(".break") + Twine(Scope.SwitchBreakIndex++), pFunction);
}
}
// Insert branch to PostScope BB.
m_pBuilder->CreateBr(Scope.pPostScopeBB);
// Set Next BB as active.
m_pBuilder->SetInsertPoint(pNextBB);
break;
}
case D3D10_SB_OPCODE_BREAKC: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Prepare condition.
Value *pCond = LoadZNZCondition(Inst, 0);
// Find parent scope.
Scope &Scope = m_ScopeStack.FindParentLoopOrSwitch();
// Create a new basic block.
BasicBlock *pNextBB;
if (Scope.Kind == Scope::Loop) {
pNextBB = BasicBlock::Create(m_Ctx, Twine("loop") + Twine(Scope.NameIndex) +
Twine(".breakc") + Twine(Scope.LoopBreakIndex++), pFunction);
} else {
pNextBB = BasicBlock::Create(m_Ctx, Twine("switch") + Twine(Scope.NameIndex) +
Twine(".break") + Twine(Scope.SwitchBreakIndex++), pFunction);
}
// Insert cbranch to PostScope and Next BB.
m_pBuilder->CreateCondBr(pCond, Scope.pPostScopeBB, pNextBB);
// Set Next BB as active.
m_pBuilder->SetInsertPoint(pNextBB);
break;
}
case D3D10_SB_OPCODE_LABEL: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
DXASSERT_DXBC(Inst.m_Operands[0].m_Type == D3D10_SB_OPERAND_TYPE_LABEL ||
Inst.m_Operands[0].m_Type == D3D11_SB_OPERAND_TYPE_FUNCTION_BODY);
unsigned LabelIdx = Inst.m_Operands[0].m_Index[0].m_RegIndex;
const bool IsFb = Inst.m_Operands[0].m_Type == D3D11_SB_OPERAND_TYPE_FUNCTION_BODY;
auto &Label = IsFb ? m_InterfaceFunctionBodies[LabelIdx] : m_Labels[LabelIdx];
// Create entry basic block.
pFunction = Label.pFunc;
BasicBlock *pBB = BasicBlock::Create(m_Ctx, "entry", pFunction);
m_pBuilder->SetInsertPoint(pBB);
IFT(m_ScopeStack.IsEmpty());
(void)m_ScopeStack.Push(Scope::Function, nullptr);
InsertSM50ResourceHandles();
break;
}
case D3D10_SB_OPCODE_CALL: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
DXASSERT_DXBC(Inst.m_Operands[0].m_Type == D3D10_SB_OPERAND_TYPE_LABEL);
unsigned LabelIdx = Inst.m_Operands[0].m_Index[0].m_RegIndex;
auto &Label = m_Labels[LabelIdx];
// Create call instruction.
m_pBuilder->CreateCall(Label.pFunc);
break;
}
case D3D11_SB_OPCODE_INTERFACE_CALL: {
DXASSERT_DXBC(Inst.m_Operands[0].m_Type == D3D11_SB_OPERAND_TYPE_INTERFACE);
DXASSERT_DXBC(Inst.m_Operands[0].m_IndexDimension == D3D10_SB_OPERAND_INDEX_2D);
DXASSERT_DXBC(Inst.m_Operands[0].m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32);
unsigned BaseIfaceIdx = Inst.m_Operands[0].m_Index[0].m_RegIndex;
unsigned CallSiteIdx = Inst.m_InterfaceCall.FunctionIndex;
Interface& Iface = m_Interfaces[BaseIfaceIdx];
DXASSERT_DXBC(Inst.m_Operands[0].m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32 || Iface.bDynamicallyIndexed);
Value* pIfaceArrayIdx = LoadOperandIndex(Inst.m_Operands[0].m_Index[1], Inst.m_Operands[0].m_IndexType[1]);
Value* pIfaceIdx = m_pBuilder->CreateAdd(m_pOP->GetU32Const(BaseIfaceIdx), pIfaceArrayIdx);
// Load function table index
Value *pCBufferRetValue;
{
Value *Args[3];
Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy); // OpCode
Args[1] = CreateHandle(m_pInterfaceDataBuffer->GetClass(),
m_pInterfaceDataBuffer->GetID(),
m_pOP->GetU32Const(m_pInterfaceDataBuffer->GetLowerBound()),
false /*Nonuniform*/); // CBuffer handle
Args[2] = pIfaceIdx; // 0-based index into cbuffer instance
Function *pCBufferLoadFunc = m_pOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, Type::getInt32Ty(m_Ctx));
pCBufferRetValue = m_pBuilder->CreateCall(pCBufferLoadFunc, Args);
pCBufferRetValue = m_pBuilder->CreateExtractValue(pCBufferRetValue, 0);
}
// Switch on function table index
// Create endswitch BB.
BasicBlock* pPostSwitchBB = BasicBlock::Create(m_Ctx, Twine("fcall") + Twine(m_FcallCount) + Twine(".end"));
SwitchInst* pSwitch = m_pBuilder->CreateSwitch(pCBufferRetValue, pPostSwitchBB);
for (unsigned caseIdx = 0; caseIdx < Iface.Tables.size(); ++caseIdx) {
BasicBlock* pCaseBB = BasicBlock::Create(m_Ctx, Twine("fcall") + Twine(m_FcallCount) +
Twine(".case") + Twine(caseIdx), pFunction);
m_pBuilder->SetInsertPoint(pCaseBB);
unsigned fbIdx = m_FunctionTables[Iface.Tables[caseIdx]][CallSiteIdx];
m_pBuilder->CreateCall(m_InterfaceFunctionBodies[fbIdx].pFunc);
m_pBuilder->CreateBr(pPostSwitchBB);
pSwitch->addCase(m_pBuilder->getInt32(Iface.Tables[caseIdx]), pCaseBB);
}
pFunction->getBasicBlockList().push_back(pPostSwitchBB);
m_pBuilder->SetInsertPoint(pPostSwitchBB);
++m_FcallCount;
break;
}
case D3D10_SB_OPCODE_CALLC: {
DXASSERT_DXBC(Inst.m_NumOperands == 2);
DXASSERT_DXBC(Inst.m_Operands[1].m_Type == D3D10_SB_OPERAND_TYPE_LABEL);
unsigned LabelIdx = Inst.m_Operands[1].m_Index[0].m_RegIndex;
auto &Label = m_Labels[LabelIdx];
// Prepare condition.
Value *pCond = LoadZNZCondition(Inst, 0);
// Create call and after-call BBs.
Function *pCurFunc = m_pBuilder->GetInsertBlock()->getParent();
BasicBlock *pCallBB = BasicBlock::Create(m_Ctx, Twine("label") + Twine(LabelIdx) + Twine(".callc"), pCurFunc);
BasicBlock *pPostCallBB = BasicBlock::Create(m_Ctx, Twine("label") + Twine(LabelIdx) + Twine(".callc"), pCurFunc);
// Create cbranch for callc.
m_pBuilder->CreateCondBr(pCond, pCallBB, pPostCallBB);
m_pBuilder->SetInsertPoint(pCallBB);
// Create call.
m_pBuilder->CreateCall(Label.pFunc);
m_pBuilder->CreateBr(pPostCallBB);
m_pBuilder->SetInsertPoint(pPostCallBB);
break;
}
case D3D10_SB_OPCODE_RET: {
// Find parent scope.
Scope &FuncScope = m_ScopeStack.FindParentFunction();
if ((FuncScope.IsEntry() && !m_bPatchConstantPhase) || !FuncScope.IsEntry()) {
m_pBuilder->CreateRetVoid();
BasicBlock *pAfterRet = BasicBlock::Create(m_Ctx, Twine("afterret"), pFunction);
m_pBuilder->SetInsertPoint(pAfterRet);
} else {
// Hull shader control point phase fork/join.
Scope &HullScope = m_ScopeStack.FindParentHullLoop();
BasicBlock *pAfterRet = BasicBlock::Create(m_Ctx, Twine("afterret"), pFunction);
if (m_ScopeStack.Top().Kind == Scope::HullLoop) {
bMustCloseHullLoop = true;
m_pBuilder->CreateBr(pAfterRet);
} else {
// A non-terminating return.
m_pBuilder->CreateBr(HullScope.pPostScopeBB);
}
m_pBuilder->SetInsertPoint(pAfterRet);
}
break;
}
case D3D10_SB_OPCODE_RETC: {
DXASSERT_DXBC(Inst.m_NumOperands == 1);
// Find parent scope.
Scope &FuncScope = m_ScopeStack.FindParentFunction();
// Prepare condition.
Value *pCond = LoadZNZCondition(Inst, 0);
if ((FuncScope.IsEntry() && !m_bPatchConstantPhase) || !FuncScope.IsEntry()) {
// Create retc and after-retc BB.
BasicBlock *pRetc = BasicBlock::Create(m_Ctx, Twine("label") + Twine(FuncScope.LabelIdx) +
Twine(".callc") + Twine(FuncScope.CallIdx) +
Twine(".retc") + Twine(FuncScope.ReturnIndex), pFunction);
BasicBlock *pAfterRetc = BasicBlock::Create(m_Ctx, Twine("label") + Twine(FuncScope.LabelIdx) +
Twine(".callc") + Twine(FuncScope.CallIdx) +
Twine(".afterretc") + Twine(FuncScope.ReturnIndex++), pFunction);
// Create cbranch for retc.
m_pBuilder->CreateCondBr(pCond, pRetc, pAfterRetc);
// Emit return.
m_pBuilder->SetInsertPoint(pRetc);
m_pBuilder->CreateRetVoid();
m_pBuilder->SetInsertPoint(pAfterRetc);
} else {
// Hull shader control point phase fork/join.
Scope &HullScope = m_ScopeStack.FindParentHullLoop();
// Create HullLoopBreak and AfterHullLoopBreak BB.
BasicBlock *pAfterHullBreakc = BasicBlock::Create(m_Ctx, Twine("hullloop") + Twine(FuncScope.NameIndex) +
Twine(".retc") + Twine(FuncScope.HullLoopBreakIndex) +
Twine(".afterretc"), pFunction);
// Create cbranch for retc (HullLoopBreak).
m_pBuilder->CreateCondBr(pCond, HullScope.pPostScopeBB, pAfterHullBreakc);
m_pBuilder->SetInsertPoint(pAfterHullBreakc);
}
break;
}
case D3D11_SB_OPCODE_HS_CONTROL_POINT_PHASE:
IFTBOOL(m_ScopeStack.FindParentFunction().IsEntry(), E_FAIL);
m_bControlPointPhase = true;
break;
case D3D11_SB_OPCODE_HS_FORK_PHASE:
case D3D11_SB_OPCODE_HS_JOIN_PHASE: {
if (!m_bPatchConstantPhase) {
if (!m_bControlPointPhase) {
// This is a pass-through CP HS.
bPasshThroughCP = true;
}
m_bControlPointPhase = false;
m_bPatchConstantPhase = true;
// Start patch constant function.
(void)m_ScopeStack.Push(Scope::Function, nullptr);
m_ScopeStack.Top().SetEntry(true);
pFunction = Function::Create(pEntryFuncType, GlobalValue::LinkageTypes::ExternalLinkage,
"pc_main", m_pModule.get());
pFunction->setCallingConv(CallingConv::C);
m_pPR->SetPatchConstantFunction(pFunction);
BasicBlock *pBB = BasicBlock::Create(m_Ctx, "entry", pFunction);
m_pBuilder->SetInsertPoint(pBB);
// Swap active x-registers.
m_IndexableRegs.swap(m_PatchConstantIndexableRegs);
DeclareIndexableRegisters();
// Create HullLoop induction variable.
pHullLoopInductionVar = m_pBuilder->CreateAlloca(Type::getInt32Ty(m_Ctx), nullptr, "InstanceID");
InsertSM50ResourceHandles();
}
// Create HullLoop-scope.
Scope &Scope = m_ScopeStack.Push(Scope::HullLoop, m_pBuilder->GetInsertBlock());
// Initialize HullLoop induction variable.
Scope.pInductionVar = pHullLoopInductionVar;
m_pBuilder->CreateStore(m_pOP->GetI32Const(0), Scope.pInductionVar);
Scope.HullLoopTripCount = m_PatchConstantPhaseInstanceCounts[ForkJoinPhaseIndex];
ForkJoinPhaseIndex++;
// Create HullLoop and EndHullLoop BBs.
Scope.pHullLoopBB = BasicBlock::Create(m_Ctx, Twine("hullloop") + Twine(Scope.NameIndex), pFunction);
Scope.pPostScopeBB = BasicBlock::Create(m_Ctx, Twine("hullloop") + Twine(Scope.NameIndex) + Twine(".end"));
// Insert branch to Loop BB.
m_pBuilder->CreateBr(Scope.pLoopBB);
// Set Loop BB as active.
m_pBuilder->SetInsertPoint(Scope.pLoopBB);
break;
}
case D3D11_SB_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
case D3D11_SB_OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
break;
//
// Pixel shader.
//
case D3D10_1_SB_OPCODE_LOD: {
OP::OpCode OpCode = OP::OpCode::CalculateLOD;
const unsigned uOpOutput = 0;
const unsigned uOpCoord = uOpOutput + 1;
const unsigned uOpSRV = uOpCoord + 1;
const unsigned uOpSampler = uOpSRV + 1;
DXASSERT_DXBC(Inst.m_Operands[uOpSRV].m_Type == D3D10_SB_OPERAND_TYPE_RESOURCE);
OperandValue InCoord, InSRV, InSampler;
// Resource.
const DxilResource &R = LoadSRVOperand(InSRV, Inst, uOpSRV, CMask::MakeXMask(), CompType::getInvalid());
// Coordinates.
CMask CoordMask = CMask::MakeFirstNCompMask(DXBC::GetNumResOffsets(R.GetKind()));
LoadOperand(InCoord, Inst, uOpCoord, CoordMask, CompType::getF32());
// Sampler.
LoadOperand(InSampler, Inst, uOpSampler, CMask::MakeXMask(), CompType::getInvalid());
// Create CalculateLOD call.
Value *Args[7];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = InSRV[0]; // Resource handle
Args[2] = InSampler[0]; // Sampler handle
Args[3] = CoordMask.IsSet(0) ? InCoord[0] : m_pUnusedF32;
Args[4] = CoordMask.IsSet(1) ? InCoord[1] : m_pUnusedF32;
Args[5] = CoordMask.IsSet(2) ? InCoord[2] : m_pUnusedF32;
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
// Create unclamped CalculateLOD.
Args[6] = m_pOP->GetI1Const(false); // Unclamped
Value *pOpRetUnclamped = m_pBuilder->CreateCall(F, Args);
// Create clamped CalculateLOD.
Args[6] = m_pOP->GetI1Const(true); // Clamped
Value *pOpRetClamped = m_pBuilder->CreateCall(F, Args);
CMask OutputMask = CMask::FromDXBC(Inst.m_Operands[uOpOutput].m_WriteMask);
OperandValue Out;
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!OutputMask.IsSet(c)) continue;
// Respect swizzle: resource swizzle == return value swizzle.
BYTE Comp = Inst.m_Operands[uOpSRV].m_Swizzle[c];
switch (Comp) {
case 0: Out[c] = pOpRetClamped; break;
case 1: Out[c] = pOpRetUnclamped; break;
case 2: __fallthrough;
case 3: Out[c] = m_pOP->GetFloatConst(0.f); break;
default: DXASSERT_DXBC(false);
}
}
StoreOperand(Out, Inst, uOpOutput, OutputMask, DstType);
break;
}
case D3D10_SB_OPCODE_DISCARD: {
OP::OpCode OpCode = OP::OpCode::Discard;
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = LoadZNZCondition(Inst, 0); // Condition
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
MarkPrecise(m_pBuilder->CreateCall(F, Args));
break;
}
case D3D10_SB_OPCODE_DERIV_RTX: __fallthrough;
case D3D11_SB_OPCODE_DERIV_RTX_COARSE: ConvertUnary(OP::OpCode::DerivCoarseX, CompType::getF32(), Inst); break;
case D3D10_SB_OPCODE_DERIV_RTY: __fallthrough;
case D3D11_SB_OPCODE_DERIV_RTY_COARSE: ConvertUnary(OP::OpCode::DerivCoarseY, CompType::getF32(), Inst); break;
case D3D11_SB_OPCODE_DERIV_RTX_FINE: ConvertUnary(OP::OpCode::DerivFineX, CompType::getF32(), Inst); break;
case D3D11_SB_OPCODE_DERIV_RTY_FINE: ConvertUnary(OP::OpCode::DerivFineY, CompType::getF32(), Inst); break;
case D3D11_SB_OPCODE_EVAL_SNAPPED: {
OP::OpCode OpCode = OP::OpCode::EvalSnapped;
const unsigned uOpOutput = 0;
const unsigned uOpInput = uOpOutput + 1;
const unsigned uOpOffset = uOpInput + 1;
OperandValue InOffset;
CMask OutputMask = CMask::FromDXBC(Inst.m_Operands[uOpOutput].m_WriteMask);
LoadOperand(InOffset, Inst, uOpOffset, CMask::MakeFirstNCompMask(2), CompType::getI32());
const D3D10ShaderBinary::COperandBase &OpInput = Inst.m_Operands[uOpInput];
DXASSERT_NOMSG(Inst.m_Operands[uOpInput].m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
unsigned Register = OpInput.m_Index[0].m_RegIndex;
Value *pRowIndexValue = LoadOperandIndex(OpInput.m_Index[0], OpInput.m_IndexType[0]);
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *Args[6];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[4] = InOffset[0]; // Offset X
Args[5] = InOffset[1]; // Offset Y
OperandValue Out;
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!OutputMask.IsSet(c)) continue;
BYTE Comp = OpInput.m_Swizzle[c];
// Retrieve signature element.
const DxilSignatureElement *E = m_pInputSignature->GetElement(Register, Comp);
// Make row/col index relative within element.
Value *pRowIndexValueRel = m_pBuilder->CreateSub(pRowIndexValue, m_pOP->GetU32Const(E->GetStartRow()));
Args[1] = m_pOP->GetU32Const(E->GetID()); // Input signature element ID
Args[2] = pRowIndexValueRel; // Row, relative to the element
Args[3] = m_pOP->GetU8Const(Comp - E->GetStartCol()); // Col, relative to the element
Out[c] = m_pBuilder->CreateCall(F, Args);
}
StoreOperand(Out, Inst, uOpOutput, OutputMask, DstType);
break;
}
case D3D11_SB_OPCODE_EVAL_SAMPLE_INDEX: {
OP::OpCode OpCode = OP::OpCode::EvalSampleIndex;
const unsigned uOpOutput = 0;
const unsigned uOpInput = uOpOutput + 1;
const unsigned uOpSampleIndex = uOpInput + 1;
CMask OutputMask = CMask::FromDXBC(Inst.m_Operands[uOpOutput].m_WriteMask);
OperandValue InSampleIndex;
LoadOperand(InSampleIndex, Inst, uOpSampleIndex, CMask::MakeXMask(), CompType::getI32());
const D3D10ShaderBinary::COperandBase &OpInput = Inst.m_Operands[uOpInput];
DXASSERT_NOMSG(Inst.m_Operands[uOpInput].m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
unsigned Register = OpInput.m_Index[0].m_RegIndex;
Value *pRowIndexValue = LoadOperandIndex(OpInput.m_Index[0], OpInput.m_IndexType[0]);
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *Args[5];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[4] = InSampleIndex[0]; // Sample index
OperandValue Out;
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!OutputMask.IsSet(c)) continue;
BYTE Comp = OpInput.m_Swizzle[c];
// Retrieve signature element.
const DxilSignatureElement *E = m_pInputSignature->GetElement(Register, Comp);
// Make row/col index relative within element.
Value *pRowIndexValueRel = m_pBuilder->CreateSub(pRowIndexValue, m_pOP->GetU32Const(E->GetStartRow()));
Args[1] = m_pOP->GetU32Const(E->GetID()); // Input signature element ID
Args[2] = pRowIndexValueRel; // Row, relative to the element
Args[3] = m_pOP->GetU8Const(Comp - E->GetStartCol()); // Col, relative to the element
Out[c] = m_pBuilder->CreateCall(F, Args);
}
StoreOperand(Out, Inst, uOpOutput, OutputMask, DstType);
break;
}
case D3D11_SB_OPCODE_EVAL_CENTROID: {
OP::OpCode OpCode = OP::OpCode::EvalCentroid;
const unsigned uOpOutput = 0;
const unsigned uOpInput = uOpOutput + 1;
CMask OutputMask = CMask::FromDXBC(Inst.m_Operands[uOpOutput].m_WriteMask);
const D3D10ShaderBinary::COperandBase &OpInput = Inst.m_Operands[uOpInput];
DXASSERT_NOMSG(Inst.m_Operands[uOpInput].m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
unsigned Register = OpInput.m_Index[0].m_RegIndex;
Value *pRowIndexValue = LoadOperandIndex(OpInput.m_Index[0], OpInput.m_IndexType[0]);
CompType DstType = DXBC::GetCompTypeWithMinPrec(CompType::getF32(), Inst.m_Operands[uOpOutput].m_MinPrecision);
Type *pDstType = DstType.GetLLVMType(m_Ctx);
Function *F = m_pOP->GetOpFunc(OpCode, pDstType);
Value *Args[4];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
OperandValue Out;
for (BYTE c = 0; c < DXBC::kWidth; c++) {
if (!OutputMask.IsSet(c)) continue;
BYTE Comp = OpInput.m_Swizzle[c];
// Retrieve signature element.
const DxilSignatureElement *E = m_pInputSignature->GetElement(Register, Comp);
// Make row/col index relative within element.
Value *pRowIndexValueRel = m_pBuilder->CreateSub(pRowIndexValue, m_pOP->GetU32Const(E->GetStartRow()));
Args[1] = m_pOP->GetU32Const(E->GetID()); // Input signature element ID
Args[2] = pRowIndexValueRel; // Row, relative to the element
Args[3] = m_pOP->GetU8Const(Comp - E->GetStartCol()); // Col, relative to the element
Out[c] = m_pBuilder->CreateCall(F, Args);
}
StoreOperand(Out, Inst, uOpOutput, OutputMask, DstType);
break;
}
case D3D10_SB_OPCODE_EMIT:
case D3D11_SB_OPCODE_EMIT_STREAM: {
OP::OpCode OpCode = OP::OpCode::EmitStream;
BYTE StreamId = 0;
if (Inst.OpCode() == D3D11_SB_OPCODE_EMIT_STREAM) {
StreamId = (BYTE)Inst.m_Operands[0].m_Index[0].m_RegIndex;
}
// For GS with multiple streams, capture the values of output registers at the emit point.
if (m_pPR->HasMultipleOutputStreams()) {
EmitGSOutputRegisterStore(StreamId);
}
// Create EmitStream call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = m_pOP->GetU8Const(StreamId); // Stream ID
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
MarkPrecise(m_pBuilder->CreateCall(F, Args));
break;
}
case D3D10_SB_OPCODE_CUT:
case D3D11_SB_OPCODE_CUT_STREAM: {
OP::OpCode OpCode = OP::OpCode::CutStream;
BYTE StreamId = 0;
if (Inst.OpCode() == D3D11_SB_OPCODE_CUT_STREAM) {
StreamId = (BYTE)Inst.m_Operands[0].m_Index[0].m_RegIndex;
}
// Create CutStream call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = m_pOP->GetU8Const(StreamId); // Stream ID
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
MarkPrecise(m_pBuilder->CreateCall(F, Args));
break;
}
case D3D10_SB_OPCODE_EMITTHENCUT:
case D3D11_SB_OPCODE_EMITTHENCUT_STREAM: {
OP::OpCode OpCode = OP::OpCode::EmitThenCutStream;
BYTE StreamId = 0;
if (Inst.OpCode() == D3D11_SB_OPCODE_EMITTHENCUT_STREAM) {
StreamId = (BYTE)Inst.m_Operands[0].m_Index[0].m_RegIndex;
}
// For GS with multiple streams, capture the values of output registers at the emit point.
if (m_pPR->HasMultipleOutputStreams()) {
EmitGSOutputRegisterStore(StreamId);
}
// Create EmitThenCutStream call.
Value *Args[2];
Args[0] = m_pOP->GetU32Const((unsigned)OpCode); // OpCode
Args[1] = m_pOP->GetU8Const(StreamId); // Stream ID
Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));
MarkPrecise(m_pBuilder->CreateCall(F, Args));
break;
}
case D3D10_SB_OPCODE_NOP:
break;
default:
HandleUnknownInstruction(Inst);
break;
}
}
DXASSERT_NOMSG(m_ScopeStack.IsEmpty());
if (bPasshThroughCP) {
Function *Entry = m_pPR->GetEntryFunction();
m_pPR->SetEntryFunction(nullptr);
Entry->eraseFromParent();
m_pPR->SetEntryFunctionName("");
}
CleanupIndexableRegisterDecls(m_IndexableRegs);
CleanupIndexableRegisterDecls(m_PatchConstantIndexableRegs);
RemoveUnreachableBasicBlocks();
CleanupGEP();
}