void DxbcConverter::ConvertInstructions()

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();
}