void DxbcConverter::AnalyzeShader()

in projects/dxilconv/lib/DxbcConverter/DxbcConverter.cpp [1171:1900]


void DxbcConverter::AnalyzeShader(D3D10ShaderBinary::CShaderCodeParser &Parser) {
  // Parse shader model.
  D3D10_SB_TOKENIZED_PROGRAM_TYPE ShaderType = Parser.ShaderType();
  m_DxbcMajor = Parser.ShaderMajorVersion();
  m_DxbcMinor = Parser.ShaderMinorVersion();
  ShaderModel::Kind ShaderKind = DXBC::GetShaderModelKind(ShaderType);
  // The converter always promotes the shader version to 6.0.
  m_pSM = ShaderModel::Get(ShaderKind, 6, 0);
  m_pPR->SetShaderModel(m_pSM);

  // By default refactoring is disallowed, unless we encounter
  // dcl_globalflags allowRefactoring
  m_pPR->m_ShaderFlags.SetDisableMathRefactoring(true);
  // By default, all resources are assumed bound for SM5.0 shaders,
  // unless we encounter interface declarations
  m_pPR->m_ShaderFlags.SetAllResourcesBound(true);

  // Setup signature helpers.
  m_pInputSignature.reset(new SignatureHelper(m_pSM->GetKind(), DXIL::SignatureKind::Input));
  m_pOutputSignature.reset(new SignatureHelper(m_pSM->GetKind(), DXIL::SignatureKind::Output));
  m_pPatchConstantSignature.reset(new SignatureHelper(m_pSM->GetKind(), DXIL::SignatureKind::PatchConstOrPrim));

  // Collect:
  //   1. Declarations
  //   2. Labels
  // Declare:
  //   1. Global symbols for resources/samplers.
  //   2. Their types.
  BYTE CurrentOutputStream = 0;
  unsigned MaxOutputRegister = 0;
  m_bControlPointPhase = false;
  bool bPatchConstantPhase = false;
  D3D10ShaderBinary::CInstruction Inst;
  while(!Parser.EndOfShader()) {
    Parser.ParseInstruction(&Inst);

    switch (Inst.OpCode()) {
    case D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER: {
      // Record this cbuffer declaration in DxilModule.
      unsigned ID = m_pPR->AddCBuffer(unique_ptr<DxilCBuffer>(new DxilCBuffer));
      DxilCBuffer &R = m_pPR->GetCBuffer(ID);  // R == record
      R.SetID(ID);
      // Root signature bindings.
      unsigned RangeID = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      unsigned CBufferSize = Inst.m_ConstantBufferDecl.Size * DXBC::kWidth * 4;
      unsigned LB, RangeSize;
      switch (Inst.m_Operands[0].m_IndexDimension) {
      case D3D10_SB_OPERAND_INDEX_2D: // SM 5.0-
        LB = RangeID;
        RangeSize = 1;
        break;
      case D3D10_SB_OPERAND_INDEX_3D: // SM 5.1
        LB = Inst.m_Operands[0].m_Index[1].m_RegIndex;
        RangeSize = Inst.m_Operands[0].m_Index[2].m_RegIndex != UINT_MAX ? Inst.m_Operands[0].m_Index[2].m_RegIndex - LB + 1 : UINT_MAX;
        break;
      default:
        DXASSERT_DXBC(false);
        IFTARG(NULL);
      }
      R.SetLowerBound(LB);
      R.SetRangeSize(RangeSize);
      R.SetSpaceID(Inst.m_ConstantBufferDecl.Space);
      // Declare global variable.
      R.SetGlobalName(SynthesizeResGVName("CB", R.GetID()));
      StructType *pResType = GetStructResElemType(CBufferSize);
      R.SetGlobalSymbol(DeclareUndefPtr(pResType, DXIL::kCBufferAddrSpace));

      // CBuffer-specific state.
      R.SetSize(CBufferSize);
      //R.SetImmediateIndexed(Inst.m_ConstantBufferDecl.AccessPattern == D3D10_SB_CONSTANT_BUFFER_IMMEDIATE_INDEXED);

      // Record shader register/rangeID mapping for upcoming instruction conversion.
      DXASSERT(m_CBufferRangeMap.find(RangeID) == m_CBufferRangeMap.end(), "otherwise overlapping declarations");
      m_CBufferRangeMap[RangeID] = R.GetID();
      break;
    }

    case D3D10_SB_OPCODE_DCL_SAMPLER: {
      // Record this sampler declaration in DxilModule.
      unsigned ID = m_pPR->AddSampler(unique_ptr<DxilSampler>(new DxilSampler));
      DxilSampler &R = m_pPR->GetSampler(ID);  // R == record
      R.SetID(ID);
      // Root signature bindings.
      unsigned RangeID = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      unsigned LB, RangeSize;
      switch (Inst.m_Operands[0].m_IndexDimension) {
      case D3D10_SB_OPERAND_INDEX_1D: // SM 5.0-
        LB = RangeID;
        RangeSize = 1;
        break;
      case D3D10_SB_OPERAND_INDEX_3D: // SM 5.1
        LB = Inst.m_Operands[0].m_Index[1].m_RegIndex;
        RangeSize = Inst.m_Operands[0].m_Index[2].m_RegIndex != UINT_MAX ? Inst.m_Operands[0].m_Index[2].m_RegIndex - LB + 1 : UINT_MAX;
        break;
      default:
        DXASSERT_DXBC(false);
        IFTARG(NULL);
      }
      R.SetLowerBound(LB);
      R.SetRangeSize(RangeSize);
      R.SetSpaceID(Inst.m_SamplerDecl.Space);
      // Declare global variable.
      R.SetGlobalName(SynthesizeResGVName("S", R.GetID()));
      string ResTypeName("dx.types.Sampler");
      StructType *pResType = m_pModule->getTypeByName(ResTypeName);
      if (pResType == nullptr) {
        pResType = StructType::create(m_Ctx, ResTypeName);
      }
      R.SetGlobalSymbol(DeclareUndefPtr(pResType, DXIL::kDeviceMemoryAddrSpace));

      // Sampler-specific state.
      R.SetSamplerKind(DXBC::GetSamplerKind(Inst.m_SamplerDecl.SamplerMode));

      // Record shader register/rangeID mapping for upcoming instruction conversion.
      DXASSERT(m_SamplerRangeMap.find(RangeID) == m_SamplerRangeMap.end(), "otherwise overlapping declarations");
      m_SamplerRangeMap[RangeID] = R.GetID();
      break;
    }

    case D3D10_SB_OPCODE_DCL_RESOURCE:
    case D3D11_SB_OPCODE_DCL_RESOURCE_RAW:
    case D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED: {
      // Record this SRV declaration in DxilModule.
      unsigned ID = m_pPR->AddSRV(unique_ptr<DxilResource>(new DxilResource));
      DxilResource &R = m_pPR->GetSRV(ID);  // R == record
      R.SetID(ID);
      R.SetRW(false);
      // Root signature bindings.
      unsigned RangeID = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      unsigned LB, RangeSize;
      if (IsSM51Plus()) {
        LB = Inst.m_Operands[0].m_Index[1].m_RegIndex;
        RangeSize = Inst.m_Operands[0].m_Index[2].m_RegIndex != UINT_MAX ? Inst.m_Operands[0].m_Index[2].m_RegIndex - LB + 1 : UINT_MAX;
      } else {
        LB = RangeID;
        RangeSize = 1;
      }
      R.SetLowerBound(LB);
      R.SetRangeSize(RangeSize);

      // Resource-specific state.
      StructType *pResType = nullptr;
      switch (Inst.OpCode()) {
      case D3D10_SB_OPCODE_DCL_RESOURCE: {
        R.SetSpaceID(Inst.m_ResourceDecl.Space);
        R.SetKind(DXBC::GetResourceKind(Inst.m_ResourceDecl.Dimension));
        const unsigned kTypedBufferElementSizeInBytes = 4;
        R.SetElementStride(kTypedBufferElementSizeInBytes);
        R.SetSampleCount(Inst.m_ResourceDecl.SampleCount);
        CompType DeclCT = DXBC::GetDeclResCompType(Inst.m_ResourceDecl.ReturnType[0]);
        if (DeclCT.IsInvalid()) DeclCT = CompType::getU32();
        R.SetCompType(DeclCT);
        pResType = GetTypedResElemType(DeclCT);
        break;
      }
      case D3D11_SB_OPCODE_DCL_RESOURCE_RAW: {
        R.SetSpaceID(Inst.m_RawSRVDecl.Space);
        R.SetKind(DxilResource::Kind::RawBuffer);
        const unsigned kRawBufferElementSizeInBytes = 1;
        R.SetElementStride(kRawBufferElementSizeInBytes);
        pResType = GetTypedResElemType(CompType::getU32());
        break;
      }
      case D3D11_SB_OPCODE_DCL_RESOURCE_STRUCTURED: {
        R.SetSpaceID(Inst.m_StructuredSRVDecl.Space);
        R.SetKind(DxilResource::Kind::StructuredBuffer);
        unsigned Stride = Inst.m_StructuredSRVDecl.ByteStride;
        R.SetElementStride(Stride);
        pResType = GetStructResElemType(Stride);
        break;
      }
      default: ;
      }

      // Declare global variable.
      R.SetGlobalName(SynthesizeResGVName("T", R.GetID()));
      R.SetGlobalSymbol(DeclareUndefPtr(pResType, DXIL::kDeviceMemoryAddrSpace));

      // Record shader register/rangeID mapping for upcoming instruction conversion.
      DXASSERT(m_SRVRangeMap.find(RangeID) == m_SRVRangeMap.end(), "otherwise overlapping declarations");
      m_SRVRangeMap[RangeID] = R.GetID();
      break;
    }

    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: {
      // Record this UAV declaration in DxilModule.
      unsigned ID = m_pPR->AddUAV(unique_ptr<DxilResource>(new DxilResource));
      DxilResource &R = m_pPR->GetUAV(ID);  // R == record
      R.SetID(ID);
      R.SetRW(true);
      // Root signature bindings.
      unsigned RangeID = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      unsigned LB, RangeSize;
      if (IsSM51Plus()) {
        LB = Inst.m_Operands[0].m_Index[1].m_RegIndex;
        RangeSize = Inst.m_Operands[0].m_Index[2].m_RegIndex != UINT_MAX ? Inst.m_Operands[0].m_Index[2].m_RegIndex - LB + 1 : UINT_MAX;
      } else {
        LB = RangeID;
        RangeSize = 1;
      }
      R.SetLowerBound(LB);
      R.SetRangeSize(RangeSize);

      // Resource-specific state.
      string GVTypeName;
      raw_string_ostream GVTypeNameStream(GVTypeName);
      StructType *pResType = nullptr;
      unsigned Flags = 0;
      switch (Inst.OpCode()) {
      case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED: {
        R.SetSpaceID(Inst.m_TypedUAVDecl.Space);
        Flags = Inst.m_TypedUAVDecl.Flags;
        R.SetKind(DXBC::GetResourceKind(Inst.m_TypedUAVDecl.Dimension));
        const unsigned kTypedBufferElementSizeInBytes = 4;
        R.SetElementStride(kTypedBufferElementSizeInBytes);
        CompType DeclCT = DXBC::GetDeclResCompType(Inst.m_TypedUAVDecl.ReturnType[0]);
        if (DeclCT.IsInvalid()) DeclCT = CompType::getU32();
        R.SetCompType(DeclCT);
        pResType = GetTypedResElemType(DeclCT);
        break;
      }
      case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW: {
        R.SetSpaceID(Inst.m_RawUAVDecl.Space);
        R.SetKind(DxilResource::Kind::RawBuffer);
        Flags = Inst.m_RawUAVDecl.Flags;
        const unsigned kRawBufferElementSizeInBytes = 1;
        R.SetElementStride(kRawBufferElementSizeInBytes);
        pResType = GetTypedResElemType(CompType::getU32());
        break;
      }
      case D3D11_SB_OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED: {
        R.SetSpaceID(Inst.m_StructuredUAVDecl.Space);
        R.SetKind(DxilResource::Kind::StructuredBuffer);
        Flags = Inst.m_StructuredUAVDecl.Flags;
        unsigned Stride = Inst.m_StructuredUAVDecl.ByteStride;
        R.SetElementStride(Stride);
        pResType = GetStructResElemType(Stride);
        break;
      }
      default: ;
      }

      R.SetGloballyCoherent((Flags & D3D11_SB_GLOBALLY_COHERENT_ACCESS) != 0);
      R.SetHasCounter((Flags & D3D11_SB_UAV_HAS_ORDER_PRESERVING_COUNTER) != 0);
      R.SetROV((Flags & D3D11_SB_RASTERIZER_ORDERED_ACCESS) != 0);

      // Declare global variable.
      R.SetGlobalName(SynthesizeResGVName("U", R.GetID()));
      R.SetGlobalSymbol(DeclareUndefPtr(pResType, DXIL::kDeviceMemoryAddrSpace));

      // Record shader register/rangeID mapping for upcoming instruction conversion.
      DXASSERT(m_UAVRangeMap.find(RangeID) == m_UAVRangeMap.end(), "otherwise overlapping declarations");
      m_UAVRangeMap[RangeID] = R.GetID();
      break;
    }
    
    case D3D10_SB_OPCODE_DCL_INDEX_RANGE: {
      unsigned RowRegIdx = (Inst.m_Operands[0].m_IndexDimension == D3D10_SB_OPERAND_INDEX_1D) ? 0 : 1;
      SignatureHelper::Range R;
      R.StartRow      = Inst.m_Operands[0].m_Index[RowRegIdx].m_RegIndex;
      R.StartCol      = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      R.Rows          = Inst.m_IndexRangeDecl.RegCount;
      R.Cols          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      R.OutputStream  = CurrentOutputStream;

      switch (Inst.m_Operands[0].m_Type) {
      case D3D10_SB_OPERAND_TYPE_INPUT:
        m_pInputSignature->m_Ranges.emplace_back(R);
        break;
      case D3D10_SB_OPERAND_TYPE_OUTPUT:
        if (!m_pSM->IsHS() || m_bControlPointPhase) {
          m_pOutputSignature->m_Ranges.emplace_back(R);
        } else {
          DXASSERT_NOMSG(m_pSM->IsHS() && bPatchConstantPhase);
          m_pPatchConstantSignature->m_Ranges.emplace_back(R);
        }
        break;
      case D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT:
        DXASSERT_DXBC(m_pSM->IsHS() || m_pSM->IsDS());
        m_pPatchConstantSignature->m_Ranges.emplace_back(R);
        break;
      case D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT:
        DXASSERT_DXBC(m_pSM->IsHS() || m_pSM->IsDS());
        m_pInputSignature->m_Ranges.emplace_back(R);
        break;
      default:
        DXASSERT_DXBC(false);
      }
      break;
    }

    case D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE:
      m_pPR->SetInputPrimitive(DXBC::GetInputPrimitive(Inst.m_InputPrimitiveDecl.Primitive));
      break;

    case D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
      m_pPR->SetStreamPrimitiveTopology(DXBC::GetPrimitiveTopology(Inst.m_OutputTopologyDecl.Topology));
      break;

    case D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
      m_pPR->SetMaxVertexCount(Inst.m_GSMaxOutputVertexCountDecl.MaxOutputVertexCount);
      break;

    case D3D10_SB_OPCODE_DCL_INPUT: {
      D3D10_SB_OPERAND_TYPE RegType = Inst.m_Operands[0].m_Type;
      switch (RegType) {
      case D3D11_SB_OPERAND_TYPE_INPUT_COVERAGE_MASK:
        m_pInputSignature->m_bHasInputCoverage = true;
        break;

      case D3D11_SB_OPERAND_TYPE_INNER_COVERAGE:
        m_pInputSignature->m_bHasInnerInputCoverage = true;
        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:
      case D3D11_SB_OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED:
      case D3D11_SB_OPERAND_TYPE_INPUT_DOMAIN_POINT:
      case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID:
      case D3D10_SB_OPERAND_TYPE_INPUT_PRIMITIVEID:
      case D3D11_SB_OPERAND_TYPE_INPUT_FORK_INSTANCE_ID:
      case D3D11_SB_OPERAND_TYPE_INPUT_JOIN_INSTANCE_ID:
      case D3D11_SB_OPERAND_TYPE_CYCLE_COUNTER:
      case D3D11_SB_OPERAND_TYPE_INPUT_GS_INSTANCE_ID:
        break;

      default: {
        unsigned NumUnits, Row;
        switch (Inst.m_Operands[0].m_IndexDimension) {
        case D3D10_SB_OPERAND_INDEX_1D:
          NumUnits = 0;
          Row = Inst.m_Operands[0].m_Index[0].m_RegIndex;
          break;

        case D3D10_SB_OPERAND_INDEX_2D:
          NumUnits = Inst.m_Operands[0].m_Index[0].m_RegIndex;
          Row = Inst.m_Operands[0].m_Index[1].m_RegIndex;
          break;

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

        SignatureHelper::UsedElement E;
        E.NumUnits          = NumUnits;
        E.Row               = Row;
        E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
        E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
        E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
        E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

        if (RegType == D3D10_SB_OPERAND_TYPE_INPUT) {
          m_pInputSignature->m_UsedElements.emplace_back(E);
        } else {
          if (m_pSM->IsDS()) {
            switch (RegType) {
            case D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT:
              m_pInputSignature->m_UsedElements.emplace_back(E);
              break;
            case D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT:
              m_pPatchConstantSignature->m_UsedElements.emplace_back(E);
              break;
            default:
              DXASSERT(false, "check unsupported case");
              break;
            }
          }

          if (m_pSM->IsHS()) {
            switch (RegType) {
            case D3D11_SB_OPERAND_TYPE_INPUT_CONTROL_POINT:
              m_pInputSignature->m_UsedElements.emplace_back(E);
              break;
            case D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT:
              break;
            case D3D11_SB_OPERAND_TYPE_OUTPUT_CONTROL_POINT:
              break;
            default:
              DXASSERT(false, "check unsupported case");
              break;
            }
          }
        }

        break;
      }
      }

      break;
    }

    case D3D10_SB_OPCODE_DCL_INPUT_SGV: {
      SignatureHelper::UsedElement E;
      E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

      m_pInputSignature->m_UsedElements.emplace_back(E);
      break;
    }

    case D3D10_SB_OPCODE_DCL_INPUT_SIV: {
      unsigned NumUnits = 0;
      unsigned Row = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      if (m_pSM->IsGS()) {
        NumUnits = Inst.m_Operands[0].m_Index[0].m_RegIndex;
        Row = Inst.m_Operands[0].m_Index[1].m_RegIndex;
      }

      SignatureHelper::UsedElement E;
      E.NumUnits          = NumUnits;
      E.Row               = Row;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

      switch (Inst.m_Operands[0].m_Type) {
      case D3D10_SB_OPERAND_TYPE_INPUT:
        m_pInputSignature->m_UsedElements.emplace_back(E);
        break;

      case D3D11_SB_OPERAND_TYPE_INPUT_PATCH_CONSTANT:
        m_pPatchConstantSignature->m_UsedElements.emplace_back(E);
        break;

      default:
        DXASSERT(false, "missing case");
        break;
      }

      break;
    }

    case D3D10_SB_OPCODE_DCL_INPUT_PS: {
      SignatureHelper::UsedElement E;
      E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = (D3D_INTERPOLATION_MODE)Inst.m_InputPSDecl.InterpolationMode;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

      m_pInputSignature->m_UsedElements.emplace_back(E);
      break;
    }

    case D3D10_SB_OPCODE_DCL_INPUT_PS_SGV: {
      SignatureHelper::UsedElement E;
      E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = (D3D_INTERPOLATION_MODE)Inst.m_InputPSDeclSGV.InterpolationMode;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

      m_pInputSignature->m_UsedElements.emplace_back(E);
      break;
    }

    case D3D10_SB_OPCODE_DCL_INPUT_PS_SIV: {
      SignatureHelper::UsedElement E;
      E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = (D3D_INTERPOLATION_MODE)Inst.m_InputPSDeclSIV.InterpolationMode;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

      m_pInputSignature->m_UsedElements.emplace_back(E);
      break;
    }

    case D3D10_SB_OPCODE_DCL_OUTPUT: {
      D3D10_SB_OPERAND_TYPE RegType = Inst.m_Operands[0].m_Type;
      switch (RegType) {
      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:
        m_DepthRegType = RegType;
        __fallthrough;
      case D3D11_SB_OPERAND_TYPE_OUTPUT_STENCIL_REF:
      case D3D10_SB_OPERAND_TYPE_OUTPUT_COVERAGE_MASK: {
        m_bHasStencilRef = RegType == D3D11_SB_OPERAND_TYPE_OUTPUT_STENCIL_REF;
        m_bHasCoverageOut = RegType == D3D10_SB_OPERAND_TYPE_OUTPUT_COVERAGE_MASK;

        SignatureHelper::UsedElement E;
        E.Row               = Semantic::kUndefinedRow;
        E.StartCol          = 0;
        E.Cols              = 1;
        E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
        E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;

        m_pOutputSignature->m_UsedElements.emplace_back(E);
        break;
      }

      default: {
        SignatureHelper::UsedElement E;
        E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
        E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
        E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
        E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
        E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;
        E.OutputStream      = CurrentOutputStream;

        if (!m_pSM->IsHS() || m_bControlPointPhase) {
          m_pOutputSignature->m_UsedElements.emplace_back(E);
        } else {
          DXASSERT_NOMSG(m_pSM->IsHS() && bPatchConstantPhase);
          m_pPatchConstantSignature->m_UsedElements.emplace_back(E);
        }

        MaxOutputRegister = std::max(MaxOutputRegister, E.Row);
        break;
      }
      }
      
      break;
    }

    case D3D10_SB_OPCODE_DCL_OUTPUT_SGV:
    case D3D10_SB_OPCODE_DCL_OUTPUT_SIV: {
      SignatureHelper::UsedElement E;
      E.Row               = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      E.StartCol          = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetFirstActiveComp();
      E.Cols              = CMask::FromDXBC(Inst.m_Operands[0].m_WriteMask).GetNumActiveRangeComps();
      E.InterpolationMode = D3D_INTERPOLATION_UNDEFINED;
      E.MinPrecision      = Inst.m_Operands[0].m_MinPrecision;
      E.OutputStream      = CurrentOutputStream;

      if (!m_pSM->IsHS() || m_bControlPointPhase) {
        m_pOutputSignature->m_UsedElements.emplace_back(E);
      } else {
        DXASSERT_NOMSG(m_pSM->IsHS() && bPatchConstantPhase);
        m_pPatchConstantSignature->m_UsedElements.emplace_back(E);
      }

      MaxOutputRegister = std::max(MaxOutputRegister, E.Row);
      break;
    }
    
    case D3D10_SB_OPCODE_DCL_TEMPS:
      m_NumTempRegs = std::max(m_NumTempRegs, Inst.m_TempsDecl.NumTemps);
      break;

    case D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP: {
      // Record x-register.
      unsigned Reg = Inst.m_IndexableTempDecl.IndexableTempNumber;
      unsigned NumRegs = Inst.m_IndexableTempDecl.NumRegisters;
      CMask Mask = CMask::FromDXBC(Inst.m_IndexableTempDecl.Mask);
      IndexableReg IR = { nullptr, nullptr, NumRegs, Mask.GetNumActiveRangeComps(), true };

      if (!bPatchConstantPhase) {
        // This is the main shader.
        DXASSERT_DXBC(m_IndexableRegs.find(Reg) == m_IndexableRegs.end());
        m_IndexableRegs[Reg] = IR;
      } else {
        // This is patch constant function.
        // Can have dcl per phase
        auto itIR = m_PatchConstantIndexableRegs.find(Reg);
        if (itIR != m_PatchConstantIndexableRegs.end()) {
          auto &theIR = itIR->second;
          theIR.NumComps = std::max(theIR.NumComps, IR.NumComps);
          theIR.NumComps = std::max(theIR.NumRegs, IR.NumRegs);
        } else {
          m_PatchConstantIndexableRegs[Reg] = IR;
        }
      }
      break;
    }

    case D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS:
      SetShaderGlobalFlags(Inst.m_GlobalFlagsDecl.Flags);
      break;

    case D3D11_SB_OPCODE_DCL_STREAM: {
      BYTE Stream = (BYTE)Inst.m_Operands[0].m_Index[0].m_RegIndex;
      IFTBOOL(Stream < DXIL::kNumOutputStreams, DXC_E_INCORRECT_DXBC);
      CurrentOutputStream = Stream;
      m_pPR->SetStreamActive(Stream, true);
      break;
    }
    
    case D3D11_SB_OPCODE_HS_DECLS:
      break;

    case D3D11_SB_OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
      m_pPR->SetInputControlPointCount(Inst.m_InputControlPointCountDecl.InputControlPointCount);
      break;

    case D3D11_SB_OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
      m_pPR->SetOutputControlPointCount(Inst.m_OutputControlPointCountDecl.OutputControlPointCount);
      break;

    case D3D11_SB_OPCODE_DCL_TESS_DOMAIN:
      m_pPR->SetTessellatorDomain(DXBC::GetTessellatorDomain(Inst.m_TessellatorDomainDecl.TessellatorDomain));
      break;

    case D3D11_SB_OPCODE_DCL_TESS_PARTITIONING:
      m_pPR->SetTessellatorPartitioning(DXBC::GetTessellatorPartitioning(Inst.m_TessellatorPartitioningDecl.TessellatorPartitioning));
      break;

    case D3D11_SB_OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
      m_pPR->SetTessellatorOutputPrimitive(DXBC::GetTessellatorOutputPrimitive(Inst.m_TessellatorOutputPrimitiveDecl.TessellatorOutputPrimitive));
      break;

    case D3D11_SB_OPCODE_DCL_HS_MAX_TESSFACTOR:
      m_pPR->SetMaxTessellationFactor(Inst.m_HSMaxTessFactorDecl.MaxTessFactor);
      break;

    case D3D11_SB_OPCODE_HS_CONTROL_POINT_PHASE:
      DXASSERT_NOMSG(!m_bControlPointPhase && !bPatchConstantPhase);
      m_bControlPointPhase = true;
      break;

    case D3D11_SB_OPCODE_HS_FORK_PHASE:
    case D3D11_SB_OPCODE_HS_JOIN_PHASE:
      m_bControlPointPhase = false;
      bPatchConstantPhase = true;
      m_PatchConstantPhaseInstanceCounts.push_back(1);
      break;

    case D3D11_SB_OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
      m_PatchConstantPhaseInstanceCounts.back() = Inst.m_HSForkPhaseInstanceCountDecl.InstanceCount;
      break;

    case D3D11_SB_OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT:
      m_PatchConstantPhaseInstanceCounts.back() = Inst.m_HSJoinPhaseInstanceCountDecl.InstanceCount;
      break;

    case D3D11_SB_OPCODE_DCL_THREAD_GROUP:
      m_pPR->SetNumThreads(Inst.m_ThreadGroupDecl.x,
                           Inst.m_ThreadGroupDecl.y,
                           Inst.m_ThreadGroupDecl.z);
      break;

    case D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
    case D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED: {
      TGSMEntry E;
      E.Id = m_TGSMCount++;

      if (Inst.OpCode() == D3D11_SB_OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW) {
        E.Stride = 1;
        E.Count = Inst.m_RawTGSMDecl.ByteCount;
      } else {
        E.Stride = Inst.m_StructuredTGSMDecl.StructByteStride;
        E.Count = Inst.m_StructuredTGSMDecl.StructCount;
      }

      // Declare global variable.
      unsigned SizeInBytes = E.Stride*E.Count;
      Type *pArrayType = ArrayType::get(Type::getInt8Ty(m_Ctx), SizeInBytes);
      E.pVar = new GlobalVariable(*m_pModule, pArrayType, 
                                  false, GlobalValue::InternalLinkage, 
                                  UndefValue::get(pArrayType), 
                                  Twine("TGSM") + Twine(E.Id), nullptr, 
                                  GlobalVariable::NotThreadLocal, DXIL::kTGSMAddrSpace);
      E.pVar->setAlignment(kRegCompAlignment);

      // Mark GV as being used for LLVM.
      m_pPR->GetLLVMUsed().push_back(E.pVar);

      m_TGSMMap[Inst.m_Operands[0].m_Index[0].m_RegIndex] = E;
      break;
    }

    case D3D11_SB_OPCODE_DCL_GS_INSTANCE_COUNT:
      m_pPR->SetGSInstanceCount(Inst.m_GSInstanceCountDecl.InstanceCount);
      break;

    case D3D10_SB_OPCODE_CUSTOMDATA:
      break;

    case D3D11_SB_OPCODE_DCL_FUNCTION_BODY: {
      DXASSERT_DXBC(Inst.m_NumOperands == 0);
      unsigned FBIdx = Inst.m_FunctionBodyDecl.FunctionBodyNumber;
      m_InterfaceFunctionBodies[FBIdx].pFunc = nullptr;
      break;
    }

    case D3D11_SB_OPCODE_DCL_FUNCTION_TABLE: {
      DXASSERT_DXBC(Inst.m_NumOperands == 0);
      auto& FnTable = m_FunctionTables[Inst.m_FunctionTableDecl.FunctionTableNumber];
      FnTable.assign(Inst.m_FunctionTableDecl.pFunctionIdentifiers, Inst.m_FunctionTableDecl.pFunctionIdentifiers + Inst.m_FunctionTableDecl.TableLength);
      break;
    }

    case D3D11_SB_OPCODE_DCL_INTERFACE: {
      DXASSERT_DXBC(Inst.m_NumOperands == 0);
      auto& Iface = m_Interfaces[Inst.m_InterfaceDecl.InterfaceNumber];
      Iface.Tables.assign(Inst.m_InterfaceDecl.pFunctionTableIdentifiers, Inst.m_InterfaceDecl.pFunctionTableIdentifiers + Inst.m_InterfaceDecl.TableLength);
#ifdef DBG
      for (unsigned TableIdx : Iface.Tables) {
          DXASSERT_DXBC(m_FunctionTables[TableIdx].size() == Inst.m_InterfaceDecl.ExpectedTableSize);
      }
#endif
      Iface.bDynamicallyIndexed = Inst.m_InterfaceDecl.bDynamicallyIndexed;
      Iface.NumArrayEntries = Inst.m_InterfaceDecl.ArrayLength;
      m_NumIfaces = std::max(m_NumIfaces, Inst.m_InterfaceDecl.InterfaceNumber + Iface.NumArrayEntries);
      InsertInterfacesResourceDecls();
      break;
    }

    case D3D10_SB_OPCODE_LABEL: {
      m_bControlPointPhase = false;
      bPatchConstantPhase = false;
      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);
      FunctionType *pFuncType = FunctionType::get(Type::getVoidTy(m_Ctx), false);
      unsigned LabelIdx = Inst.m_Operands[0].m_Index[0].m_RegIndex;
      LabelEntry Label;
      const bool IsFb = Inst.m_Operands[0].m_Type == D3D11_SB_OPERAND_TYPE_FUNCTION_BODY;
      auto& LabelMap = IsFb ? m_InterfaceFunctionBodies : m_Labels;
      DXASSERT_DXBC((LabelMap.find(LabelIdx) == LabelMap.end()) == !IsFb); // Function bodies should be pre-declared, labels aren't
      Label.pFunc = Function::Create(pFuncType, GlobalValue::LinkageTypes::InternalLinkage,
                                     StringRef(IsFb ? "dx.fb." : "dx.label.") + Twine(LabelIdx), m_pModule.get());
      Label.pFunc->setCallingConv(CallingConv::C);
      LabelMap[LabelIdx] = Label;
      break;
    }

    default:
      break;
    }
  }
}