void DxbcConverter::LoadOperand()

in projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp [5742:6442]


void DxbcConverter::LoadOperand(OperandValue &SrcVal,
                                D3D10ShaderBinary::CInstruction &Inst,
                                const unsigned OpIdx,
                                const CMask &Mask,
                                const CompType &ValueType) {
  D3D10ShaderBinary::COperandBase &O = Inst.m_Operands[OpIdx];

  switch (O.m_Type) {
  case D3D10_SB_OPERAND_TYPE_IMMEDIATE32:
    DXASSERT_DXBC(O.m_Modifier == D3D10_SB_OPERAND_MODIFIER_NONE);
    for (BYTE c = 0; c < DXBC::kWidth; c++) {
      if (!Mask.IsSet(c)) continue;

      bool bVec4 = O.m_NumComponents == D3D10_SB_OPERAND_4_COMPONENT;
      BYTE Comp =  bVec4 ? c : 0;

      switch (ValueType.GetKind()) {
      case CompType::Kind::F32:
        SrcVal[c] = LoadConstFloat(O.m_Valuef[Comp]);
        break;

      case CompType::Kind::F16:
        SrcVal[c] = CastDxbcValue(LoadConstFloat(O.m_Valuef[Comp]), CompType::Kind::F32, CompType::Kind::F16);
        break;

      case CompType::Kind::I32: __fallthrough;
      case CompType::Kind::U32:
        SrcVal[c] = m_pOP->GetU32Const(O.m_Value[Comp]);
        break;

      case CompType::Kind::I16: __fallthrough;
      case CompType::Kind::U16:
        SrcVal[c] = CastDxbcValue(m_pOP->GetU32Const(O.m_Value[Comp]), CompType::Kind::U32, CompType::Kind::I16);
        break;

      case CompType::Kind::I1:
        SrcVal[c] = CastDxbcValue(m_pOP->GetU32Const(O.m_Value[Comp]), CompType::Kind::U32, CompType::Kind::I1);
        break;

      default:
        DXASSERT_DXBC(false);
      }
    }
    break;

  case D3D10_SB_OPERAND_TYPE_IMMEDIATE64:
    DXASSERT_NOMSG(ValueType.GetKind() == CompType::Kind::F64);
    for (BYTE c = 0; c < DXBC::kWidth; c += 2) {
      if (!Mask.IsSet(c)) continue;

      SrcVal[c] = m_pOP->GetDoubleConst(O.m_Valued[c]);
    }
    break;

  case D3D10_SB_OPERAND_TYPE_TEMP: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
    unsigned Reg = O.m_Index[0].m_RegIndex;
    CompType DxbcValueType = DXBC::GetCompTypeFromMinPrec(O.m_MinPrecision, ValueType);
    if (DxbcValueType.IsBoolTy()) {
      DxbcValueType = CompType::getI32();
    }
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);

    if (DxbcValueType.GetKind() != CompType::Kind::F64)
    {
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();

        Value *Args[2];
        Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::TempRegLoad);    // OpCode
        Args[1] = m_pOP->GetU32Const(DXBC::GetRegIndex(Reg, Comp));         // Linearized register index
        Function *F = m_pOP->GetOpFunc(OP::OpCode::TempRegLoad, pDxbcValueType);
        Value *pValue = m_pBuilder->CreateCall(F, Args);

        pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
        pValue = ApplyOperandModifiers(pValue, O);

        OVH.SetValue(pValue);
      }
    } else {
      DXASSERT_DXBC(CMask::IsValidDoubleMask(Mask));
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();

        Value *pValue1, *pValue2;
        {
          Value *Args[2];
          Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::TempRegLoad);  // OpCode
          Args[1] = m_pOP->GetU32Const(DXBC::GetRegIndex(Reg, Comp));       // Linearized register index1
          Function *F = m_pOP->GetOpFunc(OP::OpCode::TempRegLoad, CompType::getU32().GetLLVMType(m_Ctx));
          pValue1 = m_pBuilder->CreateCall(F, Args);
          Args[1] = m_pOP->GetU32Const(DXBC::GetRegIndex(Reg, Comp+1));     // Linearized register index2
          pValue2 = m_pBuilder->CreateCall(F, Args);
        }

        Value *pValue;
        {
          Value *Args[3];
          Function *F = m_pOP->GetOpFunc(OP::OpCode::MakeDouble, pDxbcValueType);
          Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::MakeDouble);   // OpCode
          Args[1] = pValue1;                              // Lo part
          Args[2] = pValue2;                              // Hi part
          pValue = m_pBuilder->CreateCall(F, Args);
          pValue = ApplyOperandModifiers(pValue, O);
        }

        OVH.SetValue(pValue);
        OVH.Advance();
      }
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_INDEXABLE_TEMP: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_2D);
    DXASSERT_DXBC(O.m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32);
    unsigned Reg = O.m_Index[0].m_RegIndex;
    IndexableReg &IRRec = m_IndexableRegs[Reg];
    Value *pXRegIndex = LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]);
    Value *pRegIndex = m_pBuilder->CreateMul(pXRegIndex, m_pOP->GetI32Const(IRRec.NumComps));
    CompType DxbcValueType = DXBC::GetCompTypeFromMinPrec(O.m_MinPrecision, ValueType);
    if (DxbcValueType.IsBoolTy()) {
      DxbcValueType = CompType::getI32();
    }

    if (DxbcValueType.GetKind() != CompType::Kind::F64) {
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();
        Value *pValue = nullptr;

        // Create GEP.
        Value *pIndex = m_pBuilder->CreateAdd(pRegIndex, m_pOP->GetU32Const(Comp));
        Value *pGEPIndices[2] = { m_pOP->GetU32Const(0), pIndex };

        if (!DxbcValueType.HasMinPrec()) {
          Value *pBasePtr = m_IndexableRegs[Reg].pValue32;
          Value *pPtr = m_pBuilder->CreateGEP(pBasePtr, pGEPIndices);
          pValue = m_pBuilder->CreateAlignedLoad(pPtr, kRegCompAlignment);
          pValue = CastDxbcValue(pValue, CompType::getF32(), ValueType);
        } else {
          // Create GEP.
          Value *pBasePtr = m_IndexableRegs[Reg].pValue16;
          Value *pPtr = m_pBuilder->CreateGEP(pBasePtr, pGEPIndices);
          pValue = m_pBuilder->CreateAlignedLoad(pPtr, kRegCompAlignment/2);
          pValue = CastDxbcValue(pValue, CompType::getF16(), ValueType);
        }

        pValue = ApplyOperandModifiers(pValue, O);

        OVH.SetValue(pValue);
      }
    } else {
      // Double precision.
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();
        Value *pValue = nullptr;

        // Create GEP.
        Value *pIndex = m_pBuilder->CreateAdd(pRegIndex, m_pOP->GetU32Const(Comp));
        Value *pGEPIndices[1] = { pIndex };
        Value *pBasePtr = m_pBuilder->CreateBitCast(m_IndexableRegs[Reg].pValue32, Type::getDoublePtrTy(m_Ctx));
        Value *pPtr = m_pBuilder->CreateGEP(pBasePtr, pGEPIndices);
        pValue = m_pBuilder->CreateAlignedLoad(pPtr, kRegCompAlignment*2);

        pValue = ApplyOperandModifiers(pValue, O);

        OVH.SetValue(pValue);
        OVH.Advance();
        OVH.SetValue(pValue);
      }
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_INPUT:
  case D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT: {
    OP::OpCode OpCode = OP::OpCode::LoadInput;
    unsigned Register;        // Starting index of the register range.
    Value *pUnitIndexValue;   // Vertex/point index expression.
    Value *pRowIndexValue;    // Row index expression.

    switch (O.m_IndexDimension) {
    case D3D10_SB_OPERAND_INDEX_1D:
      Register        = O.m_Index[0].m_RegIndex;
      pUnitIndexValue = m_pUnusedI32;
      pRowIndexValue  = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);
      break;

    case D3D10_SB_OPERAND_INDEX_2D:
      // 2D input register index: <index1, input register index>.
      // index1: GS -- vertex index, DS -- input control point index.
      Register        = O.m_Index[1].m_RegIndex;
      pUnitIndexValue = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);
      pRowIndexValue  = LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]);
      break;

    default:
      DXASSERT(false, "there should no other index dimensions");
    }

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();
      // Retrieve signature element.
      const DxilSignatureElement *E = m_pInputSignature->GetElement(Register, Comp);
      CompType DxbcValueType = E->GetCompType();
      if (DxbcValueType.IsBoolTy()) {
        DxbcValueType = CompType::getI32();
      }
      Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);

      MutableArrayRef<Value *> Args;
      Value *Args1[1];
      Value *Args5[5];

      if (E->GetKind() == DXIL::SemanticKind::SampleIndex) {
        // Use SampleIndex intrinsic instead of LoadInput
        Args = Args1;
        OpCode = OP::OpCode::SampleIndex;
      } else {
        Args = Args5;
        // 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
        Args[4] = pUnitIndexValue;                            // Vertex/point index
      }

      Args[0] = m_pOP->GetU32Const((unsigned)OpCode);       // OpCode

      Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER: {
    // Upconvert operand to SM5.1.
    if (O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_2D) {
      O.m_IndexDimension = D3D10_SB_OPERAND_INDEX_3D;
      O.m_IndexType[2] = O.m_IndexType[1]; 
      O.m_Index[2] = O.m_Index[1];
      O.m_IndexType[1] = O.m_IndexType[0];
      O.m_Index[1] = O.m_Index[0];
    }

    // Retrieve cbuffer range ID and record.
    const DxilCBuffer* pR = m_pClassInstanceCBuffers;
    if (O.m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32) {
      unsigned RangeID = O.m_Index[0].m_RegIndex;
      unsigned RecIdx = m_CBufferRangeMap[RangeID];
      pR = &m_pPR->GetCBuffer(RecIdx);
    }

    const DxilCBuffer &R = *pR;

    // Setup cbuffer handle.
    Value *pHandle = GetCachedHandle(R);
    if (pHandle == nullptr) {
      // Create dynamic-index handle.
      pHandle = CreateHandle(R.GetClass(), R.GetID(), LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]), O.m_Nonuniform);
    }

    // Load values for unique components.
    Value *pRegIndexValue = LoadOperandIndex(O.m_Index[2], O.m_IndexType[2]);
    CompType DxbcValueType = ValueType.GetBaseCompType();
    if (DxbcValueType.IsBoolTy()) {
      DxbcValueType = CompType::getI32();
    }
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);

    DXASSERT_NOMSG(m_bLegacyCBufferLoad);
    Value *Args[3];
    Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::CBufferLoadLegacy);  // OpCode
    Args[1] = pHandle;                                                      // CBuffer handle
    Args[2] = pRegIndexValue;                                               // 0-based index into cbuffer instance
    Function *pCBufferLoadFunc = m_pOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, pDxbcValueType);

    Value *pCBufferRetValue = m_pBuilder->CreateCall(pCBufferLoadFunc, Args);

    if (ValueType.GetKind() != CompType::Kind::F64) {
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();

        Value *pValue = m_pBuilder->CreateExtractValue(pCBufferRetValue, Comp);
        pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
        pValue = ApplyOperandModifiers(pValue, O);

        OVH.SetValue(pValue);
      }
    } else {
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp() / 2;

        Value *pValue = m_pBuilder->CreateExtractValue(pCBufferRetValue, Comp);
        pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
        pValue = ApplyOperandModifiers(pValue, O);

        OVH.SetValue(pValue);
        OVH.Advance();
        OVH.SetValue(pValue);
      }
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_IMMEDIATE_CONSTANT_BUFFER: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
    Value *pRegIndex = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);

    if (ValueType.GetKind() != CompType::Kind::F64) {
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();

        Value *pValueIndex = m_pBuilder->CreateMul(pRegIndex, m_pOP->GetI32Const(DXBC::kWidth));
        pValueIndex = m_pBuilder->CreateAdd(pValueIndex, m_pOP->GetI32Const(Comp));
        // Create GEP.
        Value *pGEPIndices[2] = { m_pOP->GetU32Const(0), pValueIndex };
        Value *pPtr = m_pBuilder->CreateGEP(m_pIcbGV, pGEPIndices);
        LoadInst *pLoad = m_pBuilder->CreateLoad(pPtr);
        pLoad->setAlignment(kRegCompAlignment);
        Value *pValue = CastDxbcValue(pLoad, CompType::getF32(), ValueType);
        pValue = ApplyOperandModifiers(pValue, O);
      
        OVH.SetValue(pValue);
      }
    } else {
      // Double precision ICB.
      for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
        BYTE Comp = OVH.GetComp();

        Value *pValueIndex = m_pBuilder->CreateMul(pRegIndex, m_pOP->GetI32Const(DXBC::kWidth));
        pValueIndex = m_pBuilder->CreateAdd(pValueIndex, m_pOP->GetI32Const(Comp));
        // Bitcast pointer.
        Value *pPtrBase = m_pBuilder->CreateBitCast(m_pIcbGV, Type::getDoublePtrTy(m_Ctx));
        // Create GEP.
        Value *pGEPIndices[1] = { pValueIndex };
        Value *pPtr = m_pBuilder->CreateGEP(pPtrBase, pGEPIndices);
        LoadInst *pLoad = m_pBuilder->CreateLoad(pPtr);
        pLoad->setAlignment(kRegCompAlignment*2);
        Value *pValue = pLoad;
        pValue = ApplyOperandModifiers(pValue, O);
      
        OVH.SetValue(pValue);
        OVH.Advance();
        OVH.SetValue(pValue);
      }
    }
    break;
  }

  case D3D10_SB_OPERAND_TYPE_SAMPLER: {
    // Upconvert operand to SM5.1.
    if (O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D) {
      O.m_IndexDimension = D3D10_SB_OPERAND_INDEX_2D;
      O.m_IndexType[1] = O.m_IndexType[0];
      O.m_Index[1] = O.m_Index[0];
    }

    // Retrieve sampler range ID and record.
    const DxilSampler* pR = nullptr;
    if (O.m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32) {
      unsigned RangeID = O.m_Index[0].m_RegIndex;
      unsigned RecIdx = m_SamplerRangeMap[RangeID];
      pR = &m_pPR->GetSampler(RecIdx);
    }
    else {
      switch (Inst.OpCode()) {
      case D3D10_SB_OPCODE_SAMPLE_C:
      case D3D10_SB_OPCODE_SAMPLE_C_LZ:
      case D3DWDDM1_3_SB_OPCODE_SAMPLE_C_CLAMP_FEEDBACK:
      case D3DWDDM1_3_SB_OPCODE_SAMPLE_C_LZ_FEEDBACK:
      case D3D11_SB_OPCODE_GATHER4_PO_C:
      case D3DWDDM1_3_SB_OPCODE_GATHER4_PO_C_FEEDBACK:
        pR = m_pClassInstanceComparisonSamplers;
        break;
      default:
        pR = m_pClassInstanceSamplers;
        break;
      }
    }
    const DxilSampler &R = *pR;

    // Setup sampler handle.
    Value *pHandle = GetCachedHandle(R);
    if (pHandle == nullptr) {
      // Create dynamic-index handle.
      pHandle = CreateHandle(R.GetClass(), R.GetID(), LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]), O.m_Nonuniform);
    }

    // Replicate handle values.
    for (BYTE c = 0; c < DXBC::kWidth; c++) {
      if (Mask.IsSet(c))
        SrcVal[c] = pHandle;
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_RESOURCE: {
    (void)LoadSRVOperand(SrcVal, Inst, OpIdx, Mask, ValueType);
    break;
  }

  case D3D11_SB_OPERAND_TYPE_UNORDERED_ACCESS_VIEW: {
    // Upconvert operand to SM5.1.
    if (O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D) {
      DXASSERT_DXBC(O.m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32);
      O.m_IndexDimension = D3D10_SB_OPERAND_INDEX_2D;
      O.m_IndexType[1] = O.m_IndexType[0];
      O.m_Index[1] = O.m_Index[0];
    }

    // Retrieve UAV range ID and record.
    DXASSERT_DXBC(O.m_IndexType[0] == D3D10_SB_OPERAND_INDEX_IMMEDIATE32);
    unsigned RangeID = O.m_Index[0].m_RegIndex;
    unsigned RecIdx = m_UAVRangeMap[RangeID];
    const DxilResource &R = m_pPR->GetUAV(RecIdx);

    // Setup UAV handle.
    Value *pHandle = GetCachedHandle(R);
    if (pHandle == nullptr) {
      DXASSERT(IsSM51Plus(), "otherwise did not initialize handles on entry to main");
      // Create dynamic-index handle.
      pHandle = CreateHandle(R.GetClass(), R.GetID(), LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]), O.m_Nonuniform);
    }

    // Replicate handle values.
    for (BYTE c = 0; c < DXBC::kWidth; c++) {
      if (Mask.IsSet(c))
        SrcVal[c] = pHandle;
    }

    break;
  }

  case D3D10_SB_OPERAND_TYPE_RASTERIZER: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_0D);
    DXASSERT_DXBC(false);   // "rasterizer" register is not used in DXIL.
    break;
  }

  case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID:
  case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_GROUP_ID:
  case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP: {
    OP::OpCode OpCode;
    switch (O.m_Type) {
    case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID:           OpCode = OP::OpCode::ThreadId; break;
    case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_GROUP_ID:     OpCode = OP::OpCode::GroupId; break;
    case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP:  OpCode = OP::OpCode::ThreadIdInGroup; break;
    }
    CompType DxbcValueType = CompType::Kind::I32;
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);
    Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();

      Value *Args[2];
      Args[0] = m_pOP->GetU32Const((unsigned)OpCode);       // OpCode
      Args[1] = m_pOP->GetU32Const(Comp);         // Component: x,y,z
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }
    break;
  }

  case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED: {
    OP::OpCode OpCode = OP::OpCode::FlattenedThreadIdInGroup;
    CompType DxbcValueType = CompType::Kind::I32;
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);
    Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      Value *Args[1];
      Args[0] = m_pOP->GetU32Const((unsigned)OpCode);       // OpCode
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }
    break;
  }

  case D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D);
    unsigned Register     = O.m_Index[0].m_RegIndex;
    Value *pRowIndexValue = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();
      // Retrieve signature element.
      const DxilSignatureElement *E = m_pPatchConstantSignature->GetElement(Register, Comp);
      CompType DxbcValueType = E->GetCompType();
      if (DxbcValueType.IsBoolTy()) {
        DxbcValueType = CompType::getI32();
      }
      Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);

      // Make row/col index relative within element.
      Value *pRowIndexValueRel = m_pBuilder->CreateSub(pRowIndexValue, m_pOP->GetU32Const(E->GetStartRow()));

      Value *Args[4];
      Args[0] = m_pOP->GetU32Const((unsigned)OP::OpCode::LoadPatchConstant);  // OpCode
      Args[1] = m_pOP->GetU32Const(E->GetID());                               // Patch constant signature element ID
      Args[2] = pRowIndexValueRel;                                            // Row, relative to the element
      Args[3] = m_pOP->GetU8Const(Comp - E->GetStartCol());                   // Col, relative to the element
      Function *F = m_pOP->GetOpFunc(OP::OpCode::LoadPatchConstant, pDxbcValueType);
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }

    break;
  }

  case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT: {
    DXASSERT_DXBC(O.m_IndexDimension == D3D10_SB_OPERAND_INDEX_2D);
    OP::OpCode OpCode = OP::OpCode::LoadOutputControlPoint;
    unsigned Register      = O.m_Index[1].m_RegIndex;                           // Starting index of the register range.
    Value *pUnitIndexValue = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);  // Vertex/point index expression.
    Value *pRowIndexValue  = LoadOperandIndex(O.m_Index[1], O.m_IndexType[1]);  // Row index expression.

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();
      // Retrieve signature element.
      const DxilSignatureElement *E = m_pOutputSignature->GetElement(Register, Comp);
      CompType DxbcValueType = E->GetCompType();
      if (DxbcValueType.IsBoolTy()) {
        DxbcValueType = CompType::getI32();
      }
      Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);

      // Make row/col index relative within element.
      Value *pRowIndexValueRel = m_pBuilder->CreateSub(pRowIndexValue, m_pOP->GetU32Const(E->GetStartRow()));

      Value *Args[5];
      Args[0] = m_pOP->GetU32Const((unsigned)OpCode);         // OpCode
      Args[1] = m_pOP->GetU32Const(E->GetID());               // Output signature element ID
      Args[2] = pRowIndexValueRel;                            // Row, relative to the element
      Args[3] = m_pOP->GetU8Const(Comp - E->GetStartCol());   // Col, relative to the element
      Args[4] = pUnitIndexValue;                              // Vertex/point index
      Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }

    break;
  }

  case D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT: {
    OP::OpCode OpCode = OP::OpCode::DomainLocation;
    CompType DxbcValueType = CompType::Kind::F32;
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);
    Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();
      Value *Args[2];
      Args[0] = m_pOP->GetU32Const((unsigned)OpCode);   // OpCode
      Args[1] = m_pOP->GetU8Const(Comp);                // Component
      Value *pValue = m_pBuilder->CreateCall(F, Args);

      pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }

    break;
  }

  case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID:
  case D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID:
  case D3D11_SB_OPERAND_TYPE_INPUT_GS_INSTANCE_ID:
  case D3D11_SB_OPERAND_TYPE_INPUT_COVERAGE_MASK:
  case D3D11_SB_OPERAND_TYPE_INNER_COVERAGE: {
    OP::OpCode OpCode;
    switch (O.m_Type) {
    case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID: OpCode = OP::OpCode::OutputControlPointID; break;
    case D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID:       OpCode = OP::OpCode::PrimitiveID; break;
    case D3D11_SB_OPERAND_TYPE_INPUT_GS_INSTANCE_ID:    OpCode = OP::OpCode::GSInstanceID; break;
    case D3D11_SB_OPERAND_TYPE_INPUT_COVERAGE_MASK:     OpCode = OP::OpCode::Coverage; break;
    case D3D11_SB_OPERAND_TYPE_INNER_COVERAGE:          OpCode = OP::OpCode::InnerCoverage; break;
    }
    CompType DxbcValueType = CompType::Kind::I32;
    Type *pDxbcValueType = DxbcValueType.GetLLVMType(m_Ctx);
    Function *F = m_pOP->GetOpFunc(OpCode, pDxbcValueType);

    Value *Args[1];
    Args[0] = m_pOP->GetU32Const((unsigned)OpCode);   // OpCode
    Value *pValue = m_pBuilder->CreateCall(F, Args);

    pValue = CastDxbcValue(pValue, DxbcValueType, ValueType);
    pValue = ApplyOperandModifiers(pValue, O);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      OVH.SetValue(pValue);
    }
    break;
  }

  case D3D11_SB_OPERAND_TYPE_CYCLE_COUNTER: {
    OP::OpCode OpCode = OP::OpCode::CycleCounterLegacy;
    Function *F = m_pOP->GetOpFunc(OpCode, Type::getVoidTy(m_Ctx));

    Value *Args[1];
    Args[0] = m_pOP->GetU32Const((unsigned)OpCode);   // OpCode
    Value *pValue = m_pBuilder->CreateCall(F, Args);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE c = OVH.GetComp();
      switch (c) {
      case 0: {
        Value *pLo32 = m_pBuilder->CreateExtractValue(pValue, 0);
        pLo32 = CastDxbcValue(pLo32, CompType::Kind::I32, ValueType);
        OVH.SetValue(pLo32);
        break;
      }
      case 1: {
        Value *pHi32 = m_pBuilder->CreateExtractValue(pValue, 1);
        pHi32 = CastDxbcValue(pHi32, CompType::Kind::I32, ValueType);
        OVH.SetValue(pHi32);
        break;
      }
      default:
        OVH.SetValue(m_pOP->GetU32Const(0));
      }
    }
    break;
  }

  case D3D11_SB_OPERAND_TYPE_INPUT_FORK_INSTANCE_ID:
  case D3D11_SB_OPERAND_TYPE_INPUT_JOIN_INSTANCE_ID: {
    Scope &HullScope = m_ScopeStack.FindParentHullLoop();
    Value *pValue = m_pBuilder->CreateLoad(HullScope.pInductionVar);
    pValue = ApplyOperandModifiers(pValue, O);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      OVH.SetValue(pValue);
    }

    break;
  }

  case D3D11_SB_OPERAND_TYPE_THIS_POINTER: {
    Value *pIfaceIdx = LoadOperandIndex(O.m_Index[0], O.m_IndexType[0]);
    // The CBuffer layout here is a UINT for the interface class type selection, then 3 UINTs padding, per interface.
    // After that, there's another 4 UINTs per interface which defines the "this" pointer data.
    // Note, legacy CBuffer loads address their data in number of 4-float constants, not bytes or single elements.
    // Since the "this" data comes after 4 UINTs per interface, adjust the CB offset just by the number of interfaces.
    Value* pCBOffset = m_pBuilder->CreateAdd(m_pOP->GetU32Const(m_NumIfaces), pIfaceIdx);

    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] = pCBOffset;                                                    // 0-based index into cbuffer instance
    Function *pCBufferLoadFunc = m_pOP->GetOpFunc(OP::OpCode::CBufferLoadLegacy, Type::getInt32Ty(m_Ctx));
    Value* pCBufferRetValue = m_pBuilder->CreateCall(pCBufferLoadFunc, Args);

    for (OperandValueHelper OVH(SrcVal, Mask, O); !OVH.IsDone(); OVH.Advance()) {
      BYTE Comp = OVH.GetComp();

      Value *pValue = m_pBuilder->CreateExtractValue(pCBufferRetValue, Comp);
      pValue = CastDxbcValue(pValue, CompType::Kind::I32, ValueType);
      pValue = ApplyOperandModifiers(pValue, O);

      OVH.SetValue(pValue);
    }
    break;
  }

  default:
    DXASSERT_ARGS(false, "Operand type %u is not yet implemented", O.m_Type);
  }
}