text: ///////////////////////////////////////////////////////////////////////////////
  //                                                                           //
  // DxilMetadataHelper.h                                                      //
  // Copyright (C) Microsoft Corporation. All rights reserved.                 //
  // This file is distributed under the University of Illinois Open Source     //
  // License. See LICENSE.TXT for details.                                     //
  //                                                                           //
  // Helper to serialize/desialize metadata for DxilModule.                    //
  //                                                                           //
  ///////////////////////////////////////////////////////////////////////////////
  
  #pragma once
  
  #include "dxc/DXIL/DxilConstants.h"
  #include "llvm37/ADT/ArrayRef.h"
  #include <memory>
  #include <string>
  #include <vector>
  
  namespace llvm37 {
  class LLVM37Context;
  class Module;
  class Function;
  class Instruction;
  class DbgDeclareInst;
  class Value;
  class MDOperand;
  class Metadata;
  class ConstantAsMetadata;
  class MDTuple;
  class MDNode;
  class NamedMDNode;
  class GlobalVariable;
  class StringRef;
  }
  
  namespace hlsl {
  
  class ShaderModel;
  class DxilSignature;
  struct DxilEntrySignature;
  class DxilSignatureElement;
  class DxilModule;
  class DxilResourceBase;
  class DxilCBuffer;
  class DxilResource;
  class DxilSampler;
  class DxilTypeSystem;
  class DxilStructAnnotation;
  class DxilFieldAnnotation;
  class DxilTemplateArgAnnotation;
  class DxilFunctionAnnotation;
  class DxilParameterAnnotation;
  class RootSignatureHandle;
  struct DxilFunctionProps;
  class DxilSubobjects;
  class DxilSubobject;
  struct DxilCounters;
  
  // Additional debug information for SROA'ed array variables,
  // where adjacent elements in DXIL might not have been adjacent
  // in the original user variable.
  struct DxilDIArrayDim {
    unsigned StrideInBits;
    unsigned NumElements;
  };
  
  /// Use this class to manipulate DXIL-spcific metadata.
  // In our code, only DxilModule and HLModule should use this class.
  class DxilMDHelper {
  public:
    //
    // Constants for metadata names and field positions.
    //
  
    // Dxil version.
    static const char kDxilVersionMDName[];
    static const unsigned kDxilVersionNumFields = 2;
    static const unsigned kDxilVersionMajorIdx  = 0;  // DXIL version major.
    static const unsigned kDxilVersionMinorIdx  = 1;  // DXIL version minor.
  
    // Shader model.
    static const char kDxilShaderModelMDName[];
    static const unsigned kDxilShaderModelNumFields = 3;
    static const unsigned kDxilShaderModelTypeIdx   = 0;  // Shader type (vs,ps,cs,gs,ds,hs).
    static const unsigned kDxilShaderModelMajorIdx  = 1;  // Shader model major.
    static const unsigned kDxilShaderModelMinorIdx  = 2;  // Shader model minor.
  
    // Intermediate codegen/optimizer options, not valid in final DXIL module.
    static const char kDxilIntermediateOptionsMDName[];
    static const unsigned kDxilIntermediateOptionsFlags = 0;  // Unique element ID.
  
    // DxilCounters
    static const char kDxilCountersMDName[];
    // !{!"<counter>", i32 <count>, !"<counter>", i32 <count>, ...}
  
    // Entry points.
    static const char kDxilEntryPointsMDName[];
  
    // Root Signature, for intermediate use, not valid in final DXIL module.
    static const char kDxilRootSignatureMDName[];
  
    // ViewId state.
    static const char kDxilViewIdStateMDName[];
  
    // Subobjects
    static const char kDxilSubobjectsMDName[];
  
    // Source info.
    static const char kDxilSourceContentsMDName[];
    static const char kDxilSourceDefinesMDName[];
    static const char kDxilSourceMainFileNameMDName[];
    static const char kDxilSourceArgsMDName[];
  
    // Old source info.
    static const char kDxilSourceContentsOldMDName[];
    static const char kDxilSourceDefinesOldMDName[];
    static const char kDxilSourceMainFileNameOldMDName[];
    static const char kDxilSourceArgsOldMDName[];
  
    static const unsigned kDxilEntryPointNumFields  = 5;
    static const unsigned kDxilEntryPointFunction   = 0;  // Entry point function symbol.
    static const unsigned kDxilEntryPointName       = 1;  // Entry point unmangled name.
    static const unsigned kDxilEntryPointSignatures = 2;  // Entry point signature tuple.
    static const unsigned kDxilEntryPointResources  = 3;  // Entry point resource tuple.
    static const unsigned kDxilEntryPointProperties = 4;  // Entry point properties tuple.
  
    // Signatures.
    static const unsigned kDxilNumSignatureFields     = 3;
    static const unsigned kDxilInputSignature         = 0;  // Shader input signature.
    static const unsigned kDxilOutputSignature        = 1;  // Shader output signature.
    static const unsigned kDxilPatchConstantSignature = 2;  // Shader patch constant (PC) signature.
  
    // Signature Element.
    static const unsigned kDxilSignatureElementNumFields      = 11;
    static const unsigned kDxilSignatureElementID             = 0;  // Unique element ID.
    static const unsigned kDxilSignatureElementName           = 1;  // Element name.
    static const unsigned kDxilSignatureElementType           = 2;  // Element type.
    static const unsigned kDxilSignatureElementSystemValue    = 3;  // Effective system value.
    static const unsigned kDxilSignatureElementIndexVector    = 4;  // Semantic index vector.
    static const unsigned kDxilSignatureElementInterpMode     = 5;  // Interpolation mode.
    static const unsigned kDxilSignatureElementRows           = 6;  // Number of rows.
    static const unsigned kDxilSignatureElementCols           = 7;  // Number of columns.
    static const unsigned kDxilSignatureElementStartRow       = 8;  // Element packing start row.
    static const unsigned kDxilSignatureElementStartCol       = 9;  // Element packing start column.
    static const unsigned kDxilSignatureElementNameValueList  = 10;  // Name-value list for extended properties.
  
    // Signature Element Extended Properties.
    static const unsigned kDxilSignatureElementOutputStreamTag    = 0;
    static const unsigned kHLSignatureElementGlobalSymbolTag      = 1;
    static const unsigned kDxilSignatureElementDynIdxCompMaskTag  = 2;
    static const unsigned kDxilSignatureElementUsageCompMaskTag   = 3;
  
    // Resources.
    static const char kDxilResourcesMDName[];
    static const unsigned kDxilNumResourceFields              = 4;
    static const unsigned kDxilResourceSRVs                   = 0;
    static const unsigned kDxilResourceUAVs                   = 1;
    static const unsigned kDxilResourceCBuffers               = 2;
    static const unsigned kDxilResourceSamplers               = 3;
  
    // ResourceBase.
    static const unsigned kDxilResourceBaseNumFields          = 6;
    static const unsigned kDxilResourceBaseID                 = 0;  // Unique (per type) resource ID.
    static const unsigned kDxilResourceBaseVariable           = 1;  // Resource global variable.
    static const unsigned kDxilResourceBaseName               = 2;  // Original (HLSL) name of the resource.
    static const unsigned kDxilResourceBaseSpaceID            = 3;  // Resource range space ID.
    static const unsigned kDxilResourceBaseLowerBound         = 4;  // Resource range lower bound.
    static const unsigned kDxilResourceBaseRangeSize          = 5;  // Resource range size.
  
    // SRV-specific.
    static const unsigned kDxilSRVNumFields                   = 9;
    static const unsigned kDxilSRVShape                       = 6;  // SRV shape.
    static const unsigned kDxilSRVSampleCount                 = 7;  // SRV sample count.
    static const unsigned kDxilSRVNameValueList               = 8;  // Name-value list for extended properties.
  
    // UAV-specific.
    static const unsigned kDxilUAVNumFields                   = 11;
    static const unsigned kDxilUAVShape                       = 6;  // UAV shape.
    static const unsigned kDxilUAVGloballyCoherent            = 7;  // Globally-coherent UAV.
    static const unsigned kDxilUAVCounter                     = 8;  // UAV with a counter.
    static const unsigned kDxilUAVRasterizerOrderedView       = 9;  // UAV that is a ROV.
    static const unsigned kDxilUAVNameValueList               = 10; // Name-value list for extended properties.
  
    // CBuffer-specific.
    static const unsigned kDxilCBufferNumFields               = 8;
    static const unsigned kDxilCBufferSizeInBytes             = 6;  // CBuffer size in bytes.
    static const unsigned kDxilCBufferNameValueList           = 7;  // Name-value list for extended properties.
  
    // CBuffer extended properties
    static const unsigned kHLCBufferIsTBufferTag              = 0;  // CBuffer is actually TBuffer, not yet converted to SRV.
  
    // Sampler-specific.
    static const unsigned kDxilSamplerNumFields               = 8;
    static const unsigned kDxilSamplerType                    = 6;  // Sampler type.
    static const unsigned kDxilSamplerNameValueList           = 7;  // Name-value list for extended properties.
  
    // Resource extended property tags.
    static const unsigned kDxilTypedBufferElementTypeTag            = 0;
    static const unsigned kDxilStructuredBufferElementStrideTag     = 1;
    static const unsigned kDxilSamplerFeedbackKindTag               = 2;
  
    // Type system.
    static const char kDxilTypeSystemMDName[];
    static const char kDxilTypeSystemHelperVariablePrefix[];
    static const unsigned kDxilTypeSystemStructTag                  = 0;
    static const unsigned kDxilTypeSystemFunctionTag                = 1;
    static const unsigned kDxilFieldAnnotationSNormTag              = 0;
    static const unsigned kDxilFieldAnnotationUNormTag              = 1;
    static const unsigned kDxilFieldAnnotationMatrixTag             = 2;
    static const unsigned kDxilFieldAnnotationCBufferOffsetTag      = 3;
    static const unsigned kDxilFieldAnnotationSemanticStringTag     = 4;
    static const unsigned kDxilFieldAnnotationInterpolationModeTag  = 5;
    static const unsigned kDxilFieldAnnotationFieldNameTag          = 6;
    static const unsigned kDxilFieldAnnotationCompTypeTag           = 7;
    static const unsigned kDxilFieldAnnotationPreciseTag            = 8;
    static const unsigned kDxilFieldAnnotationCBUsedTag             = 9;
  
    // StructAnnotation extended property tags (DXIL 1.5+ only, appended)
    static const unsigned kDxilTemplateArgumentsTag                 = 0;  // Name for name-value list of extended struct properties
    // TemplateArgument tags
    static const unsigned kDxilTemplateArgTypeTag                   = 0;  // Type template argument, followed by undef of type
    static const unsigned kDxilTemplateArgIntegralTag               = 1;  // Integral template argument, followed by i64 value
    static const unsigned kDxilTemplateArgValue                     = 1;  // Position of template arg value (type or int)
  
    // Control flow hint.
    static const char kDxilControlFlowHintMDName[];
  
    // Resource attribute.
    static const char kHLDxilResourceAttributeMDName[];
    static const unsigned kHLDxilResourceAttributeNumFields = 2;
    static const unsigned kHLDxilResourceAttributeClass = 0;
    static const unsigned kHLDxilResourceAttributeMeta = 1;
  
    // Precise attribute.
    static const char kDxilPreciseAttributeMDName[];
  
    // NonUniform attribute.
    static const char kDxilNonUniformAttributeMDName[];
  
    // Variable debug layout metadata.
    static const char kDxilVariableDebugLayoutMDName[];
  
    // Indication of temporary storage metadata.
    static const char kDxilTempAllocaMDName[];
  
    // Validator version.
    static const char kDxilValidatorVersionMDName[];
    // Validator version uses the same constants for fields as kDxilVersion*
  
    // Extended shader property tags.
    static const unsigned kDxilShaderFlagsTag     = 0;
    static const unsigned kDxilGSStateTag         = 1;
    static const unsigned kDxilDSStateTag         = 2;
    static const unsigned kDxilHSStateTag         = 3;
    static const unsigned kDxilNumThreadsTag      = 4;
    static const unsigned kDxilAutoBindingSpaceTag    = 5;
    static const unsigned kDxilRayPayloadSizeTag  = 6;
    static const unsigned kDxilRayAttribSizeTag   = 7;
    static const unsigned kDxilShaderKindTag      = 8;
    static const unsigned kDxilMSStateTag         = 9;
    static const unsigned kDxilASStateTag         = 10;
    static const unsigned kDxilWaveSizeTag        = 11;
  
    // GSState.
    static const unsigned kDxilGSStateNumFields               = 5;
    static const unsigned kDxilGSStateInputPrimitive          = 0;
    static const unsigned kDxilGSStateMaxVertexCount          = 1;
    static const unsigned kDxilGSStateActiveStreamMask        = 2;
    static const unsigned kDxilGSStateOutputStreamTopology    = 3;
    static const unsigned kDxilGSStateGSInstanceCount         = 4;
  
    // DSState.
    static const unsigned kDxilDSStateNumFields               = 2;
    static const unsigned kDxilDSStateTessellatorDomain       = 0;
    static const unsigned kDxilDSStateInputControlPointCount  = 1;
  
    // HSState.
    static const unsigned kDxilHSStateNumFields                 = 7;
    static const unsigned kDxilHSStatePatchConstantFunction     = 0;
    static const unsigned kDxilHSStateInputControlPointCount    = 1;
    static const unsigned kDxilHSStateOutputControlPointCount   = 2;
    static const unsigned kDxilHSStateTessellatorDomain         = 3;
    static const unsigned kDxilHSStateTessellatorPartitioning   = 4;
    static const unsigned kDxilHSStateTessellatorOutputPrimitive= 5;
    static const unsigned kDxilHSStateMaxTessellationFactor     = 6;
  
    // MSState.
    static const unsigned kDxilMSStateNumFields = 5;
    static const unsigned kDxilMSStateNumThreads = 0;
    static const unsigned kDxilMSStateMaxVertexCount = 1;
    static const unsigned kDxilMSStateMaxPrimitiveCount = 2;
    static const unsigned kDxilMSStateOutputTopology = 3;
    static const unsigned kDxilMSStatePayloadSizeInBytes = 4;
  
    // ASState.
    static const unsigned kDxilASStateNumFields = 2;
    static const unsigned kDxilASStateNumThreads = 0;
    static const unsigned kDxilASStatePayloadSizeInBytes = 1;
  
  public:
    /// Use this class to manipulate metadata of DXIL or high-level DX IR specific fields in the record.
    class ExtraPropertyHelper {
    public:
      ExtraPropertyHelper(llvm37::Module *pModule);
      virtual ~ExtraPropertyHelper() {}
  
      virtual void EmitSRVProperties(const DxilResource &SRV, std::vector<llvm37::Metadata *> &MDVals) = 0;
      virtual void LoadSRVProperties(const llvm37::MDOperand &MDO, DxilResource &SRV) = 0;
  
      virtual void EmitUAVProperties(const DxilResource &UAV, std::vector<llvm37::Metadata *> &MDVals) = 0;
      virtual void LoadUAVProperties(const llvm37::MDOperand &MDO, DxilResource &UAV) = 0;
  
      virtual void EmitCBufferProperties(const DxilCBuffer &CB, std::vector<llvm37::Metadata *> &MDVals) = 0;
      virtual void LoadCBufferProperties(const llvm37::MDOperand &MDO, DxilCBuffer &CB) = 0;
  
      virtual void EmitSamplerProperties(const DxilSampler &S, std::vector<llvm37::Metadata *> &MDVals) = 0;
      virtual void LoadSamplerProperties(const llvm37::MDOperand &MDO, DxilSampler &S) = 0;
  
      virtual void EmitSignatureElementProperties(const DxilSignatureElement &SE, std::vector<llvm37::Metadata *> &MDVals) = 0;
      virtual void LoadSignatureElementProperties(const llvm37::MDOperand &MDO, DxilSignatureElement &SE) = 0;
  
    protected:
      llvm37::LLVM37Context &m_Ctx;
      llvm37::Module *m_pModule;
  
    public:
      unsigned m_ValMajor, m_ValMinor;        // Reported validation version in DXIL
      unsigned m_MinValMajor, m_MinValMinor;  // Minimum validation version dictated by shader model
      bool m_bExtraMetadata;
    };
  
  public:
    DxilMDHelper(llvm37::Module *pModule, std::unique_ptr<ExtraPropertyHelper> EPH);
    ~DxilMDHelper();
  
    void SetShaderModel(const ShaderModel *pSM);
    const ShaderModel *GetShaderModel() const;
  
    // Dxil version.
    void EmitDxilVersion(unsigned Major, unsigned Minor);
    void LoadDxilVersion(unsigned &Major, unsigned &Minor);
  
    // Validator version.
    void EmitValidatorVersion(unsigned Major, unsigned Minor);
    void LoadValidatorVersion(unsigned &Major, unsigned &Minor);
  
    // Shader model.
    void EmitDxilShaderModel(const ShaderModel *pSM);
    void LoadDxilShaderModel(const ShaderModel *&pSM);
  
    // Intermediate flags
    void EmitDxilIntermediateOptions(uint32_t flags);
    void LoadDxilIntermediateOptions(uint32_t &flags);
  
    // Entry points.
    void EmitDxilEntryPoints(std::vector<llvm37::MDNode *> &MDEntries);
    void UpdateDxilEntryPoints(std::vector<llvm37::MDNode *> &MDEntries);
    const llvm37::NamedMDNode *GetDxilEntryPoints();
    llvm37::MDTuple *EmitDxilEntryPointTuple(llvm37::Function *pFunc, const std::string &Name, llvm37::MDTuple *pSignatures,
                                           llvm37::MDTuple *pResources, llvm37::MDTuple *pProperties);
    void GetDxilEntryPoint(const llvm37::MDNode *MDO, llvm37::Function *&pFunc, std::string &Name,
                           const llvm37::MDOperand *&pSignatures, const llvm37::MDOperand *&pResources,
                           const llvm37::MDOperand *&pProperties);
  
    // Signatures.
    llvm37::MDTuple *EmitDxilSignatures(const DxilEntrySignature &EntrySig);
    void LoadDxilSignatures(const llvm37::MDOperand &MDO,
                            DxilEntrySignature &EntrySig);
    llvm37::MDTuple *EmitSignatureMetadata(const DxilSignature &Sig);
    void EmitRootSignature(std::vector<uint8_t> &SerializedRootSignature);
    void LoadSignatureMetadata(const llvm37::MDOperand &MDO, DxilSignature &Sig);
    llvm37::MDTuple *EmitSignatureElement(const DxilSignatureElement &SE);
    void LoadSignatureElement(const llvm37::MDOperand &MDO, DxilSignatureElement &SE);
    void LoadRootSignature(std::vector<uint8_t> &SerializedRootSignature);
  
    // Resources.
    llvm37::MDTuple *EmitDxilResourceTuple(llvm37::MDTuple *pSRVs, llvm37::MDTuple *pUAVs, 
                                         llvm37::MDTuple *pCBuffers, llvm37::MDTuple *pSamplers);
    void EmitDxilResources(llvm37::MDTuple *pDxilResourceTuple);
    void UpdateDxilResources(llvm37::MDTuple *pDxilResourceTuple);
    void GetDxilResources(const llvm37::MDOperand &MDO, const llvm37::MDTuple *&pSRVs, const llvm37::MDTuple *&pUAVs, 
                          const llvm37::MDTuple *&pCBuffers, const llvm37::MDTuple *&pSamplers);
    void EmitDxilResourceBase(const DxilResourceBase &R, llvm37::Metadata *ppMDVals[]);
    void LoadDxilResourceBase(const llvm37::MDOperand &MDO, DxilResourceBase &R);
    llvm37::MDTuple *EmitDxilSRV(const DxilResource &SRV);
    void LoadDxilSRV(const llvm37::MDOperand &MDO, DxilResource &SRV);
    llvm37::MDTuple *EmitDxilUAV(const DxilResource &UAV);
    void LoadDxilUAV(const llvm37::MDOperand &MDO, DxilResource &UAV);
    llvm37::MDTuple *EmitDxilCBuffer(const DxilCBuffer &CB);
    void LoadDxilCBuffer(const llvm37::MDOperand &MDO, DxilCBuffer &CB);
    llvm37::MDTuple *EmitDxilSampler(const DxilSampler &S);
    void LoadDxilSampler(const llvm37::MDOperand &MDO, DxilSampler &S);
    const llvm37::MDOperand &GetResourceClass(llvm37::MDNode *MD, DXIL::ResourceClass &RC);
    void LoadDxilResourceBaseFromMDNode(llvm37::MDNode *MD, DxilResourceBase &R);
    void LoadDxilResourceFromMDNode(llvm37::MDNode *MD, DxilResource &R);
    void LoadDxilSamplerFromMDNode(llvm37::MDNode *MD, DxilSampler &S);
  
    // Type system.
    void EmitDxilTypeSystem(DxilTypeSystem &TypeSystem, std::vector<llvm37::GlobalVariable *> &LLVM37Used);
    void LoadDxilTypeSystemNode(const llvm37::MDTuple &MDT, DxilTypeSystem &TypeSystem);
    void LoadDxilTypeSystem(DxilTypeSystem &TypeSystem);
    llvm37::Metadata *EmitDxilStructAnnotation(const DxilStructAnnotation &SA);
    void LoadDxilStructAnnotation(const llvm37::MDOperand &MDO, DxilStructAnnotation &SA);
    llvm37::Metadata *EmitDxilFieldAnnotation(const DxilFieldAnnotation &FA);
    void LoadDxilFieldAnnotation(const llvm37::MDOperand &MDO, DxilFieldAnnotation &FA);
    llvm37::Metadata *EmitDxilFunctionAnnotation(const DxilFunctionAnnotation &FA);
    void LoadDxilFunctionAnnotation(const llvm37::MDOperand &MDO, DxilFunctionAnnotation &FA);
    llvm37::Metadata *EmitDxilParamAnnotation(const DxilParameterAnnotation &PA);
    void LoadDxilParamAnnotation(const llvm37::MDOperand &MDO, DxilParameterAnnotation &PA);
    llvm37::Metadata *EmitDxilParamAnnotations(const DxilFunctionAnnotation &FA);
    void LoadDxilParamAnnotations(const llvm37::MDOperand &MDO, DxilFunctionAnnotation &FA);
    llvm37::Metadata *EmitDxilTemplateArgAnnotation(const DxilTemplateArgAnnotation &annotation);
    void LoadDxilTemplateArgAnnotation(const llvm37::MDOperand &MDO, DxilTemplateArgAnnotation &annotation);
  
    // Function props.
    llvm37::MDTuple *EmitDxilFunctionProps(const hlsl::DxilFunctionProps *props,
                                         const llvm37::Function *F);
    const llvm37::Function *LoadDxilFunctionProps(const llvm37::MDTuple *pProps,
                                                hlsl::DxilFunctionProps *props);
    llvm37::MDTuple *EmitDxilEntryProperties(uint64_t rawShaderFlag,
                                            const hlsl::DxilFunctionProps &props,
                                            uint32_t autoBindingSpace);
    void LoadDxilEntryProperties(const llvm37::MDOperand &MDO,
                                  uint64_t &rawShaderFlag,
                                  hlsl::DxilFunctionProps &props,
                                  uint32_t &autoBindingSpace);
  
    // ViewId state.
    void EmitDxilViewIdState(std::vector<unsigned> &SerializedState);
    void LoadDxilViewIdState(std::vector<unsigned> &SerializedState);
    // Control flow hints.
    static llvm37::MDNode *EmitControlFlowHints(llvm37::LLVM37Context &Ctx, std::vector<DXIL::ControlFlowHint> &hints);
    static unsigned GetControlFlowHintMask(const llvm37::Instruction *I);
    static bool HasControlFlowHintToPreventFlatten(const llvm37::Instruction *I);
  
    // Subobjects
    void EmitSubobjects(const DxilSubobjects &Subobjects);
    void LoadSubobjects(DxilSubobjects &Subobjects);
    llvm37::Metadata *EmitSubobject(const DxilSubobject &obj);
    void LoadSubobject(const llvm37::MDNode &MDO, DxilSubobjects &Subobjects);
  
    // Extra metadata present
    bool HasExtraMetadata() { return m_bExtraMetadata; }
  
    // Instruction Counters
    void EmitDxilCounters(const DxilCounters &counters);
    void LoadDxilCounters(DxilCounters &counters) const;
  
    // Shader specific.
  private:
    llvm37::MDTuple *EmitDxilGSState(DXIL::InputPrimitive Primitive, unsigned MaxVertexCount, 
                                   unsigned ActiveStreamMask, DXIL::PrimitiveTopology StreamPrimitiveTopology,
                                   unsigned GSInstanceCount);
    void LoadDxilGSState(const llvm37::MDOperand &MDO, DXIL::InputPrimitive &Primitive, unsigned &MaxVertexCount, 
                         unsigned &ActiveStreamMask, DXIL::PrimitiveTopology &StreamPrimitiveTopology,
                         unsigned &GSInstanceCount);
  
    llvm37::MDTuple *EmitDxilDSState(DXIL::TessellatorDomain Domain, unsigned InputControlPointCount);
    void LoadDxilDSState(const llvm37::MDOperand &MDO, DXIL::TessellatorDomain &Domain, unsigned &InputControlPointCount);
  
    llvm37::MDTuple *EmitDxilHSState(llvm37::Function *pPatchConstantFunction,
                                   unsigned InputControlPointCount,
                                   unsigned OutputControlPointCount,
                                   DXIL::TessellatorDomain TessDomain,
                                   DXIL::TessellatorPartitioning TessPartitioning,
                                   DXIL::TessellatorOutputPrimitive TessOutputPrimitive,
                                   float MaxTessFactor);
    void LoadDxilHSState(const llvm37::MDOperand &MDO,
                         llvm37::Function *&pPatchConstantFunction,
                         unsigned &InputControlPointCount,
                         unsigned &OutputControlPointCount,
                         DXIL::TessellatorDomain &TessDomain,
                         DXIL::TessellatorPartitioning &TessPartitioning,
                         DXIL::TessellatorOutputPrimitive &TessOutputPrimitive,
                         float &MaxTessFactor);
  
    llvm37::MDTuple *EmitDxilMSState(const unsigned *NumThreads,
                                   unsigned MaxVertexCount,
                                   unsigned MaxPrimitiveCount,
                                   DXIL::MeshOutputTopology OutputTopology,
                                   unsigned payloadSizeInBytes);
    void LoadDxilMSState(const llvm37::MDOperand &MDO,
                         unsigned *NumThreads,
                         unsigned &MaxVertexCount,
                         unsigned &MaxPrimitiveCount,
                         DXIL::MeshOutputTopology &OutputTopology,
                         unsigned &payloadSizeInBytes);
  
    llvm37::MDTuple *EmitDxilASState(const unsigned *NumThreads, unsigned payloadSizeInBytes);
    void LoadDxilASState(const llvm37::MDOperand &MDO, unsigned *NumThreads, unsigned &payloadSizeInBytes);
  
    void AddCounterIfNonZero(uint32_t value, llvm37::StringRef name, std::vector<llvm37::Metadata*> &MDVals);
    void LoadCounterMD(const llvm37::MDOperand &MDName, const llvm37::MDOperand &MDValue, DxilCounters &counters) const;
  public:
    // Utility functions.
    static bool IsKnownNamedMetaData(const llvm37::NamedMDNode &Node);
    static bool IsKnownMetadataID(llvm37::LLVM37Context &Ctx, unsigned ID);
    static void GetKnownMetadataIDs(llvm37::LLVM37Context &Ctx, llvm37::SmallVectorImpl<unsigned> *pIDs);
    static void combineDxilMetadata(llvm37::Instruction *K, const llvm37::Instruction *J);
    static llvm37::ConstantAsMetadata *Int32ToConstMD(int32_t v, llvm37::LLVM37Context &Ctx);
    llvm37::ConstantAsMetadata *Int32ToConstMD(int32_t v);
    static llvm37::ConstantAsMetadata *Uint32ToConstMD(unsigned v, llvm37::LLVM37Context &Ctx);
    llvm37::ConstantAsMetadata *Uint32ToConstMD(unsigned v);
    static llvm37::ConstantAsMetadata *Uint64ToConstMD(uint64_t v, llvm37::LLVM37Context &Ctx);
    llvm37::ConstantAsMetadata *Uint64ToConstMD(uint64_t v);
    llvm37::ConstantAsMetadata *Int8ToConstMD(int8_t v);
    llvm37::ConstantAsMetadata *Uint8ToConstMD(uint8_t v);
    static llvm37::ConstantAsMetadata *BoolToConstMD(bool v, llvm37::LLVM37Context &Ctx);
    llvm37::ConstantAsMetadata *BoolToConstMD(bool v);
    llvm37::ConstantAsMetadata *FloatToConstMD(float v);
    static int32_t ConstMDToInt32(const llvm37::MDOperand &MDO);
    static unsigned ConstMDToUint32(const llvm37::MDOperand &MDO);
    static uint64_t ConstMDToUint64(const llvm37::MDOperand &MDO);
    static int8_t ConstMDToInt8(const llvm37::MDOperand &MDO);
    static uint8_t ConstMDToUint8(const llvm37::MDOperand &MDO);
    static bool ConstMDToBool(const llvm37::MDOperand &MDO);
    static float ConstMDToFloat(const llvm37::MDOperand &MDO);
    static std::string StringMDToString(const llvm37::MDOperand &MDO);
    static llvm37::StringRef StringMDToStringRef(const llvm37::MDOperand &MDO);
    static llvm37::Value *ValueMDToValue(const llvm37::MDOperand &MDO);
    llvm37::MDTuple *Uint32VectorToConstMDTuple(const std::vector<unsigned> &Vec);
    void ConstMDTupleToUint32Vector(llvm37::MDTuple *pTupleMD, std::vector<unsigned> &Vec);
    static bool IsMarkedPrecise(const llvm37::Instruction *inst);
    static void MarkPrecise(llvm37::Instruction *inst);
    static bool IsMarkedNonUniform(const llvm37::Instruction *inst);
    static void MarkNonUniform(llvm37::Instruction *inst);
    static bool GetVariableDebugLayout(llvm37::DbgDeclareInst *inst,
      unsigned &StartOffsetInBits, std::vector<DxilDIArrayDim> &ArrayDims);
    static void SetVariableDebugLayout(llvm37::DbgDeclareInst *inst,
      unsigned StartOffsetInBits, const std::vector<DxilDIArrayDim> &ArrayDims);
    static void CopyMetadata(llvm37::Instruction &I, llvm37::Instruction &SrcInst, llvm37::ArrayRef<unsigned>WL = llvm37::ArrayRef<unsigned>());
  
  private:
    llvm37::LLVM37Context &m_Ctx;
    llvm37::Module *m_pModule;
    const ShaderModel *m_pSM;
    std::unique_ptr<ExtraPropertyHelper> m_ExtraPropertyHelper;
    unsigned m_ValMajor, m_ValMinor;        // Reported validation version in DXIL
    unsigned m_MinValMajor, m_MinValMinor;  // Minimum validation version dictated by shader model
  
    // Non-fatal if extra metadata is found, but will fail validation.
    // This is how metadata can be exteneded.
    bool m_bExtraMetadata;
  };
  
  
  /// Use this class to manipulate metadata of extra metadata record properties that are specific to DXIL.
  class DxilExtraPropertyHelper : public DxilMDHelper::ExtraPropertyHelper {
  public:
    DxilExtraPropertyHelper(llvm37::Module *pModule);
    virtual ~DxilExtraPropertyHelper() {}
  
    virtual void EmitSRVProperties(const DxilResource &SRV, std::vector<llvm37::Metadata *> &MDVals);
    virtual void LoadSRVProperties(const llvm37::MDOperand &MDO, DxilResource &SRV);
  
    virtual void EmitUAVProperties(const DxilResource &UAV, std::vector<llvm37::Metadata *> &MDVals);
    virtual void LoadUAVProperties(const llvm37::MDOperand &MDO, DxilResource &UAV);
  
    virtual void EmitCBufferProperties(const DxilCBuffer &CB, std::vector<llvm37::Metadata *> &MDVals);
    virtual void LoadCBufferProperties(const llvm37::MDOperand &MDO, DxilCBuffer &CB);
  
    virtual void EmitSamplerProperties(const DxilSampler &S, std::vector<llvm37::Metadata *> &MDVals);
    virtual void LoadSamplerProperties(const llvm37::MDOperand &MDO, DxilSampler &S);
  
    virtual void EmitSignatureElementProperties(const DxilSignatureElement &SE, std::vector<llvm37::Metadata *> &MDVals);
    virtual void LoadSignatureElementProperties(const llvm37::MDOperand &MDO, DxilSignatureElement &SE);
  };
  
  } // namespace hlsl
  