瀏覽代碼

Merge pull request #2416 from tex3d/sep-reflect

Merge separate refleciton and validator 1.4 compatibility fixes
Tex Riddell 6 年之前
父節點
當前提交
114080aaec
共有 68 個文件被更改,包括 1587 次插入492 次删除
  1. 0 1
      docs/DXIL.rst
  2. 12 0
      include/dxc/DXIL/DxilConstants.h
  3. 8 0
      include/dxc/DXIL/DxilMetadataHelper.h
  4. 1 1
      include/dxc/DXIL/DxilModule.h
  5. 1 0
      include/dxc/DXIL/DxilOperations.h
  6. 6 0
      include/dxc/DXIL/DxilSignatureElement.h
  7. 4 0
      include/dxc/DXIL/DxilTypeSystem.h
  8. 6 5
      include/dxc/DxilContainer/DxilContainer.h
  9. 2 1
      include/dxc/DxilContainer/DxilContainerAssembler.h
  10. 0 2
      include/dxc/DxilContainer/DxilRuntimeReflection.h
  11. 1 63
      include/dxc/DxilContainer/DxilRuntimeReflection.inl
  12. 1 0
      include/dxc/HLSL/DxilLinker.h
  13. 0 1
      include/dxc/HLSL/DxilValidation.h
  14. 3 0
      include/dxc/Support/HLSLOptions.h
  15. 17 7
      include/dxc/Support/HLSLOptions.td
  16. 1 1
      lib/Analysis/IPA/CallGraph.cpp
  17. 47 13
      lib/DXIL/DxilMetadataHelper.cpp
  18. 82 16
      lib/DXIL/DxilModule.cpp
  19. 9 0
      lib/DXIL/DxilOperations.cpp
  20. 22 0
      lib/DXIL/DxilShaderFlags.cpp
  21. 11 1
      lib/DXIL/DxilSignatureElement.cpp
  22. 6 2
      lib/DXIL/DxilTypeSystem.cpp
  23. 50 0
      lib/DxcSupport/HLSLOptions.cpp
  24. 147 31
      lib/DxilContainer/DxilContainerAssembler.cpp
  25. 154 1
      lib/HLSL/DxilCondenseResources.cpp
  26. 212 132
      lib/HLSL/DxilContainerReflection.cpp
  27. 112 3
      lib/HLSL/DxilPreparePasses.cpp
  28. 4 9
      lib/HLSL/DxilValidation.cpp
  29. 2 8
      lib/Transforms/IPO/GlobalDCE.cpp
  30. 16 9
      tools/clang/lib/CodeGen/CGHLSLMS.cpp
  31. 3 4
      tools/clang/test/CodeGenHLSL/batch/compiler_options/Qstrip_reflect.hlsl
  32. 3 4
      tools/clang/test/CodeGenHLSL/batch/compiler_options/Qstrip_reflect_struct_buf.hlsl
  33. 1 1
      tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/optimized2.hlsl
  34. 1 1
      tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/optimized3.hlsl
  35. 1 1
      tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/prefix_stable2.hlsl
  36. 1 1
      tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/prefix_stable3.hlsl
  37. 2 2
      tools/clang/test/CodeGenHLSL/batch/debug/locals/scalarized_vector.hlsl
  38. 2 2
      tools/clang/test/CodeGenHLSL/batch/debug/misc/share_mem_dbg.hlsl
  39. 2 2
      tools/clang/test/CodeGenHLSL/batch/debug/types/struct_resource_numerical.hlsl
  40. 1 1
      tools/clang/test/CodeGenHLSL/batch/declarations/resources/constant_buffers/array1.hlsl
  41. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/cb_sizes.hlsl
  42. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/cbuf-usage-lib.hlsl
  43. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/empty_struct2.hlsl
  44. 125 0
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/lib_global.hlsl
  45. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/reflect-lib-1.hlsl
  46. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/structured_buffer_layout.hlsl
  47. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/sig-bool-as-uint.hlsl
  48. 1 1
      tools/clang/test/CodeGenHLSL/batch/misc/static_const_global.hlsl
  49. 1 1
      tools/clang/test/CodeGenHLSL/batch/shader_stages/raytracing/subobjects_raytracingPipelineConfig1.hlsl
  50. 1 1
      tools/clang/test/CodeGenHLSL/batch/validation/rawbufferstore_uav.hlsl
  51. 4 1
      tools/clang/test/CodeGenHLSL/lib_global.hlsl
  52. 1 1
      tools/clang/tools/dxcompiler/dxcassembler.cpp
  53. 33 3
      tools/clang/tools/dxcompiler/dxcdisassembler.cpp
  54. 8 0
      tools/clang/tools/dxcompiler/dxclinker.cpp
  55. 20 11
      tools/clang/tools/dxcompiler/dxcompilerobj.cpp
  56. 2 1
      tools/clang/tools/dxcompiler/dxcontainerbuilder.cpp
  57. 19 0
      tools/clang/tools/dxcompiler/dxcutil.cpp
  58. 1 0
      tools/clang/unittests/HLSL/CMakeLists.txt
  59. 9 1
      tools/clang/unittests/HLSL/CompilerTest.cpp
  60. 30 0
      tools/clang/unittests/HLSL/DxcTestUtils.cpp
  61. 4 0
      tools/clang/unittests/HLSL/DxcTestUtils.h
  62. 73 12
      tools/clang/unittests/HLSL/DxilContainerTest.cpp
  63. 92 1
      tools/clang/unittests/HLSL/DxilModuleTest.cpp
  64. 55 31
      tools/clang/unittests/HLSL/FileCheckerTest.cpp
  65. 30 4
      tools/clang/unittests/HLSL/LinkerTest.cpp
  66. 2 0
      tools/clang/unittests/HLSL/OptimizerTest.cpp
  67. 116 90
      tools/clang/unittests/HLSL/ValidationTest.cpp
  68. 0 1
      utils/hct/hctdb.py

+ 0 - 1
docs/DXIL.rst

@@ -3075,7 +3075,6 @@ META.DUPLICATESYSVALUE                    System value may only appear once in s
 META.ENTRYFUNCTION                        entrypoint not found
 META.FLAGSUSAGE                           Flags must match usage
 META.FORCECASEONSWITCH                    Attribute forcecase only works for switch
-META.FUNCTIONANNOTATION                   Cannot find function annotation for %0
 META.GLCNOTONAPPENDCONSUME                globallycoherent cannot be used with append/consume buffers
 META.INTEGERINTERPMODE                    Interpolation mode on integer must be Constant
 META.INTERPMODEINONEROW                   Interpolation mode must be identical for all elements packed into the same row.

+ 12 - 0
include/dxc/DXIL/DxilConstants.h

@@ -35,6 +35,17 @@ namespace DXIL {
   inline unsigned GetCurrentDxilVersion() { return MakeDxilVersion(kDxilMajor, kDxilMinor); }
   inline unsigned GetDxilVersionMajor(unsigned DxilVersion) { return (DxilVersion >> 8) & 0xFF; }
   inline unsigned GetDxilVersionMinor(unsigned DxilVersion) { return DxilVersion & 0xFF; }
+  // Return positive if v1 > v2, negative if v1 < v2, zero if equal
+  inline int CompareVersions(unsigned Major1, unsigned Minor1, unsigned Major2, unsigned Minor2) {
+    if (Major1 != Major2) {
+      // Special case for Major == 0 (latest/unbound)
+      if (Major1 == 0 || Major2 == 0) return Major1 > 0 ? -1 : 1;
+      return Major1 < Major2 ? -1 : 1;
+    }
+    if (Minor1 < Minor2) return -1;
+    if (Minor1 > Minor2) return 1;
+    return 0;
+  }
 
   // Shader flags.
   const unsigned kDisableOptimizations          = 0x00000001; // D3D11_1_SB_GLOBAL_FLAG_SKIP_OPTIMIZATION
@@ -1340,6 +1351,7 @@ namespace DXIL {
     AllowLocalDependenciesOnExternalDefinitions = 0x1,
     AllowExternalDependenciesOnLocalDefinitions = 0x2,
     AllowStateObjectAdditions                   = 0x4,
+    ValidMask_1_4                               = 0x3,
     ValidMask                                   = 0x7,
   };
 

+ 8 - 0
include/dxc/DXIL/DxilMetadataHelper.h

@@ -128,6 +128,7 @@ public:
   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[];
@@ -192,6 +193,7 @@ public:
   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
@@ -293,6 +295,10 @@ public:
   protected:
     llvm::LLVMContext &m_Ctx;
     llvm::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
   };
 
 public:
@@ -484,6 +490,8 @@ private:
   llvm::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
 };
 
 

+ 1 - 1
include/dxc/DXIL/DxilModule.h

@@ -189,7 +189,7 @@ public:
   void ResetOP(hlsl::OP *hlslOP);
   void ResetEntryPropsMap(DxilEntryPropsMap &&PropMap);
 
-  void StripReflection();
+  bool StripReflection();
   void StripDebugRelatedCode();
   llvm::DebugInfoFinder &GetOrCreateDebugInfoFinder();
 

+ 1 - 0
include/dxc/DXIL/DxilOperations.h

@@ -109,6 +109,7 @@ public:
                                        unsigned &major, unsigned &minor,
                                        unsigned &mask);
   static void GetMinShaderModelAndMask(const llvm::CallInst *CI, bool bWithTranslation,
+                                       unsigned valMajor, unsigned valMinor,
                                        unsigned &major, unsigned &minor,
                                        unsigned &mask);
 

+ 6 - 0
include/dxc/DXIL/DxilSignatureElement.h

@@ -89,6 +89,9 @@ public:
   unsigned GetDynIdxCompMask() const;
   void SetDynIdxCompMask(unsigned DynIdxCompMask);
 
+  uint8_t GetUsageMask() const;
+  void SetUsageMask(unsigned UsageMask);
+
 protected:
   DXIL::SigPointKind m_sigPointKind;
   const Semantic *m_pSemantic;
@@ -105,6 +108,9 @@ protected:
   int m_StartCol;
   unsigned m_OutputStream;
   unsigned m_DynIdxCompMask;
+  // UsageMask is meant to match the signature usage mask, used for validation:
+  // for output: may-write, for input: always-reads
+  unsigned m_UsageMask;
 };
 
 } // namespace hlsl

+ 4 - 0
include/dxc/DXIL/DxilTypeSystem.h

@@ -79,6 +79,9 @@ public:
   const std::string &GetFieldName() const;
   void SetFieldName(const std::string &FieldName);
 
+  bool IsCBVarUsed() const;
+  void SetCBVarUsed(bool used);
+
 private:
   bool m_bPrecise;
   CompType m_CompType;
@@ -88,6 +91,7 @@ private:
   std::string m_Semantic;
   InterpolationMode m_InterpMode;
   std::string m_FieldName;
+  bool m_bCBufferVarUsed; // true if this field represents a top level variable in CB structure, and it is used.
 };
 
 class DxilTemplateArgAnnotation : DxilFieldAnnotation {

+ 6 - 5
include/dxc/DxilContainer/DxilContainer.h

@@ -404,11 +404,12 @@ inline bool GetDxilShaderDebugName(const DxilPartHeader *pDebugNamePart,
 }
 
 enum class SerializeDxilFlags : uint32_t {
-  None = 0,                         // No flags defined.
-  IncludeDebugInfoPart = 1,         // Include the debug info part in the container.
-  IncludeDebugNamePart = 2,         // Include the debug name part in the container.
-  DebugNameDependOnSource = 4,      // Make the debug name depend on source (and not just final module).
-  StripReflectionFromDxilPart = 8,  // Strip Reflection info from DXIL part.
+  None                        = 0,      // No flags defined.
+  IncludeDebugInfoPart        = 1 << 0, // Include the debug info part in the container.
+  IncludeDebugNamePart        = 1 << 1, // Include the debug name part in the container.
+  DebugNameDependOnSource     = 1 << 2, // Make the debug name depend on source (and not just final module).
+  StripReflectionFromDxilPart = 1 << 3, // Strip Reflection info from DXIL part.
+  IncludeReflectionPart       = 1 << 4, // Include reflection in STAT part.
 };
 inline SerializeDxilFlags& operator |=(SerializeDxilFlags& l, const SerializeDxilFlags& r) {
   l = static_cast<SerializeDxilFlags>(static_cast<int>(l) | static_cast<int>(r));

+ 2 - 1
include/dxc/DxilContainer/DxilContainerAssembler.h

@@ -51,7 +51,8 @@ void SerializeDxilContainerForModule(hlsl::DxilModule *pModule,
                                      AbstractMemoryStream *pStream,
                                      llvm::StringRef DebugName,
                                      SerializeDxilFlags Flags,
-                                     DxilShaderHash *pShaderHashOut = nullptr);
+                                     DxilShaderHash *pShaderHashOut = nullptr,
+                                     AbstractMemoryStream *pReflectionStreamOut = nullptr);
 void SerializeDxilContainerForRootSignature(hlsl::RootSignatureHandle *pRootSigHandle,
                                      AbstractMemoryStream *pStream);
 

+ 0 - 2
include/dxc/DxilContainer/DxilRuntimeReflection.h

@@ -601,8 +601,6 @@ public:
   DxilRuntimeData(const void *ptr, size_t size);
   // initializing reader from RDAT. return true if no error has occured.
   bool InitFromRDAT(const void *pRDAT, size_t size);
-  // read prerelease data:
-  bool InitFromRDAT_Prerelease(const void *pRDAT, size_t size);
   FunctionTableReader *GetFunctionTableReader();
   ResourceTableReader *GetResourceTableReader();
   SubobjectTableReader *GetSubobjectTableReader();

+ 1 - 63
include/dxc/DxilContainer/DxilRuntimeReflection.inl

@@ -112,8 +112,7 @@ bool DxilRuntimeData::InitFromRDAT(const void *pRDAT, size_t size) {
       CheckedReader Reader(pRDAT, size);
       RuntimeDataHeader RDATHeader = Reader.Read<RuntimeDataHeader>();
       if (RDATHeader.Version < RDAT_Version_10) {
-        // Prerelease version, fallback to that Init
-        return InitFromRDAT_Prerelease(pRDAT, size);
+        return false;
       }
       const uint32_t *offsets = Reader.ReadArray<uint32_t>(RDATHeader.PartCount);
       for (uint32_t i = 0; i < RDATHeader.PartCount; ++i) {
@@ -172,67 +171,6 @@ bool DxilRuntimeData::InitFromRDAT(const void *pRDAT, size_t size) {
   return false;
 }
 
-bool DxilRuntimeData::InitFromRDAT_Prerelease(const void *pRDAT, size_t size) {
-  enum class RuntimeDataPartType_Prerelease : uint32_t {
-    Invalid = 0,
-    String,
-    Function,
-    Resource,
-    Index
-  };
-  struct RuntimeDataTableHeader_Prerelease {
-    uint32_t tableType; // RuntimeDataPartType
-    uint32_t size;
-    uint32_t offset;
-  };
-  if (pRDAT) {
-    try {
-      CheckedReader Reader(pRDAT, size);
-      uint32_t partCount = Reader.Read<uint32_t>();
-      const RuntimeDataTableHeader_Prerelease *tableHeaders =
-        Reader.ReadArray<RuntimeDataTableHeader_Prerelease>(partCount);
-      for (uint32_t i = 0; i < partCount; ++i) {
-        uint32_t partSize = tableHeaders[i].size;
-        Reader.Advance(tableHeaders[i].offset);
-        CheckedReader PR(Reader.ReadArray<char>(partSize), partSize);
-        switch ((RuntimeDataPartType_Prerelease)(tableHeaders[i].tableType)) {
-        case RuntimeDataPartType_Prerelease::String: {
-          m_StringReader = StringTableReader(
-            PR.ReadArray<char>(partSize), partSize);
-          break;
-        }
-        case RuntimeDataPartType_Prerelease::Index: {
-          uint32_t count = partSize / sizeof(uint32_t);
-          m_IndexTableReader = IndexTableReader(
-            PR.ReadArray<uint32_t>(count), count);
-          break;
-        }
-        case RuntimeDataPartType_Prerelease::Resource: {
-          uint32_t count = partSize / sizeof(RuntimeDataResourceInfo);
-          m_ResourceTableReader.SetResourceInfo(PR.ReadArray<char>(partSize),
-            count, sizeof(RuntimeDataResourceInfo));
-          break;
-        }
-        case RuntimeDataPartType_Prerelease::Function: {
-          uint32_t count = partSize / sizeof(RuntimeDataFunctionInfo);
-          m_FunctionTableReader.SetFunctionInfo(PR.ReadArray<char>(partSize),
-            count, sizeof(RuntimeDataFunctionInfo));
-          break;
-        }
-        default:
-          return false; // There should be no unrecognized parts
-        }
-      }
-      return true;
-    } catch(CheckedReader::exception e) {
-      // TODO: error handling
-      //throw hlsl::Exception(DXC_E_MALFORMED_CONTAINER, e.what());
-      return false;
-    }
-  }
-  return false;
-}
-
 FunctionTableReader *DxilRuntimeData::GetFunctionTableReader() {
   return &m_FunctionTableReader;
 }

+ 1 - 0
include/dxc/HLSL/DxilLinker.h

@@ -37,6 +37,7 @@ public:
   virtual ~DxilLinker() {}
   static DxilLinker *CreateLinker(llvm::LLVMContext &Ctx, unsigned valMajor, unsigned valMinor);
 
+  void SetValidatorVersion(unsigned valMajor, unsigned valMinor) { m_valMajor = valMajor, m_valMinor = valMinor; }
   virtual bool HasLibNameRegistered(llvm::StringRef name) = 0;
   virtual bool RegisterLib(llvm::StringRef name,
                            std::unique_ptr<llvm::Module> pModule,

+ 0 - 1
include/dxc/HLSL/DxilValidation.h

@@ -152,7 +152,6 @@ enum class ValidationRule : unsigned {
   MetaEntryFunction, // entrypoint not found
   MetaFlagsUsage, // Flags must match usage
   MetaForceCaseOnSwitch, // Attribute forcecase only works for switch
-  MetaFunctionAnnotation, // Cannot find function annotation for %0
   MetaGlcNotOnAppendConsume, // globallycoherent cannot be used with append/consume buffers
   MetaIntegerInterpMode, // Interpolation mode on integer must be Constant
   MetaInterpModeInOneRow, // Interpolation mode must be identical for all elements packed into the same row.

+ 3 - 0
include/dxc/Support/HLSLOptions.h

@@ -154,6 +154,8 @@ public:
   bool StripRootSignature = false; // OPT_Qstrip_rootsignature
   bool StripPrivate = false; // OPT_Qstrip_priv
   bool StripReflection = false; // OPT_Qstrip_reflect
+  bool KeepReflectionInDxil = false; // OPT_Qkeep_reflect_in_dxil
+  bool StripReflectionFromDxil = false; // OPT_Qstrip_reflect_from_dxil
   bool ExtractRootSignature = false; // OPT_extractrootsignature
   bool DisassembleColorCoded = false; // OPT_Cc
   bool DisassembleInstNumbers = false; //OPT_Ni
@@ -164,6 +166,7 @@ public:
   unsigned long AutoBindingSpace = UINT_MAX; // OPT_auto_binding_space
   bool ExportShadersOnly = false; // OPT_export_shaders_only
   bool ResMayAlias = false; // OPT_res_may_alias
+  unsigned long ValVerMajor = UINT_MAX, ValVerMinor = UINT_MAX; // OPT_validator_version
 
   bool IsRootSignatureProfile();
   bool IsLibraryProfile();

+ 17 - 7
include/dxc/Support/HLSLOptions.td

@@ -242,6 +242,8 @@ def export_shaders_only : Flag<["-", "/"], "export-shaders-only">, Group<hlslcom
   HelpText<"Only export shaders when compiling a library">;
 def default_linkage : Separate<["-", "/"], "default-linkage">, Group<hlslcomp_Group>, Flags<[CoreOption]>,
   HelpText<"Set default linkage for non-shader functions when compiling or linking to a library target (internal, external)">;
+def validator_version : Separate<["-", "/"], "validator-version">, Group<hlslcomp_Group>, Flags<[CoreOption, HelpHidden]>,
+  HelpText<"Override validator version for module.  Format: <major.minor> ; Default: DXIL.dll version or current internal version.">;
 
 // SPIRV Change Starts
 def spirv : Flag<["-"], "spirv">, Group<spirv_Group>, Flags<[CoreOption, DriverOption]>,
@@ -328,12 +330,12 @@ def Gis : Flag<["-", "/"], "Gis">, HelpText<"Force IEEE strictness">, Flags<[Cor
 
 def denorm : JoinedOrSeparate<["-", "/"], "denorm">, HelpText<"select denormal value options (any, preserve, ftz). any is the default.">, Flags<[CoreOption]>, Group<hlslcomp_Group>;
 
-def Fo : JoinedOrSeparate<["-", "/"], "Fo">, MetaVarName<"<file>">, HelpText<"Output object file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
+def Fo : JoinedOrSeparate<["-", "/"], "Fo">, MetaVarName<"<file>">, HelpText<"Output object file">, Flags<[CoreOption, DriverOption]>, Group<hlslcomp_Group>;
 // def Fl : JoinedOrSeparate<["-", "/"], "Fl">, MetaVarName<"<file>">, HelpText<"Output a library">;
 def Fc : JoinedOrSeparate<["-", "/"], "Fc">, MetaVarName<"<file>">, HelpText<"Output assembly code listing file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
 //def Fx : JoinedOrSeparate<["-", "/"], "Fx">, MetaVarName<"<file>">, HelpText<"Output assembly code and hex listing file">;
 def Fh : JoinedOrSeparate<["-", "/"], "Fh">, MetaVarName<"<file>">, HelpText<"Output header file containing object code">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
-def Fe : JoinedOrSeparate<["-", "/"], "Fe">, MetaVarName<"<file>">, HelpText<"Output warnings and errors to the given file">, Flags<[DriverOption]>, Group<hlslcomp_Group>;
+def Fe : JoinedOrSeparate<["-", "/"], "Fe">, MetaVarName<"<file>">, HelpText<"Output warnings and errors to the given file">, Flags<[CoreOption, DriverOption]>, Group<hlslcomp_Group>;
 def Fd : JoinedOrSeparate<["-", "/"], "Fd">, MetaVarName<"<file>">,
   HelpText<"Write debug information to the given file, or automatically named file in directory when ending in '\\'">,
   Flags<[CoreOption, DriverOption]>, Group<hlslcomp_Group>;
@@ -344,28 +346,36 @@ def No : Flag<["-", "/"], "No">, HelpText<"Output instruction byte offsets in as
 def Lx : Flag<["-", "/"], "Lx">, HelpText<"Output hexadecimal literals">, Group<hlslcomp_Group>, Flags<[DriverOption]>;
 
 // In place of 'E' for clang; fxc uses 'E' for entry point.
-def P : Separate<["-", "/"], "P">, Flags<[DriverOption]>, Group<hlslutil_Group>,
+def P : Separate<["-", "/"], "P">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Preprocess to file (must be used alone)">;
 
 // @<file> - options response file
 
 def dumpbin : Flag<["-", "/"], "dumpbin">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Load a binary file rather than compiling">;
-def Qstrip_reflect : Flag<["-", "/"], "Qstrip_reflect">, Flags<[CoreOption]>, Group<hlslutil_Group>,
+def Qstrip_reflect : Flag<["-", "/"], "Qstrip_reflect">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip reflection data from shader bytecode  (must be used with /Fo <file>)">;
-def Qstrip_debug : Flag<["-", "/"], "Qstrip_debug">, Flags<[CoreOption]>, Group<hlslutil_Group>,
+def Qstrip_debug : Flag<["-", "/"], "Qstrip_debug">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip debug information from 4_0+ shader bytecode  (must be used with /Fo <file>)">;
 def Qembed_debug : Flag<["-", "/"], "Qembed_debug">, Flags<[CoreOption]>, Group<hlslutil_Group>,
   HelpText<"Embed PDB in shader container (must be used with /Zi)">;
 def Qstrip_priv : Flag<["-", "/"], "Qstrip_priv">, Flags<[DriverOption]>, Group<hlslutil_Group>,
   HelpText<"Strip private data from shader bytecode  (must be used with /Fo <file>)">;
 
-def Qstrip_rootsignature : Flag<["-", "/"], "Qstrip_rootsignature">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Strip root signature data from shader bytecode  (must be used with /Fo <file>)">;
-def setrootsignature     : JoinedOrSeparate<["-", "/"], "setrootsignature">,     MetaVarName<"<file>">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Attach root signature to shader bytecode">;
+def Qstrip_rootsignature : Flag<["-", "/"], "Qstrip_rootsignature">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>, HelpText<"Strip root signature data from shader bytecode  (must be used with /Fo <file>)">;
+def setrootsignature     : JoinedOrSeparate<["-", "/"], "setrootsignature">,     MetaVarName<"<file>">, Flags<[CoreOption, DriverOption]>, Group<hlslutil_Group>, HelpText<"Attach root signature to shader bytecode">;
 def extractrootsignature : Flag<["-", "/"], "extractrootsignature">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Extract root signature from shader bytecode (must be used with /Fo <file>)">;
 def verifyrootsignature  : JoinedOrSeparate<["-", "/"], "verifyrootsignature">,  MetaVarName<"<file>">, Flags<[DriverOption]>, Group<hlslutil_Group>, HelpText<"Verify shader bytecode with root signature">;
 def force_rootsig_ver    : JoinedOrSeparate<["-", "/"], "force_rootsig_ver">,    Flags<[CoreOption]>, MetaVarName<"<profile>">, Group<hlslcomp_Group>, HelpText<"force root signature version (rootsig_1_1 if omitted)">;
 
+// Temporary TEST options, until reflection inside DXIL part can always be stripped
+def Qkeep_reflect_in_dxil : Flag<["-", "/"], "Qkeep_reflect_in_dxil">,
+  Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
+  HelpText<"Keep reflection data in shader bytecode">;
+def Qstrip_reflect_from_dxil : Flag<["-", "/"], "Qstrip_reflect_from_dxil">,
+  Flags<[CoreOption, HelpHidden]>, Group<hlslutil_Group>,
+  HelpText<"Strip reflection data from shader bytecode  (must be used with /Fo <file>)">;
+
 /*
 def shtemplate : JoinedOrSeparate<["-", "/"], "shtemplate">, MetaVarName<"<file>">, Group<hlslcomp_Group>,
   HelpText<"Template shader file for merging/matching resources">;

+ 1 - 1
lib/Analysis/IPA/CallGraph.cpp

@@ -159,7 +159,7 @@ Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
   delete CGN;                       // Delete the call graph node for this func
   FunctionMap.erase(F);             // Remove the call graph node from the map
 
-  if (M.HasHLModule()) M.GetHLModule().RemoveFunction(F); // HLSL Change
+  M.CallRemoveGlobalHook(F); // HLSL Change
 
   M.getFunctionList().remove(F);
   return F;

+ 47 - 13
lib/DXIL/DxilMetadataHelper.cpp

@@ -77,7 +77,12 @@ DxilMDHelper::DxilMDHelper(Module *pModule, std::unique_ptr<ExtraPropertyHelper>
 : m_Ctx(pModule->getContext())
 , m_pModule(pModule)
 , m_pSM(nullptr)
-, m_ExtraPropertyHelper(std::move(EPH)) {
+, m_ExtraPropertyHelper(std::move(EPH))
+, m_ValMajor(1)
+, m_ValMinor(0)
+, m_MinValMajor(1)
+, m_MinValMinor(0)
+{
 }
 
 DxilMDHelper::~DxilMDHelper() {
@@ -85,6 +90,17 @@ DxilMDHelper::~DxilMDHelper() {
 
 void DxilMDHelper::SetShaderModel(const ShaderModel *pSM) {
   m_pSM = pSM;
+  m_pSM->GetMinValidatorVersion(m_MinValMajor, m_MinValMinor);
+  if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, m_MinValMajor, m_MinValMinor) < 0) {
+    m_ValMajor = m_MinValMajor;
+    m_ValMinor = m_MinValMinor;
+  }
+  if (m_ExtraPropertyHelper) {
+    m_ExtraPropertyHelper->m_ValMajor = m_ValMajor;
+    m_ExtraPropertyHelper->m_ValMinor = m_ValMinor;
+    m_ExtraPropertyHelper->m_MinValMajor = m_MinValMajor;
+    m_ExtraPropertyHelper->m_MinValMinor = m_MinValMinor;
+  }
 }
 
 const ShaderModel *DxilMDHelper::GetShaderModel() const {
@@ -135,6 +151,8 @@ void DxilMDHelper::EmitValidatorVersion(unsigned Major, unsigned Minor) {
   MDVals[kDxilVersionMinorIdx] = Uint32ToConstMD(Minor);
 
   pDxilValidatorVersionMD->addOperand(MDNode::get(m_Ctx, MDVals));
+
+  m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use
 }
 
 void DxilMDHelper::LoadValidatorVersion(unsigned &Major, unsigned &Minor) {
@@ -144,6 +162,7 @@ void DxilMDHelper::LoadValidatorVersion(unsigned &Major, unsigned &Minor) {
     // If no validator version metadata, assume 1.0
     Major = 1;
     Minor = 0;
+    m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use
     return;
   }
 
@@ -154,6 +173,7 @@ void DxilMDHelper::LoadValidatorVersion(unsigned &Major, unsigned &Minor) {
 
   Major = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMajorIdx));
   Minor = ConstMDToUint32(pVersionMD->getOperand(kDxilVersionMinorIdx));
+  m_ValMajor = Major; m_ValMinor = Minor; // Keep these for later use
 }
 
 //
@@ -170,6 +190,8 @@ void DxilMDHelper::EmitDxilShaderModel(const ShaderModel *pSM) {
   MDVals[kDxilShaderModelMinorIdx] = Uint32ToConstMD(pSM->GetMinor());
 
   pShaderModelNamedMD->addOperand(MDNode::get(m_Ctx, MDVals));
+
+  SetShaderModel(pSM);
 }
 
 void DxilMDHelper::LoadDxilShaderModel(const ShaderModel *&pSM) {
@@ -792,11 +814,12 @@ void DxilMDHelper::LoadDxilTemplateArgAnnotation(const llvm::MDOperand &MDO, Dxi
   IFTBOOL(pTupleMD->getNumOperands() >= 1, DXC_E_INCORRECT_DXIL_METADATA);
   unsigned Tag = ConstMDToUint32(pTupleMD->getOperand(0));
   switch (Tag) {
-  case kDxilTemplateArgTypeTag:
+  case kDxilTemplateArgTypeTag: {
     IFTBOOL(pTupleMD->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA);
-    annotation.SetType(MetadataAsValue::get(m_Ctx,
-      pTupleMD->getOperand(kDxilTemplateArgValue))->getType());
-    break;
+    Constant *C = dyn_cast<Constant>(ValueMDToValue(pTupleMD->getOperand(kDxilTemplateArgValue)));
+    IFTBOOL(C != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+    annotation.SetType(C->getType());
+  } break;
   case kDxilTemplateArgIntegralTag:
     IFTBOOL(pTupleMD->getNumOperands() == 2, DXC_E_INCORRECT_DXIL_METADATA);
     annotation.SetIntegral((int64_t)ConstMDToUint64(pTupleMD->getOperand(kDxilTemplateArgValue)));
@@ -805,10 +828,7 @@ void DxilMDHelper::LoadDxilTemplateArgAnnotation(const llvm::MDOperand &MDO, Dxi
 }
 
 Metadata *DxilMDHelper::EmitDxilStructAnnotation(const DxilStructAnnotation &SA) {
-  unsigned valMajor = 0, valMinor = 0;
-  if (m_pSM)
-    m_pSM->GetMinValidatorVersion(valMajor, valMinor);
-  bool bSupportExtended = !(valMajor == 1 && valMinor < 5);
+  bool bSupportExtended = DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0;
 
   vector<Metadata *> MDVals;
   MDVals.reserve(SA.GetNumFields() + 2);  // In case of extended 1.5 property list
@@ -841,10 +861,7 @@ void DxilMDHelper::LoadDxilStructAnnotation(const MDOperand &MDO, DxilStructAnno
   if (pTupleMD->getNumOperands() == 1) {
     SA.MarkEmptyStruct();
   }
-  unsigned valMajor = 0, valMinor = 0;
-  if (m_pSM)
-    m_pSM->GetMinValidatorVersion(valMajor, valMinor);
-  if (!(valMajor == 1 && valMinor < 5) &&
+  if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0 &&
       (pTupleMD->getNumOperands() == SA.GetNumFields()+2)) {
     // Load template args from extended operand
     const MDOperand &MDOExtra = pTupleMD->getOperand(SA.GetNumFields()+1);
@@ -969,6 +986,11 @@ Metadata *DxilMDHelper::EmitDxilFieldAnnotation(const DxilFieldAnnotation &FA) {
     MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCompTypeTag));
     MDVals.emplace_back(Uint32ToConstMD((unsigned)FA.GetCompType().GetKind()));
   }
+  if (FA.IsCBVarUsed() &&
+      DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0) {
+    MDVals.emplace_back(Uint32ToConstMD(kDxilFieldAnnotationCBUsedTag));
+    MDVals.emplace_back(BoolToConstMD(true));
+  }
 
   return MDNode::get(m_Ctx, MDVals);
 }
@@ -1013,6 +1035,9 @@ void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnota
     case kDxilFieldAnnotationCompTypeTag:
       FA.SetCompType((CompType::Kind)ConstMDToUint32(MDO));
       break;
+    case kDxilFieldAnnotationCBUsedTag:
+      FA.SetCBVarUsed(ConstMDToBool(MDO));
+      break;
     default:
       // TODO:  I don't think we should be failing unrecognized extended tags.
       //        Perhaps we can flag this case in the module and fail validation
@@ -2158,6 +2183,12 @@ void DxilExtraPropertyHelper::EmitSignatureElementProperties(const DxilSignature
     MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag, m_Ctx));
     MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetDynIdxCompMask(), m_Ctx));
   }
+
+  if (SE.GetUsageMask() != 0 &&
+      DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0) {
+    MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementUsageCompMaskTag, m_Ctx));
+    MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetUsageMask(), m_Ctx));
+  }
 }
 
 void DxilExtraPropertyHelper::LoadSignatureElementProperties(const MDOperand &MDO, DxilSignatureElement &SE) {
@@ -2182,6 +2213,9 @@ void DxilExtraPropertyHelper::LoadSignatureElementProperties(const MDOperand &MD
     case DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag:
       SE.SetDynIdxCompMask(DxilMDHelper::ConstMDToUint32(MDO));
       break;
+    case DxilMDHelper::kDxilSignatureElementUsageCompMaskTag:
+      SE.SetUsageMask(DxilMDHelper::ConstMDToUint32(MDO));
+      break;
     default:
       DXASSERT(false, "Unknown signature element tag");
     }

+ 82 - 16
lib/DXIL/DxilModule.cpp

@@ -197,7 +197,13 @@ bool DxilModule::GetMinValidatorVersion(unsigned &ValMajor, unsigned &ValMinor)
   if (!m_pSM)
     return false;
   m_pSM->GetMinValidatorVersion(ValMajor, ValMinor);
-  if (ValMajor == 1 && ValMinor == 0 &&
+  if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0 &&
+      m_ShaderFlags.GetRaytracingTier1_1())
+    ValMinor = 5;
+  else if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 4) < 0 &&
+           GetSubobjects() && !GetSubobjects()->GetSubobjects().empty())
+    ValMinor = 4;
+  else if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 1) < 0 &&
       (m_ShaderFlags.GetFeatureInfo() & hlsl::DXIL::ShaderFeatureInfo_ViewID))
     ValMinor = 1;
   return true;
@@ -1531,52 +1537,112 @@ void DxilModule::ReEmitDxilResources() {
 }
 
 template <typename TResource>
-static void
+static bool
 StripResourcesReflection(std::vector<std::unique_ptr<TResource>> &vec) {
+  bool bChanged = false;
   for (auto &p : vec) {
     p->SetGlobalName("");
     // Cannot remove global symbol which used by validation.
+    bChanged = true;
   }
+  return bChanged;
 }
 
-void DxilModule::StripReflection() {
+static bool ResourceTypeRequiresTranslation(const StructType* Ty) {
+  if (Ty->getName().startswith("class.matrix."))
+    return true;
+  for (auto eTy : Ty->elements()) {
+    if (StructType *structTy = dyn_cast<StructType>(eTy)) {
+      if (ResourceTypeRequiresTranslation(structTy))
+        return true;
+    }
+    SequentialType *seqTy;
+    while (seqTy = dyn_cast<SequentialType>(eTy)) {
+      eTy = seqTy->getElementType();
+    }
+    if (eTy->getScalarSizeInBits() < 32) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool DxilModule::StripReflection() {
+  bool bChanged = false;
+  bool bIsLib = GetShaderModel()->IsLib();
+
   // Remove names.
   for (Function &F : m_pModule->functions()) {
     for (BasicBlock &BB : F) {
-      if (BB.hasName())
+      if (BB.hasName()) {
         BB.setName("");
+        bChanged = true;
+      }
       for (Instruction &I : BB) {
-        if (I.hasName())
+        if (I.hasName()) {
           I.setName("");
+          bChanged = true;
+        }
       }
     }
   }
-  // Remove struct annotation.
-  // FunctionAnnotation is used later, so keep it.
-  m_pTypeSystem->GetStructAnnotationMap().clear();
 
+  if (bIsLib && GetUseMinPrecision())
+  {
+    // We must preserve struct annotations for resources containing min-precision types,
+    // since they have not yet been converted for legacy layout.
+    SmallVector<const StructType*, 4> structsToRemove;
+    for (auto &item : m_pTypeSystem->GetStructAnnotationMap()) {
+      if (!ResourceTypeRequiresTranslation(item.first))
+        structsToRemove.emplace_back(item.first);
+    }
+    for (auto Ty : structsToRemove) {
+      m_pTypeSystem->GetStructAnnotationMap().erase(Ty);
+    }
+  } else {
+    // Remove struct annotations.
+    if (!m_pTypeSystem->GetStructAnnotationMap().empty()) {
+      m_pTypeSystem->GetStructAnnotationMap().clear();
+      bChanged = true;
+    }
+    if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) >= 0) {
+      // Remove function annotations.
+      if (!m_pTypeSystem->GetFunctionAnnotationMap().empty()) {
+        m_pTypeSystem->GetFunctionAnnotationMap().clear();
+        bChanged = true;
+      }
+    }
+  }
 
   // Resource
-  if (!GetShaderModel()->IsLib()) {
-    StripResourcesReflection(m_CBuffers);
-    StripResourcesReflection(m_UAVs);
-    StripResourcesReflection(m_SRVs);
-    StripResourcesReflection(m_Samplers);
+  if (!bIsLib) {
+    bChanged |= StripResourcesReflection(m_CBuffers);
+    bChanged |= StripResourcesReflection(m_UAVs);
+    bChanged |= StripResourcesReflection(m_SRVs);
+    bChanged |= StripResourcesReflection(m_Samplers);
   }
 
   // Unused global.
   SmallVector<GlobalVariable *,2> UnusedGlobals;
   for (GlobalVariable &GV : m_pModule->globals()) {
-    if (GV.use_empty())
-      UnusedGlobals.emplace_back(&GV);
+    if (GV.use_empty()) {
+      // Need to preserve this global, otherwise we drop constructors
+      // for static globals.
+      if (!bIsLib || GV.getName().compare("llvm.global_ctors") != 0)
+        UnusedGlobals.emplace_back(&GV);
+    }
   }
+  bChanged |= !UnusedGlobals.empty();
 
   for (GlobalVariable *GV : UnusedGlobals) {
     GV->eraseFromParent();
   }
 
   // ReEmit meta.
-  ReEmitDxilResources();
+  if (bChanged)
+    ReEmitDxilResources();
+
+  return bChanged;
 }
 
 void DxilModule::LoadDxilResources(const llvm::MDOperand &MDO) {

+ 9 - 0
lib/DXIL/DxilOperations.cpp

@@ -807,11 +807,20 @@ void OP::GetMinShaderModelAndMask(OpCode C, bool bWithTranslation,
 }
 
 void OP::GetMinShaderModelAndMask(const llvm::CallInst *CI, bool bWithTranslation,
+                                  unsigned valMajor, unsigned valMinor,
                                   unsigned &major, unsigned &minor,
                                   unsigned &mask) {
   OpCode opcode = OP::GetDxilOpFuncCallInst(CI);
   GetMinShaderModelAndMask(opcode, bWithTranslation, major, minor, mask);
 
+  if (DXIL::CompareVersions(valMajor, valMinor, 1, 5) < 0) {
+    // validator 1.4 didn't exclude wave ops in mask
+    if (IsDxilOpWave(opcode))
+      mask = ((unsigned)1 << (unsigned)DXIL::ShaderKind::Invalid) - 1;
+    // validator 1.4 didn't have any additional rules applied:
+    return;
+  }
+
   // Additional rules are applied manually here.
 
   // Barrier with mode != UAVFenceGlobal requires compute, amplification, or mesh

+ 22 - 0
lib/DXIL/DxilShaderFlags.cpp

@@ -459,6 +459,28 @@ ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
     }
   }
 
+  if (!hasRaytracingTier1_1) {
+    if (const DxilSubobjects *pSubobjects = M->GetSubobjects()) {
+      for (const auto &it : pSubobjects->GetSubobjects()) {
+        switch (it.second->GetKind()) {
+        case DXIL::SubobjectKind::RaytracingPipelineConfig1:
+          hasRaytracingTier1_1 = true;
+          break;
+        case DXIL::SubobjectKind::StateObjectConfig: {
+          uint32_t Flags;
+          if (it.second->GetStateObjectConfig(Flags) &&
+              ((Flags & ~(unsigned)DXIL::StateObjectFlags::ValidMask_1_4) != 0))
+            hasRaytracingTier1_1 = true;
+        } break;
+        default:
+          break;
+        }
+        if (hasRaytracingTier1_1)
+          break;
+      }
+    }
+  }
+
   flag.SetEnableDoublePrecision(hasDouble);
   flag.SetStencilRef(hasStencilRef);
   flag.SetInnerCoverage(hasInnerCoverage);

+ 11 - 1
lib/DXIL/DxilSignatureElement.cpp

@@ -37,7 +37,8 @@ DxilSignatureElement::DxilSignatureElement(DXIL::SigPointKind sigPointKind)
 , m_Cols(0)
 , m_StartRow(Semantic::kUndefinedRow)
 , m_StartCol(Semantic::kUndefinedCol)
-, m_DynIdxCompMask(0) {
+, m_DynIdxCompMask(0)
+, m_UsageMask(0) {
 }
 
 DxilSignatureElement::~DxilSignatureElement() {
@@ -277,4 +278,13 @@ void DxilSignatureElement::SetDynIdxCompMask(unsigned DynIdxCompMask) {
   m_DynIdxCompMask = DynIdxCompMask;
 }
 
+uint8_t DxilSignatureElement::GetUsageMask() const {
+  DXASSERT_NOMSG(m_UsageMask <= 0xF);
+  return (uint8_t)m_UsageMask;
+}
+void DxilSignatureElement::SetUsageMask(unsigned UsageMask) {
+  DXASSERT_NOMSG(UsageMask <= 0xF);
+  m_UsageMask = UsageMask;
+}
+
 } // namespace hlsl

+ 6 - 2
lib/DXIL/DxilTypeSystem.cpp

@@ -43,8 +43,9 @@ DxilMatrixAnnotation::DxilMatrixAnnotation()
 DxilFieldAnnotation::DxilFieldAnnotation()
 : m_bPrecise(false)
 , m_ResourceAttribute(nullptr)
-, m_CBufferOffset(UINT_MAX) {
-}
+, m_CBufferOffset(UINT_MAX)
+, m_bCBufferVarUsed(false)
+{}
 
 bool DxilFieldAnnotation::IsPrecise() const { return m_bPrecise; }
 void DxilFieldAnnotation::SetPrecise(bool b) { m_bPrecise = b; }
@@ -76,6 +77,9 @@ void DxilFieldAnnotation::SetInterpolationMode(const InterpolationMode &IM) { m_
 bool DxilFieldAnnotation::HasFieldName() const { return !m_FieldName.empty(); }
 const std::string &DxilFieldAnnotation::GetFieldName() const { return m_FieldName; }
 void DxilFieldAnnotation::SetFieldName(const std::string &FieldName) { m_FieldName = FieldName; }
+bool DxilFieldAnnotation::IsCBVarUsed() const { return m_bCBufferVarUsed; }
+void DxilFieldAnnotation::SetCBVarUsed(bool used) { m_bCBufferVarUsed = used; }
+
 
 
 //------------------------------------------------------------------------------

+ 50 - 0
lib/DxcSupport/HLSLOptions.cpp

@@ -13,6 +13,7 @@
 #include "llvm/Option/Option.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Path.h"
+#include "llvm/ADT/APInt.h"
 #include "dxc/Support/Global.h"
 #include "dxc/Support/WinIncludes.h"
 #include "dxc/Support/HLSLOptions.h"
@@ -552,6 +553,8 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
   opts.StripRootSignature = Args.hasFlag(OPT_Qstrip_rootsignature, OPT_INVALID, false);
   opts.StripPrivate = Args.hasFlag(OPT_Qstrip_priv, OPT_INVALID, false);
   opts.StripReflection = Args.hasFlag(OPT_Qstrip_reflect, OPT_INVALID, false);
+  opts.KeepReflectionInDxil = Args.hasFlag(OPT_Qkeep_reflect_in_dxil, OPT_INVALID, false);
+  opts.StripReflectionFromDxil = Args.hasFlag(OPT_Qstrip_reflect_from_dxil, OPT_INVALID, false);
   opts.ExtractRootSignature = Args.hasFlag(OPT_extractrootsignature, OPT_INVALID, false);
   opts.DisassembleColorCoded = Args.hasFlag(OPT_Cc, OPT_INVALID, false);
   opts.DisassembleInstNumbers = Args.hasFlag(OPT_Ni, OPT_INVALID, false);
@@ -642,11 +645,45 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
     return 1;
   }
 
+  llvm::StringRef valVersionStr = Args.getLastArgValue(OPT_validator_version);
+  if (!valVersionStr.empty()) {
+    // Parse "major.minor" version string
+    auto verPair = valVersionStr.split(".");
+    llvm::APInt major, minor;
+    if (verPair.first.getAsInteger(0, major) || verPair.second.getAsInteger(0, minor)) {
+      errors << "Format of validator version is \"<major>.<minor>\" (ex: \"1.4\").";
+      return 1;
+    }
+    uint64_t major64 = major.getLimitedValue();
+    uint64_t minor64 = minor.getLimitedValue();
+    if (major64 > DXIL::kDxilMajor ||
+        (major64 == DXIL::kDxilMajor && minor64 > DXIL::kDxilMinor)) {
+      errors << "Validator version must be less than or equal to current internal version.";
+      return 1;
+    }
+    if (major64 == 0 && minor64 != 0) {
+      errors << "If validator major version is 0, minor version must also be 0.";
+      return 1;
+    }
+    opts.ValVerMajor = (unsigned long)major64;
+    opts.ValVerMinor = (unsigned long)minor64;
+  }
+
   if (opts.IsLibraryProfile() && Minor == 0xF) {
+    if (opts.ValVerMajor != UINT_MAX && opts.ValVerMajor != 0) {
+      errors << "Offline library profile cannot be used with non-zero -validator-version.";
+      return 1;
+    }
     // Disable validation for offline link only target
     opts.DisableValidation = true;
+
+    // ValVerMajor == 0 means that the module is not meant to ever be validated.
+    opts.ValVerMajor = 0;
+    opts.ValVerMinor = 0;
   }
 
+  // These targets are only useful as an intermediate step towards linking to matching
+  // shader targets without going through target downgrading at link time.
   // Disable lib_6_1 and lib_6_2 if /Vd is not present
   if (opts.IsLibraryProfile() && (Major < 6 || (Major == 6 && Minor < 3))) {
     if (!opts.DisableValidation) {
@@ -654,6 +691,19 @@ int ReadDxcOpts(const OptTable *optionTable, unsigned flagsToInclude,
                 "targets.";
       return 1;
     }
+    if (opts.ValVerMajor != UINT_MAX && opts.ValVerMajor != 0) {
+      errors << "non-zero -validator-version cannot be used with library profiles lib_6_1 or lib_6_2.";
+      return 1;
+    }
+
+    // ValVerMajor == 0 means that the module is not meant to ever be validated.
+    opts.ValVerMajor = 0;
+    opts.ValVerMinor = 0;
+  }
+
+  if (opts.KeepReflectionInDxil && opts.StripReflectionFromDxil) {
+    errors << "-Qstrip_reflect_from_dxil mutually exclusive with -Qkeep_reflect_in_dxil.";
+    return 1;
   }
 
     // SPIRV Change Starts

+ 147 - 31
lib/DxilContainer/DxilContainerAssembler.cpp

@@ -17,6 +17,7 @@
 #include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/Support/MD5.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Transforms/Utils/Cloning.h"
 #include "dxc/DxilContainer/DxilContainer.h"
 #include "dxc/DXIL/DxilModule.h"
 #include "dxc/DXIL/DxilShaderModel.h"
@@ -101,10 +102,15 @@ static DxilProgramSigSemantic KindToSystemValue(Semantic::Kind kind, DXIL::Tesse
   // TODO: Final_* values need mappings
 }
 
-static DxilProgramSigCompType CompTypeToSigCompType(hlsl::CompType value) {
+static DxilProgramSigCompType CompTypeToSigCompType(hlsl::CompType value, bool i1ToUnknownCompat) {
   switch (value.GetKind()) {
   case CompType::Kind::I32: return DxilProgramSigCompType::SInt32;
-  case CompType::Kind::I1: __fallthrough;
+
+  case CompType::Kind::I1:
+    // Validator 1.4 and below returned Unknown for i1
+    if (i1ToUnknownCompat)  return DxilProgramSigCompType::Unknown;
+    else                    return DxilProgramSigCompType::UInt32;
+
   case CompType::Kind::U32: return DxilProgramSigCompType::UInt32;
   case CompType::Kind::F32: return DxilProgramSigCompType::Float32;
   case CompType::Kind::I16: return DxilProgramSigCompType::SInt16;
@@ -154,6 +160,10 @@ struct sort_sig {
   }
 };
 
+static uint8_t NegMask(uint8_t V) {
+  V ^= 0xF;
+  return V & 0xF;
+}
 
 class DxilProgramSignatureWriter : public DxilPartWriter {
 private:
@@ -161,6 +171,7 @@ private:
   DXIL::TessellatorDomain m_domain;
   bool   m_isInput;
   bool   m_useMinPrecision;
+  bool m_bCompat_1_4;
   size_t m_fixedSize;
   typedef std::pair<const char *, uint32_t> NameOffsetPair;
   typedef llvm::SmallMapVector<const char *, uint32_t, 8> NameOffsetMap;
@@ -203,16 +214,27 @@ private:
     sig.Stream = pElement->GetOutputStream();
     sig.SemanticName = GetSemanticOffset(pElement);
     sig.SystemValue = KindToSystemValue(pElement->GetKind(), m_domain);
-    sig.CompType = CompTypeToSigCompType(pElement->GetCompType());
+    sig.CompType = CompTypeToSigCompType(pElement->GetCompType(), m_bCompat_1_4);
     sig.Register = pElement->GetStartRow();
 
     sig.Mask = pElement->GetColsAsMask();
-    // Only mark exist channel write for output.
-    // All channel not used for input.
-    if (!m_isInput)
-      sig.NeverWrites_Mask = ~(sig.Mask);
-    else
-      sig.AlwaysReads_Mask = 0;
+    if (m_bCompat_1_4) {
+      // Match what validator 1.4 and below expects
+      // Only mark exist channel write for output.
+      // All channel not used for input.
+      if (!m_isInput)
+        sig.NeverWrites_Mask = ~sig.Mask;
+      else
+        sig.AlwaysReads_Mask = 0;
+    } else {
+      unsigned UsageMask = pElement->GetUsageMask();
+      if (pElement->IsAllocated())
+        UsageMask <<= pElement->GetStartCol();
+      if (!m_isInput)
+        sig.NeverWrites_Mask = NegMask(UsageMask);
+      else
+        sig.AlwaysReads_Mask = UsageMask;
+    }
 
     sig.MinPrecision = m_useMinPrecision
                            ? CompTypeToSigMinPrecision(pElement->GetCompType())
@@ -252,8 +274,12 @@ private:
 
 public:
   DxilProgramSignatureWriter(const DxilSignature &signature,
-                             DXIL::TessellatorDomain domain, bool isInput, bool UseMinPrecision)
-      : m_signature(signature), m_domain(domain), m_isInput(isInput), m_useMinPrecision(UseMinPrecision) {
+                             DXIL::TessellatorDomain domain,
+                             bool isInput, bool UseMinPrecision,
+                             bool bCompat_1_4)
+      : m_signature(signature), m_domain(domain),
+        m_isInput(isInput), m_useMinPrecision(UseMinPrecision),
+        m_bCompat_1_4(bCompat_1_4) {
     calcSizes();
   }
 
@@ -306,20 +332,26 @@ DxilPartWriter *hlsl::NewProgramSignatureWriter(const DxilModule &M, DXIL::Signa
   DXIL::TessellatorDomain domain = DXIL::TessellatorDomain::Undefined;
   if (M.GetShaderModel()->IsHS() || M.GetShaderModel()->IsDS())
     domain = M.GetTessellatorDomain();
+  unsigned ValMajor, ValMinor;
+  M.GetValidatorVersion(ValMajor, ValMinor);
+  bool bCompat_1_4 = DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0;
   switch (Kind) {
   case DXIL::SignatureKind::Input:
     return new DxilProgramSignatureWriter(
         M.GetInputSignature(), domain, true,
-        M.GetUseMinPrecision());
+        M.GetUseMinPrecision(),
+        bCompat_1_4);
   case DXIL::SignatureKind::Output:
     return new DxilProgramSignatureWriter(
         M.GetOutputSignature(), domain, false,
-        M.GetUseMinPrecision());
+        M.GetUseMinPrecision(),
+        bCompat_1_4);
   case DXIL::SignatureKind::PatchConstOrPrim:
     return new DxilProgramSignatureWriter(
         M.GetPatchConstOrPrimSignature(), domain,
         /*IsInput*/ M.GetShaderModel()->IsDS(),
-        /*UseMinPrecision*/M.GetUseMinPrecision());
+        /*UseMinPrecision*/M.GetUseMinPrecision(),
+        bCompat_1_4);
   case DXIL::SignatureKind::Invalid:
     return nullptr;
   }
@@ -367,6 +399,7 @@ DxilPartWriter *hlsl::NewFeatureInfoWriter(const DxilModule &M) {
 class DxilPSVWriter : public DxilPartWriter  {
 private:
   const DxilModule &m_Module;
+  unsigned m_ValMajor, m_ValMinor;
   PSVInitInfo m_PSVInitInfo;
   DxilPipelineStateValidation m_PSV;
   uint32_t m_PSVBufferSize;
@@ -422,7 +455,8 @@ private:
       E.StartRow = (uint8_t)SE.GetStartRow();
     }
     E.SemanticKind = (uint8_t)SE.GetKind();
-    E.ComponentType = (uint8_t)CompTypeToSigCompType(SE.GetCompType());
+    E.ComponentType = (uint8_t)CompTypeToSigCompType(SE.GetCompType(),
+      /*i1ToUnknownCompat*/DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) < 0);
     E.InterpolationMode = (uint8_t)SE.GetInterpolationMode()->GetKind();
     DXASSERT_NOMSG(SE.GetOutputStream() < 4);
     E.DynamicMaskAndStream = (uint8_t)((SE.GetOutputStream() & 0x3) << 4);
@@ -450,13 +484,12 @@ public:
   : m_Module(module),
     m_PSVInitInfo(PSVVersion)
   {
-    unsigned ValMajor, ValMinor;
-    m_Module.GetValidatorVersion(ValMajor, ValMinor);
+    m_Module.GetValidatorVersion(m_ValMajor, m_ValMinor);
     // Allow PSVVersion to be upgraded
-    if (ValMajor == 0 && ValMinor == 0) {
+    if (m_ValMajor == 0 && m_ValMinor == 0) {
       // Validation disabled upgrades to maximum PSVVersion
       m_PSVInitInfo.PSVVersion = MAX_PSV_VERSION;
-    } else if (m_PSVInitInfo.PSVVersion < 1 && (ValMajor > 1 || (ValMajor == 1 && ValMinor >= 1))) {
+    } else if (m_PSVInitInfo.PSVVersion < 1 && (m_ValMajor > 1 || (m_ValMajor == 1 && m_ValMinor >= 1))) {
       m_PSVInitInfo.PSVVersion = 1;
     }
 
@@ -1006,6 +1039,8 @@ private:
   FunctionIndexMap m_FuncToResNameOffset; // list of resources used
   FunctionIndexMap m_FuncToDependencies;  // list of unresolved functions used
 
+  unsigned m_ValMajor, m_ValMinor;
+
   struct ShaderCompatInfo {
     ShaderCompatInfo()
       : minMajor(6), minMinor(0),
@@ -1025,7 +1060,9 @@ private:
         ShaderCompatInfo &info = m_FuncToShaderCompat[F];
         unsigned major, minor, mask;
         // bWithTranslation = true for library modules
-        OP::GetMinShaderModelAndMask(CI, /*bWithTranslation*/true, major, minor, mask);
+        OP::GetMinShaderModelAndMask(CI, /*bWithTranslation*/true,
+                                     m_ValMajor, m_ValMinor,
+                                     major, minor, mask);
         if (major > info.minMajor) {
           info.minMajor = major;
           info.minMinor = minor;
@@ -1128,6 +1165,12 @@ private:
   }
 
   void UpdateFunctionInfo(const DxilModule &DM) {
+    // We must select the appropriate shader mask for the validator version,
+    // so we don't set any bits the validator doesn't recognize.
+    unsigned ValidShaderMask = (1 << ((unsigned)DXIL::ShaderKind::Amplification + 1)) - 1;
+    if (DXIL::CompareVersions(m_ValMajor, m_ValMinor, 1, 5) < 0) {
+      ValidShaderMask = (1 << ((unsigned)DXIL::ShaderKind::Callable + 1)) - 1;
+    }
     for (auto &function : DM.GetModule()->getFunctionList()) {
       if (function.isDeclaration() && !function.isIntrinsic()) {
         if (OP::IsDxilOpFunc(&function)) {
@@ -1196,7 +1239,7 @@ private:
         }
         if ((DXIL::ShaderKind)shaderKind == DXIL::ShaderKind::Library) {
           // Init mask to all kinds for library functions
-          info.ShaderStageFlag = ((unsigned)1 << (unsigned)DXIL::ShaderKind::Invalid) - 1;
+          info.ShaderStageFlag = ValidShaderMask;
         } else {
           // Init mask to current kind for shader functions
           info.ShaderStageFlag = (unsigned)1 << shaderKind;
@@ -1313,6 +1356,9 @@ private:
 public:
   DxilRDATWriter(const DxilModule &module, uint32_t InfoVersion = 0)
       : m_RDATBuffer(), m_Parts(), m_FuncToResNameOffset() {
+    // Keep track of validator version so we can make a compatible RDAT
+    module.GetValidatorVersion(m_ValMajor, m_ValMinor);
+
     CreateParts();
     UpdateResourceInfo(module);
     UpdateFunctionInfo(module);
@@ -1498,7 +1544,8 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
                                            AbstractMemoryStream *pFinalStream,
                                            llvm::StringRef DebugName,
                                            SerializeDxilFlags Flags,
-                                           DxilShaderHash *pShaderHashOut) {
+                                           DxilShaderHash *pShaderHashOut,
+                                           AbstractMemoryStream *pReflectionStreamOut) {
   // TODO: add a flag to update the module and remove information that is not part
   // of DXIL proper and is used only to assemble the container.
 
@@ -1508,11 +1555,12 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
 
   unsigned ValMajor, ValMinor;
   pModule->GetValidatorVersion(ValMajor, ValMinor);
-  if (ValMajor == 1 && ValMinor == 0)
+  if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 1) < 0)
     Flags &= ~SerializeDxilFlags::IncludeDebugNamePart;
-  bool bSupportsShaderHash = true;
-  if (ValMajor == 1 && ValMinor < 5)
-    bSupportsShaderHash = false;
+  bool bSupportsShaderHash = DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) >= 0;
+  bool bCompat_1_4 = DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0;
+  bool bEmitReflection = Flags & SerializeDxilFlags::IncludeReflectionPart ||
+                         pReflectionStreamOut;
 
   DxilContainerWriter_impl writer;
 
@@ -1532,11 +1580,13 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
     pInputSigWriter = llvm::make_unique<DxilProgramSignatureWriter>(
         pModule->GetInputSignature(), domain,
         /*IsInput*/ true,
-        /*UseMinPrecision*/ pModule->GetUseMinPrecision());
+        /*UseMinPrecision*/ pModule->GetUseMinPrecision(),
+        bCompat_1_4);
     pOutputSigWriter = llvm::make_unique<DxilProgramSignatureWriter>(
         pModule->GetOutputSignature(), domain,
         /*IsInput*/ false,
-        /*UseMinPrecision*/ pModule->GetUseMinPrecision());
+        /*UseMinPrecision*/ pModule->GetUseMinPrecision(),
+        bCompat_1_4);
     // Write the input and output signature parts.
     writer.AddPart(DFCC_InputSignature, pInputSigWriter->size(),
                    [&](AbstractMemoryStream *pStream) {
@@ -1550,7 +1600,8 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
     pPatchConstOrPrimSigWriter = llvm::make_unique<DxilProgramSignatureWriter>(
         pModule->GetPatchConstOrPrimSignature(), domain,
         /*IsInput*/ pModule->GetShaderModel()->IsDS(),
-        /*UseMinPrecision*/ pModule->GetUseMinPrecision());
+        /*UseMinPrecision*/ pModule->GetUseMinPrecision(),
+        bCompat_1_4);
     if (pModule->GetPatchConstOrPrimSignature().GetElements().size()) {
       writer.AddPart(DFCC_PatchConstantSignature,
                      pPatchConstOrPrimSigWriter->size(),
@@ -1623,9 +1674,74 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
     Flags &= ~SerializeDxilFlags::DebugNameDependOnSource;
   }
 
+  // Clone module for reflection, strip function defs
+  std::unique_ptr<Module> reflectionModule;
+  if (bEmitReflection) {
+    if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0) {
+      // Retain usage information in metadata for reflection by:
+      // Upgrade validator version, re-emit metadata, then clone module for reflection.
+      // 0,0 = Not meant to be validated, support latest
+      pModule->SetValidatorVersion(0, 0);
+      pModule->ReEmitDxilResources();
+    }
+
+    reflectionModule.reset(llvm::CloneModule(pModule->GetModule()));
+
+    if (DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) < 0) {
+      // Now restore validator version on main module and re-emit metadata.
+      pModule->SetValidatorVersion(ValMajor, ValMinor);
+      pModule->ReEmitDxilResources();
+    }
+
+    for (Function &F : reflectionModule->functions()) {
+      if (!F.isDeclaration()) {
+        F.deleteBody();
+      }
+    }
+    // Just make sure this doesn't crash/assert on debug build:
+    DXASSERT_NOMSG(&reflectionModule->GetOrCreateDxilModule());
+  }
+
+  CComPtr<AbstractMemoryStream> pReflectionBitcodeStream;
+
+  uint32_t reflectPartSizeInBytes = 0;
+  if (bEmitReflection)
+  {
+    IFT(CreateMemoryStream(DxcGetThreadMallocNoRef(), &pReflectionBitcodeStream));
+    raw_stream_ostream outStream(pReflectionBitcodeStream.p);
+    WriteBitcodeToFile(reflectionModule.get(), outStream, false);
+    outStream.flush();
+    uint32_t reflectInUInt32 = 0, reflectPaddingBytes = 0;
+    GetPaddedProgramPartSize(pReflectionBitcodeStream, reflectInUInt32, reflectPaddingBytes);
+    reflectPartSizeInBytes = reflectInUInt32 * sizeof(uint32_t) + sizeof(DxilProgramHeader);
+  }
+
+  if (pReflectionStreamOut) {
+    DxilPartHeader partSTAT;
+    partSTAT.PartFourCC = DFCC_ShaderStatistics;
+    partSTAT.PartSize = reflectPartSizeInBytes;
+    IFT(WriteStreamValue(pReflectionStreamOut, partSTAT));
+    WriteProgramPart(pModule->GetShaderModel(), pReflectionBitcodeStream, pReflectionStreamOut);
+
+    // If library, we need RDAT part as well.  For now, we just append it
+    if (pModule->GetShaderModel()->IsLib()) {
+      DxilPartHeader partRDAT;
+      partRDAT.PartFourCC = DFCC_RuntimeData;
+      partRDAT.PartSize = pRDATWriter->size();
+      IFT(WriteStreamValue(pReflectionStreamOut, partRDAT));
+      pRDATWriter->write(pReflectionStreamOut);
+    }
+  }
+
+  if (Flags & SerializeDxilFlags::IncludeReflectionPart) {
+    writer.AddPart(DFCC_ShaderStatistics, reflectPartSizeInBytes,
+      [pModule, pReflectionBitcodeStream](AbstractMemoryStream *pStream) {
+        WriteProgramPart(pModule->GetShaderModel(), pReflectionBitcodeStream, pStream);
+      });
+  }
+
   if (Flags & SerializeDxilFlags::StripReflectionFromDxilPart) {
-    pModule->StripReflection();
-    bModuleStripped = true;
+    bModuleStripped |= pModule->StripReflection();
   }
 
   // If debug info or reflection was stripped, re-serialize the module.

+ 154 - 1
lib/HLSL/DxilCondenseResources.cpp

@@ -477,6 +477,9 @@ public:
 
     bChanged |= ResourceRegisterAllocator.AllocateRegisters(DM);
 
+    // Fill in top-level CBuffer variable usage bit
+    UpdateCBufferUsage();
+
     if (m_bIsLib && DM.GetShaderModel()->GetMinor() == ShaderModel::kOfflineMinor)
       return bChanged;
 
@@ -494,8 +497,14 @@ public:
 
     GenerateDxilResourceHandles();
 
+    // TODO: Update types earlier for libraries and replace users, to
+    //       avoid having to preserve HL struct annotation.
+    // Note 1: Needs to happen after legalize
+    // Note 2: Cannot do this easily/trivially if any functions have
+    //         resource arguments (in offline linking target).
     if (DM.GetOP()->UseMinPrecision())
       UpdateStructTypeForLegacyLayout();
+
     // Change resource symbol into undef.
     UpdateResourceSymbols();
 
@@ -516,6 +525,7 @@ private:
   // Switch CBuffer for SRV for TBuffers.
   bool PatchTBuffers(DxilModule &DM);
   void PatchTBufferUse(Value *V, DxilModule &DM);
+  void UpdateCBufferUsage();
 };
 
 } // namespace
@@ -1597,7 +1607,11 @@ StructType *UpdateStructTypeForLegacyLayout(StructType *ST,
   unsigned fieldsCount = ST->getNumElements();
   std::vector<Type *> fieldTypes(fieldsCount);
   DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
-  DXASSERT(SA, "must have annotation for struct type");
+
+  // After reflection is stripped from library, this will be null if no update is required.
+  if (!SA) {
+    return ST;
+  }
 
   if (SA->IsEmptyStruct()) {
     return ST;
@@ -2093,6 +2107,145 @@ bool DxilLowerCreateHandleForLib::PatchTBuffers(DxilModule &DM) {
   return bChanged;
 }
 
+// Find the imm offset part from a value.
+// It must exist unless offset is 0.
+static unsigned GetCBOffset(Value *V) {
+  if (ConstantInt *Imm = dyn_cast<ConstantInt>(V))
+    return Imm->getLimitedValue();
+  else if (UnaryInstruction *UI = dyn_cast<UnaryInstruction>(V)) {
+    return 0;
+  } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(V)) {
+    switch (BO->getOpcode()) {
+    case Instruction::Add: {
+      unsigned left = GetCBOffset(BO->getOperand(0));
+      unsigned right = GetCBOffset(BO->getOperand(1));
+      return left + right;
+    } break;
+    case Instruction::Or: {
+      unsigned left = GetCBOffset(BO->getOperand(0));
+      unsigned right = GetCBOffset(BO->getOperand(1));
+      return left | right;
+    } break;
+    default:
+      return 0;
+    }
+  } else {
+    return 0;
+  }
+}
+
+typedef std::map<unsigned, DxilFieldAnnotation*> FieldAnnotationByOffsetMap;
+
+static void MarkCBUse(unsigned offset, FieldAnnotationByOffsetMap &fieldMap) {
+  auto it = fieldMap.upper_bound(offset);
+  it--;
+  if (it != fieldMap.end())
+    it->second->SetCBVarUsed(true);
+}
+
+static unsigned GetOffsetForCBExtractValue(ExtractValueInst *EV, bool bMinPrecision) {
+  DXASSERT(EV->getNumIndices() == 1, "otherwise, unexpected indices/type for extractvalue");
+  unsigned typeSize = 4;
+  unsigned bits = EV->getType()->getScalarSizeInBits();
+  if (bits == 64)
+    typeSize = 8;
+  else if (bits == 16 && !bMinPrecision)
+    typeSize = 2;
+  return (EV->getIndices().front() * typeSize);
+}
+
+static void CollectInPhiChain(PHINode *cbUser, unsigned offset,
+                              std::unordered_set<Value *> &userSet,
+                              FieldAnnotationByOffsetMap &fieldMap,
+                              bool bMinPrecision) {
+  if (userSet.count(cbUser) > 0)
+    return;
+
+  userSet.insert(cbUser);
+  for (User *cbU : cbUser->users()) {
+    if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
+      MarkCBUse(offset + GetOffsetForCBExtractValue(EV, bMinPrecision), fieldMap);
+    } else {
+      PHINode *phi = cast<PHINode>(cbU);
+      CollectInPhiChain(phi, offset, userSet, fieldMap, bMinPrecision);
+    }
+  }
+}
+
+static void CollectCBufferMemberUsage(Value *V,
+                                      FieldAnnotationByOffsetMap &legacyFieldMap,
+                                      FieldAnnotationByOffsetMap &newFieldMap,
+                                      hlsl::OP *hlslOP, bool bMinPrecision) {
+  for (auto U : V->users()) {
+    if (Constant *C = dyn_cast<Constant>(U)) {
+      CollectCBufferMemberUsage(C, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
+    } else if (LoadInst *LI = dyn_cast<LoadInst>(U)) {
+      CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
+    } else if (CallInst *CI = dyn_cast<CallInst>(U)) {
+      if (hlslOP->IsDxilOpFuncCallInst(CI)) {
+        hlsl::OP::OpCode op = hlslOP->GetDxilOpFuncCallInst(CI);
+        if (op == DXIL::OpCode::CreateHandleForLib) {
+          CollectCBufferMemberUsage(U, legacyFieldMap, newFieldMap, hlslOP, bMinPrecision);
+        } else if (op == DXIL::OpCode::CBufferLoadLegacy) {
+          DxilInst_CBufferLoadLegacy cbload(CI);
+          Value *resIndex = cbload.get_regIndex();
+          unsigned offset = GetCBOffset(resIndex);
+          offset <<= 4; // translate 16-byte vector index to byte offset
+          for (User *cbU : U->users()) {
+            if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
+              MarkCBUse(offset + GetOffsetForCBExtractValue(EV, bMinPrecision), legacyFieldMap);
+            } else {
+              PHINode *phi = cast<PHINode>(cbU);
+              std::unordered_set<Value *> userSet;
+              CollectInPhiChain(phi, offset, userSet, legacyFieldMap, bMinPrecision);
+            }
+          }
+        } else if (op == DXIL::OpCode::CBufferLoad) {
+          DxilInst_CBufferLoad cbload(CI);
+          Value *byteOffset = cbload.get_byteOffset();
+          unsigned offset = GetCBOffset(byteOffset);
+          MarkCBUse(offset, newFieldMap);
+        }
+      }
+    }
+  }
+}
+
+void DxilLowerCreateHandleForLib::UpdateCBufferUsage() {
+  DxilTypeSystem &TypeSys = m_DM->GetTypeSystem();
+  hlsl::OP *hlslOP = m_DM->GetOP();
+  const DataLayout &DL = m_DM->GetModule()->getDataLayout();
+  const auto &CBuffers = m_DM->GetCBuffers();
+  for (auto it = CBuffers.begin(); it != CBuffers.end(); it++) {
+    DxilCBuffer *CB = it->get();
+    GlobalVariable *GV = dyn_cast<GlobalVariable>(CB->GetGlobalSymbol());
+    if (GV == nullptr)
+      continue;
+    Type *ElemTy = GV->getType()->getPointerElementType();
+    ElemTy = dxilutil::StripArrayTypes(ElemTy, nullptr);
+    StructType *ST = cast<StructType>(ElemTy);
+    DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
+    if (SA == nullptr)
+      continue;
+    // If elements < 2, it's used if it exists.
+    // Only old-style cbuffer { ... } will have more than one member, and
+    // old-style cbuffers are the only ones that report usage per member.
+    if (ST->getStructNumElements() < 2) {
+      continue;
+    }
+
+    // Create offset maps for legacy layout and new compact layout, while resetting usage flags
+    const StructLayout *SL = DL.getStructLayout(ST);
+    FieldAnnotationByOffsetMap legacyFieldMap, newFieldMap;
+    for (unsigned i = 0; i < SA->GetNumFields(); ++i) {
+      DxilFieldAnnotation &FA = SA->GetFieldAnnotation(i);
+      FA.SetCBVarUsed(false);
+      legacyFieldMap[FA.GetCBufferOffset()] = &FA;
+      newFieldMap[(unsigned)SL->getElementOffset(i)] = &FA;
+    }
+    CollectCBufferMemberUsage(GV, legacyFieldMap, newFieldMap, hlslOP, m_DM->GetUseMinPrecision());
+ }
+}
 
 
 char DxilLowerCreateHandleForLib::ID = 0;

+ 212 - 132
lib/HLSL/DxilContainerReflection.cpp

@@ -38,6 +38,8 @@
 #include "d3d12shader.h" // for compatibility
 #include "d3d11shader.h" // for compatibility
 
+#include "dxc/DxilContainer/DxilRuntimeReflection.h"
+
 const GUID IID_ID3D11ShaderReflection_43 = {
     0x0a233719,
     0x3960,
@@ -82,17 +84,19 @@ enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2 };
 
 class DxilModuleReflection {
 public:
-  CComPtr<IDxcBlob> m_pContainer;
+  hlsl::RDAT::DxilRuntimeData m_RDAT;
   LLVMContext Context;
   std::unique_ptr<Module> m_pModule; // Must come after LLVMContext, otherwise unique_ptr will over-delete.
   DxilModule *m_pDxilModule = nullptr;
+  bool m_bUsageInMetadata = false;
   std::vector<std::unique_ptr<CShaderReflectionConstantBuffer>>    m_CBs;
   std::vector<D3D12_SHADER_INPUT_BIND_DESC>       m_Resources;
   std::vector<std::unique_ptr<CShaderReflectionType>> m_Types;
   void CreateReflectionObjects();
   void CreateReflectionObjectForResource(DxilResourceBase *R);
 
-  HRESULT LoadModule(IDxcBlob *pBlob, const DxilPartHeader *pPart);
+  HRESULT LoadRDAT(const DxilPartHeader *pPart);
+  HRESULT LoadModule(const DxilPartHeader *pPart);
 
   // Common code
   ID3D12ShaderReflectionConstantBuffer* _GetConstantBufferByIndex(UINT Index);
@@ -150,7 +154,7 @@ public:
     return hr;
   }
 
-  HRESULT Load(IDxcBlob *pBlob, const DxilPartHeader *pPart);
+  HRESULT Load(const DxilPartHeader *pModulePart, const DxilPartHeader *pRDATPart);
 
   // ID3D12ShaderReflection
   STDMETHODIMP GetDesc(THIS_ _Out_ D3D12_SHADER_DESC *pDesc);
@@ -205,7 +209,6 @@ private:
   // Enable indexing into functions in deterministic order:
   std::vector<CFunctionReflection*> m_FunctionVector;
 
-  void AddResourceUseToFunctions(DxilResourceBase &resource, unsigned resIndex);
   void AddResourceDependencies();
   void SetCBufferUsage();
 
@@ -216,7 +219,7 @@ public:
     return DoBasicQueryInterface<ID3D12LibraryReflection>(this, iid, ppvObject);
   }
 
-  HRESULT Load(IDxcBlob *pBlob, const DxilPartHeader *pPart);
+  HRESULT Load(const DxilPartHeader *pModulePart, const DxilPartHeader *pDXILPart);
 
   // ID3D12LibraryReflection
   STDMETHOD(GetDesc)(THIS_ _Out_ D3D12_LIBRARY_DESC * pDesc);
@@ -224,6 +227,31 @@ public:
   STDMETHOD_(ID3D12FunctionReflection *, GetFunctionByIndex)(THIS_ _In_ INT FunctionIndex);
 };
 
+namespace hlsl {
+HRESULT CreateDxilShaderReflection(const DxilPartHeader *pModulePart, const DxilPartHeader *pRDATPart, REFIID iid, void **ppvObject) {
+  if (!ppvObject)
+    return E_INVALIDARG;
+  CComPtr<DxilShaderReflection> pReflection = DxilShaderReflection::Alloc(DxcGetThreadMallocNoRef());
+  IFROOM(pReflection.p);
+  PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
+  pReflection->SetPublicAPI(api);
+  // pRDATPart to be used for transition.
+  IFR(pReflection->Load(pModulePart, pRDATPart));
+  IFR(pReflection.p->QueryInterface(iid, ppvObject));
+  return S_OK;
+}
+HRESULT CreateDxilLibraryReflection(const DxilPartHeader *pModulePart, const DxilPartHeader *pRDATPart, REFIID iid, void **ppvObject) {
+  if (!ppvObject)
+    return E_INVALIDARG;
+  CComPtr<DxilLibraryReflection> pReflection = DxilLibraryReflection::Alloc(DxcGetThreadMallocNoRef());
+  IFROOM(pReflection.p);
+  // pRDATPart used for resource usage per-function.
+  IFR(pReflection->Load(pModulePart, pRDATPart));
+  IFR(pReflection.p->QueryInterface(iid, ppvObject));
+  return S_OK;
+}
+}
+
 _Use_decl_annotations_
 HRESULT DxilContainerReflection::Load(IDxcBlob *pContainer) {
 
@@ -311,32 +339,45 @@ HRESULT DxilContainerReflection::GetPartReflection(UINT32 idx, REFIID iid, void
   if (!IsLoaded()) return E_NOT_VALID_STATE;
   if (idx >= m_pHeader->PartCount) return E_BOUNDS;
   const DxilPartHeader *pPart = GetDxilContainerPart(m_pHeader, idx);
-  if (pPart->PartFourCC != DFCC_DXIL && pPart->PartFourCC != DFCC_ShaderDebugInfoDXIL) {
+  if (pPart->PartFourCC != DFCC_DXIL && pPart->PartFourCC != DFCC_ShaderDebugInfoDXIL &&
+      pPart->PartFourCC != DFCC_ShaderStatistics) {
     return E_NOTIMPL;
   }
+
+  // Use DFCC_ShaderStatistics for reflection instead of DXIL part, until switch
+  // to using RDAT for reflection instead of module.
+  const DxilPartHeader *pRDATPart = nullptr;
+  for (idx = 0; idx < m_pHeader->PartCount; ++idx) {
+    const DxilPartHeader *pPartTest = GetDxilContainerPart(m_pHeader, idx);
+    if (pPartTest->PartFourCC == DFCC_RuntimeData) {
+      pRDATPart = pPartTest;
+    }
+    if (pPart->PartFourCC != DFCC_ShaderStatistics) {
+      if (pPartTest->PartFourCC == DFCC_ShaderStatistics) {
+        const DxilProgramHeader *pProgramHeaderTest =
+          reinterpret_cast<const DxilProgramHeader*>(GetDxilPartData(pPartTest));
+        if (IsValidDxilProgramHeader(pProgramHeaderTest, pPartTest->PartSize)) {
+          pPart = pPartTest;
+          continue;
+        }
+      }
+    }
+  }
   
-  DxcThreadMalloc TM(m_pMalloc);
-  HRESULT hr = S_OK;
   const DxilProgramHeader *pProgramHeader =
     reinterpret_cast<const DxilProgramHeader*>(GetDxilPartData(pPart));
   if (!IsValidDxilProgramHeader(pProgramHeader, pPart->PartSize)) {
     return E_INVALIDARG;
   }
 
+  DxcThreadMalloc TM(m_pMalloc);
+  HRESULT hr = S_OK;
+
   DXIL::ShaderKind SK = GetVersionShaderType(pProgramHeader->ProgramVersion);
   if (SK == DXIL::ShaderKind::Library) {
-    CComPtr<DxilLibraryReflection> pReflection = DxilLibraryReflection::Alloc(m_pMalloc);
-    IFCOOM(pReflection.p);
-    IFC(pReflection->Load(m_container, pPart));
-    IFC(pReflection.p->QueryInterface(iid, ppvObject));
+    IFC(hlsl::CreateDxilLibraryReflection(pPart, pRDATPart, iid, ppvObject));
   } else {
-    CComPtr<DxilShaderReflection> pReflection = DxilShaderReflection::Alloc(m_pMalloc);
-    IFCOOM(pReflection.p);
-    PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
-    pReflection->SetPublicAPI(api);
-
-    IFC(pReflection->Load(m_container, pPart));
-    IFC(pReflection.p->QueryInterface(iid, ppvObject));
+    IFC(hlsl::CreateDxilShaderReflection(pPart, pRDATPart, iid, ppvObject));
   }
 
 Cleanup:
@@ -444,7 +485,8 @@ public:
 
   void Initialize(DxilModule &M,
                   DxilCBuffer &CB,
-                  std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes);
+                  std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes,
+                  bool bUsageInMetadata);
   void InitializeStructuredBuffer(DxilModule &M,
                                   DxilResource &R,
                                   std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes);
@@ -829,6 +871,7 @@ HRESULT CShaderReflectionType::Initialize(
   //
   // Note that DXIL supports some types that don't currently have equivalents
   // in the reflection interface, so we try to muddle through here.
+  bool bMinPrec = M.GetUseMinPrecision();
   D3D_SHADER_VARIABLE_TYPE componentType = D3D_SVT_VOID;
   switch(typeAnnotation.GetCompType().GetKind())
   {
@@ -842,12 +885,22 @@ HRESULT CShaderReflectionType::Initialize(
 
   case hlsl::DXIL::ComponentType::I16:
     componentType = D3D_SVT_MIN16INT;
-    m_Name = "min16int";
+    if (bMinPrec) {
+      m_Name = "min16int";
+    } else {
+      m_Name = "int16_t";
+      cbCompSize = 2;
+    }
     break;
 
   case hlsl::DXIL::ComponentType::U16:
     componentType = D3D_SVT_MIN16UINT;
-    m_Name = "min16uint";
+    if (bMinPrec) {
+      m_Name = "min16uint";
+    } else {
+      m_Name = "uint16_t";
+      cbCompSize = 2;
+    }
     break;
 
   case hlsl::DXIL::ComponentType::I64:
@@ -874,7 +927,12 @@ HRESULT CShaderReflectionType::Initialize(
   case hlsl::DXIL::ComponentType::SNormF16:
   case hlsl::DXIL::ComponentType::UNormF16:
     componentType = D3D_SVT_MIN16FLOAT;
-    m_Name = "min16float";
+    if (bMinPrec) {
+      m_Name = "min16float";
+    } else {
+      m_Name = "float16_t";
+      cbCompSize = 2;
+    }
     break;
 
   case hlsl::DXIL::ComponentType::F32:
@@ -1103,7 +1161,8 @@ HRESULT CShaderReflectionType::Initialize(
 void CShaderReflectionConstantBuffer::Initialize(
   DxilModule &M,
   DxilCBuffer &CB,
-  std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes) {
+  std::vector<std::unique_ptr<CShaderReflectionType>>& allTypes,
+  bool bUsageInMetadata) {
   ZeroMemory(&m_Desc, sizeof(m_Desc));
   m_Desc.Name = CB.GetGlobalName().c_str();
   m_Desc.Size = CB.GetSize();
@@ -1129,12 +1188,16 @@ void CShaderReflectionConstantBuffer::Initialize(
     DXASSERT(m_Desc.Variables == 1, "otherwise, assumption is wrong");
   }
 
+  // If only one member, it's used if it's here.
+  bool bAllUsed = ST->getNumContainedTypes() < 2;
+  bAllUsed |= !bUsageInMetadata;  // Will update in SetCBufferUsage.
+
   for (unsigned i = 0; i < ST->getNumContainedTypes(); ++i) {
     DxilFieldAnnotation &fieldAnnotation = annotation->GetFieldAnnotation(i);
 
     D3D12_SHADER_VARIABLE_DESC VarDesc;
     ZeroMemory(&VarDesc, sizeof(VarDesc));
-    VarDesc.uFlags |= D3D_SVF_USED; // Will update in SetCBufferUsage.
+    VarDesc.uFlags = (bAllUsed || fieldAnnotation.IsCBVarUsed()) ? D3D_SVF_USED : 0;
     CShaderReflectionVariable Var;
     //Create reflection type.
     CShaderReflectionType *pVarType = new CShaderReflectionType();
@@ -1211,7 +1274,7 @@ void CShaderReflectionConstantBuffer::InitializeStructuredBuffer(
   VarDesc.Size = CalcResTypeSize(M, R);
   VarDesc.StartTexture = UINT_MAX;
   VarDesc.StartSampler = UINT_MAX;
-  VarDesc.uFlags |= D3D_SVF_USED; // TODO: not necessarily true
+  VarDesc.uFlags |= D3D_SVF_USED;
   CShaderReflectionVariable Var;
   CShaderReflectionType *pVarType = nullptr;
 
@@ -1476,26 +1539,37 @@ static unsigned GetCBOffset(Value *V) {
   }
 }
 
-void CollectInPhiChain(PHINode *cbUser, std::vector<unsigned> &cbufUsage,
-                  unsigned offset, std::unordered_set<Value *> &userSet) {
+static unsigned GetOffsetForCBExtractValue(ExtractValueInst *EV, bool bMinPrecision) {
+  DXASSERT(EV->getNumIndices() == 1, "otherwise, unexpected indices/type for extractvalue");
+  unsigned typeSize = 4;
+  unsigned bits = EV->getType()->getScalarSizeInBits();
+  if (bits == 64)
+    typeSize = 8;
+  else if (bits == 16 && !bMinPrecision)
+    typeSize = 2;
+  return (EV->getIndices().front() * typeSize);
+}
+
+static void CollectInPhiChain(PHINode *cbUser, std::vector<unsigned> &cbufUsage,
+                              unsigned offset, std::unordered_set<Value *> &userSet,
+                              bool bMinPrecision) {
   if (userSet.count(cbUser) > 0)
     return;
 
   userSet.insert(cbUser);
   for (User *cbU : cbUser->users()) {
     if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
-      for (unsigned idx : EV->getIndices()) {
-        cbufUsage.emplace_back(offset + idx * 4);
-      }
+      cbufUsage.emplace_back(offset + GetOffsetForCBExtractValue(EV, bMinPrecision));
     } else {
       PHINode *phi = cast<PHINode>(cbU);
-      CollectInPhiChain(phi, cbufUsage, offset, userSet);
+      CollectInPhiChain(phi, cbufUsage, offset, userSet, bMinPrecision);
     }
   }
 }
 
 static void CollectCBufUsage(Value *cbHandle,
-                             std::vector<unsigned> &cbufUsage) {
+                             std::vector<unsigned> &cbufUsage,
+                             bool bMinPrecision) {
   for (User *U : cbHandle->users()) {
     CallInst *CI = cast<CallInst>(U);
     ConstantInt *opcodeV =
@@ -1509,13 +1583,11 @@ static void CollectCBufUsage(Value *cbHandle,
       offset <<= 4;
       for (User *cbU : U->users()) {
         if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(cbU)) {
-          for (unsigned idx : EV->getIndices()) {
-            cbufUsage.emplace_back(offset + idx * 4);
-          }
+          cbufUsage.emplace_back(offset + GetOffsetForCBExtractValue(EV, bMinPrecision));
         } else {
           PHINode *phi = cast<PHINode>(cbU);
           std::unordered_set<Value *> userSet;
-          CollectInPhiChain(phi, cbufUsage, offset, userSet);
+          CollectInPhiChain(phi, cbufUsage, offset, userSet, bMinPrecision);
         }
       }
     } else if (opcode == DXIL::OpCode::CBufferLoad) {
@@ -1531,7 +1603,7 @@ static void CollectCBufUsage(Value *cbHandle,
 }
 
 static void SetCBufVarUsage(CShaderReflectionConstantBuffer &cb,
-                            std::vector<unsigned> usage) {
+                            std::vector<unsigned> &usage) {
   D3D12_SHADER_BUFFER_DESC Desc;
   if (FAILED(cb.GetDesc(&Desc)))
     return;
@@ -1590,7 +1662,7 @@ void DxilShaderReflection::SetCBufferUsage() {
     ConstantInt *immResClass = cast<ConstantInt>(resClass);
     if (immResClass->getLimitedValue() == (unsigned)DXIL::ResourceClass::CBuffer) {
       ConstantInt *cbID = cast<ConstantInt>(handle.get_rangeId());
-      CollectCBufUsage(U, cbufUsage[cbID->getLimitedValue()]);
+      CollectCBufUsage(U, cbufUsage[cbID->getLimitedValue()], m_pDxilModule->GetUseMinPrecision());
     }
   }
 
@@ -1605,7 +1677,7 @@ void DxilModuleReflection::CreateReflectionObjects() {
   // Create constant buffers, resources and signatures.
   for (auto && cb : m_pDxilModule->GetCBuffers()) {
     std::unique_ptr<CShaderReflectionConstantBuffer> rcb(new CShaderReflectionConstantBuffer());
-    rcb->Initialize(*m_pDxilModule, *(cb.get()), m_Types);
+    rcb->Initialize(*m_pDxilModule, *(cb.get()), m_Types, m_bUsageInMetadata);
     m_CBs.emplace_back(std::move(rcb));
   }
 
@@ -1771,7 +1843,14 @@ void DxilShaderReflection::CreateReflectionObjectsForSignature(
     // D3D11_43 does not have MinPrecison.
     if (m_PublicAPI != PublicAPI::D3D11_43)
       Desc.MinPrecision = CompTypeToMinPrecision(SigElem->GetCompType());
-    Desc.ReadWriteMask = Sig.IsInput() ? 0 : Desc.Mask; // Start with output-never-written/input-never-read.
+    if (m_bUsageInMetadata) {
+      unsigned UsageMask = SigElem->GetUsageMask();
+      if (SigElem->IsAllocated())
+        UsageMask <<= SigElem->GetStartCol();
+      Desc.ReadWriteMask = Sig.IsInput() ? UsageMask : NegMask(UsageMask);
+    } else {
+      Desc.ReadWriteMask = Sig.IsInput() ? 0 : Desc.Mask; // Start with output-never-written/input-never-read.
+    }
     Desc.Register = SigElem->GetStartRow();
     Desc.Stream = SigElem->GetOutputStream();
     Desc.SystemValueType = SemanticToSystemValueType(SigElem->GetSemantic(), m_pDxilModule->GetTessellatorDomain());
@@ -1818,12 +1897,16 @@ LPCSTR DxilShaderReflection::CreateUpperCase(LPCSTR pValue) {
   return m_UpperCaseNames.back().get();
 }
 
-HRESULT DxilModuleReflection::LoadModule(IDxcBlob *pBlob,
-                                         const DxilPartHeader *pPart) {
-  DXASSERT_NOMSG(pBlob != nullptr);
-  DXASSERT_NOMSG(pPart != nullptr);
-  m_pContainer = pBlob;
-  const char *pData = GetDxilPartData(pPart);
+HRESULT DxilModuleReflection::LoadRDAT(const DxilPartHeader *pPart) {
+  if (pPart) {
+    IFRBOOL(m_RDAT.InitFromRDAT(GetDxilPartData(pPart), pPart->PartSize), DXC_E_CONTAINER_INVALID);
+  }
+  return S_OK;
+}
+
+HRESULT DxilModuleReflection::LoadModule(const DxilPartHeader *pShaderPart) {
+  DXASSERT_NOMSG(pShaderPart != nullptr);
+  const char *pData = GetDxilPartData(pShaderPart);
   try {
     const char *pBitcode;
     uint32_t bitcodeLength;
@@ -1842,25 +1925,33 @@ HRESULT DxilModuleReflection::LoadModule(IDxcBlob *pBlob,
     }
     std::swap(m_pModule, module.get());
     m_pDxilModule = &m_pModule->GetOrCreateDxilModule();
+
+    unsigned ValMajor, ValMinor;
+    m_pDxilModule->GetValidatorVersion(ValMajor, ValMinor);
+    m_bUsageInMetadata = hlsl::DXIL::CompareVersions(ValMajor, ValMinor, 1, 5) >= 0;
+
     CreateReflectionObjects();
     return S_OK;
   }
   CATCH_CPP_RETURN_HRESULT();
 };
 
-HRESULT DxilShaderReflection::Load(IDxcBlob *pBlob,
-                                   const DxilPartHeader *pPart) {
-  IFR(LoadModule(pBlob, pPart));
+HRESULT DxilShaderReflection::Load(const DxilPartHeader *pModulePart,
+                                   const DxilPartHeader *pRDATPart) {
+  IFR(LoadRDAT(pRDATPart));
+  IFR(LoadModule(pModulePart));
 
   try {
     // Set cbuf usage.
-    SetCBufferUsage();
+    if (!m_bUsageInMetadata)
+      SetCBufferUsage();
 
     // Populate input/output/patch constant signatures.
     CreateReflectionObjectsForSignature(m_pDxilModule->GetInputSignature(), m_InputSignature);
     CreateReflectionObjectsForSignature(m_pDxilModule->GetOutputSignature(), m_OutputSignature);
     CreateReflectionObjectsForSignature(m_pDxilModule->GetPatchConstOrPrimSignature(), m_PatchConstantSignature);
-    MarkUsedSignatureElements();
+    if (!m_bUsageInMetadata)
+      MarkUsedSignatureElements();
     return S_OK;
   }
   CATCH_CPP_RETURN_HRESULT();
@@ -1952,37 +2043,51 @@ void DxilShaderReflection::MarkUsedSignatureElements() {
     DxilInst_StoreOutput SO(&*I);
     DxilInst_LoadPatchConstant LPC(&*I);
     DxilInst_StorePatchConstant SPC(&*I);
+    DxilInst_StoreVertexOutput SVO(&*I);
+    DxilInst_StorePrimitiveOutput SPO(&*I);
     std::vector<D3D12_SIGNATURE_PARAMETER_DESC> *pDescs;
     const DxilSignature *pSig;
     uint32_t col, row, sigId;
     if (LI) {
       if (!GetUnsignedVal(LI.get_inputSigId(), &sigId)) continue;
       if (!GetUnsignedVal(LI.get_colIndex(), &col)) continue;
-      if (!GetUnsignedVal(LI.get_rowIndex(), &row)) continue;
+      GetUnsignedVal(LI.get_rowIndex(), &row);
       pDescs = &m_InputSignature;
       pSig = &m_pDxilModule->GetInputSignature();
     }
     else if (SO) {
       if (!GetUnsignedVal(SO.get_outputSigId(), &sigId)) continue;
       if (!GetUnsignedVal(SO.get_colIndex(), &col)) continue;
-      if (!GetUnsignedVal(SO.get_rowIndex(), &row)) continue;
+      GetUnsignedVal(SO.get_rowIndex(), &row);
       pDescs = &m_OutputSignature;
       pSig = &m_pDxilModule->GetOutputSignature();
     }
     else if (SPC) {
       if (!GetUnsignedVal(SPC.get_outputSigID(), &sigId)) continue;
       if (!GetUnsignedVal(SPC.get_col(), &col)) continue;
-      if (!GetUnsignedVal(SPC.get_row(), &row)) continue;
+      GetUnsignedVal(SPC.get_row(), &row);
       pDescs = &m_PatchConstantSignature;
       pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
     }
     else if (LPC) {
       if (!GetUnsignedVal(LPC.get_inputSigId(), &sigId)) continue;
       if (!GetUnsignedVal(LPC.get_col(), &col)) continue;
-      if (!GetUnsignedVal(LPC.get_row(), &row)) continue;
+      GetUnsignedVal(LPC.get_row(), &row);
       pDescs = &m_PatchConstantSignature;
       pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
     }
+    else if (SVO) {
+      if (!GetUnsignedVal(SVO.get_outputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(SVO.get_colIndex(), &col)) continue;
+      GetUnsignedVal(SVO.get_rowIndex(), &row);
+      pSig = &m_pDxilModule->GetOutputSignature();
+    }
+    else if (SPO) {
+      if (!GetUnsignedVal(SPO.get_outputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(SPO.get_colIndex(), &col)) continue;
+      GetUnsignedVal(SPO.get_rowIndex(), &row);
+      pSig = &m_pDxilModule->GetPatchConstOrPrimSignature();
+    }
     else {
       continue;
     }
@@ -2328,94 +2433,67 @@ HRESULT CFunctionReflection::GetResourceBindingDescByName(LPCSTR Name,
 
 // DxilLibraryReflection
 
-// From DxilContainerAssembler:
-static llvm::Function *FindUsingFunction(llvm::Value *User) {
-  if (llvm::Instruction *I = dyn_cast<llvm::Instruction>(User)) {
-    // Instruction should be inside a basic block, which is in a function
-    return cast<llvm::Function>(I->getParent()->getParent());
-  }
-  // User can be either instruction, constant, or operator. But User is an
-  // operator only if constant is a scalar value, not resource pointer.
-  llvm::Constant *CU = cast<llvm::Constant>(User);
-  if (!CU->user_empty())
-    return FindUsingFunction(*CU->user_begin());
-  else
-    return nullptr;
-}
-
-void DxilLibraryReflection::AddResourceUseToFunctions(DxilResourceBase &resource, unsigned resIndex) {
-  Constant *var = resource.GetGlobalSymbol();
-  if (var) {
-    for (auto user : var->users()) {
-      // Find the function.
-      if (llvm::Function *F = FindUsingFunction(user)) {
-        auto funcReflector = m_FunctionsByPtr[F];
-        funcReflector->AddResourceReference(resIndex);
-        if (resource.GetClass() == DXIL::ResourceClass::CBuffer) {
-          funcReflector->AddCBReference(resource.GetID());
-        }
-      }
-    }
-  }
-}
-
 void DxilLibraryReflection::AddResourceDependencies() {
+  RDAT::FunctionTableReader *functionTable = m_RDAT.GetFunctionTableReader();
+  m_FunctionVector.clear();
+  m_FunctionVector.reserve(functionTable->GetNumFunctions());
   std::map<StringRef, CFunctionReflection*> orderedMap;
-  for (auto &F : m_pModule->functions()) {
-    if (F.isDeclaration())
-      continue;
-    auto &func = m_FunctionMap[F.getName()];
+
+  RDAT::ResourceTableReader *resourceTable = m_RDAT.GetResourceTableReader();
+  unsigned SamplersStart = resourceTable->GetNumCBuffers();
+  unsigned SRVsStart = SamplersStart + resourceTable->GetNumSamplers();
+  unsigned UAVsStart = SRVsStart + resourceTable->GetNumSRVs();
+  IFTBOOL(resourceTable->GetNumResources() == m_Resources.size(),
+          DXC_E_INCORRECT_DXIL_METADATA);
+
+  for (unsigned iFunc = 0; iFunc < functionTable->GetNumFunctions(); ++iFunc) {
+    RDAT::FunctionReader FR = functionTable->GetItem(iFunc);
+    auto &func = m_FunctionMap[FR.GetName()];
     DXASSERT(!func.get(), "otherwise duplicate named functions");
+    Function *F = m_pModule->getFunction(FR.GetName());
     func.reset(new CFunctionReflection());
-    func->Initialize(this, &F);
-    m_FunctionsByPtr[&F] = func.get();
-    orderedMap[F.getName()] = func.get();
+    func->Initialize(this, F);
+    m_FunctionsByPtr[F] = func.get();
+    orderedMap[FR.GetName()] = func.get();
+
+    for (unsigned iRes = 0; iRes < FR.GetNumResources(); ++iRes) {
+      RDAT::ResourceReader RR = FR.GetResource(iRes);
+      unsigned id = RR.GetID();
+      switch (RR.GetResourceClass()) {
+      case DXIL::ResourceClass::CBuffer:
+        func->AddResourceReference(id);
+        func->AddCBReference(id);
+        break;
+      case DXIL::ResourceClass::Sampler:
+        func->AddResourceReference(SamplersStart + id);
+        break;
+      case DXIL::ResourceClass::SRV:
+        func->AddResourceReference(SRVsStart + id);
+        break;
+      case DXIL::ResourceClass::UAV:
+        func->AddResourceReference(UAVsStart + id);
+        break;
+      default:
+        DXASSERT(false, "Unrecognized ResourceClass in RDAT");
+      }
+    }
   }
-  // Fill in function vector sorted by name
-  m_FunctionVector.clear();
-  m_FunctionVector.reserve(orderedMap.size());
+
   for (auto &it : orderedMap) {
     m_FunctionVector.push_back(it.second);
   }
-  UINT resIndex = 0;
-  for (auto &resource : m_Resources) {
-    switch ((UINT32)resource.Type) {
-    case D3D_SIT_CBUFFER:
-      AddResourceUseToFunctions(m_pDxilModule->GetCBuffer(resource.uID), resIndex);
-      break;
-    case D3D_SIT_TBUFFER:   // TODO: Handle when TBuffers are added to CB list
-    case D3D_SIT_TEXTURE:
-    case D3D_SIT_STRUCTURED:
-    case D3D_SIT_BYTEADDRESS:
-    case D3D_SIT_RTACCELERATIONSTRUCTURE:
-      AddResourceUseToFunctions(m_pDxilModule->GetSRV(resource.uID), resIndex);
-      break;
-    case D3D_SIT_UAV_RWTYPED:
-    case D3D_SIT_UAV_RWSTRUCTURED:
-    case D3D_SIT_UAV_RWBYTEADDRESS:
-    case D3D_SIT_UAV_APPEND_STRUCTURED:
-    case D3D_SIT_UAV_CONSUME_STRUCTURED:
-    case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER:
-      AddResourceUseToFunctions(m_pDxilModule->GetUAV(resource.uID), resIndex);
-      break;
-    case D3D_SIT_SAMPLER:
-      AddResourceUseToFunctions(m_pDxilModule->GetSampler(resource.uID), resIndex);
-      break;
-    }
-    resIndex++;
-  }
 }
 
-static void CollectCBufUsageForLib(Value *V, std::vector<unsigned> &cbufUsage) {
+static void CollectCBufUsageForLib(Value *V, std::vector<unsigned> &cbufUsage, bool bMinPrecision) {
   for (auto user : V->users()) {
     Value *V = user;
     if (auto *CI = dyn_cast<CallInst>(V)) {
       if (hlsl::OP::IsDxilOpFuncCallInst(CI, hlsl::OP::OpCode::CreateHandleForLib)) {
-        CollectCBufUsage(CI, cbufUsage);
+        CollectCBufUsage(CI, cbufUsage, bMinPrecision);
       }
     } else if (isa<GEPOperator>(V) ||
                isa<LoadInst>(V)) {
-      CollectCBufUsageForLib(user, cbufUsage);
+      CollectCBufUsageForLib(user, cbufUsage, bMinPrecision);
     }
   }
 }
@@ -2425,7 +2503,7 @@ void DxilLibraryReflection::SetCBufferUsage() {
 
   for (unsigned i=0;i<cbSize;i++) {
     std::vector<unsigned> cbufUsage;
-    CollectCBufUsageForLib(m_pDxilModule->GetCBuffer(i).GetGlobalSymbol(), cbufUsage);
+    CollectCBufUsageForLib(m_pDxilModule->GetCBuffer(i).GetGlobalSymbol(), cbufUsage, m_pDxilModule->GetUseMinPrecision());
     SetCBufVarUsage(*m_CBs[i], cbufUsage);
   }
 }
@@ -2433,13 +2511,15 @@ void DxilLibraryReflection::SetCBufferUsage() {
 
 // ID3D12LibraryReflection
 
-HRESULT DxilLibraryReflection::Load(IDxcBlob *pBlob,
-  const DxilPartHeader *pPart) {
-  IFR(LoadModule(pBlob, pPart));
+HRESULT DxilLibraryReflection::Load(const DxilPartHeader *pModulePart,
+                                    const DxilPartHeader *pRDATPart) {
+  IFR(LoadRDAT(pRDATPart));
+  IFR(LoadModule(pModulePart));
 
   try {
     AddResourceDependencies();
-    SetCBufferUsage();
+    if (!m_bUsageInMetadata)
+      SetCBufferUsage();
     return S_OK;
   }
   CATCH_CPP_RETURN_HRESULT();

+ 112 - 3
lib/HLSL/DxilPreparePasses.cpp

@@ -17,6 +17,7 @@
 #include "dxc/DXIL/DxilTypeSystem.h"
 #include "dxc/DXIL/DxilUtil.h"
 #include "dxc/DXIL/DxilFunctionProps.h"
+#include "dxc/DXIL/DxilInstructions.h"
 #include "llvm/IR/GetElementPtrTypeIterator.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
@@ -246,6 +247,88 @@ void CheckInBoundForTGSM(GlobalVariable &GV, const DataLayout &DL) {
   }
 }
 
+static bool GetUnsignedVal(Value *V, uint32_t *pValue) {
+  ConstantInt *CI = dyn_cast<ConstantInt>(V);
+  if (!CI) return false;
+  uint64_t u = CI->getZExtValue();
+  if (u > UINT32_MAX) return false;
+  *pValue = (uint32_t)u;
+  return true;
+}
+
+static uint8_t NegMask(uint8_t V) {
+  V ^= 0xF;
+  return V & 0xF;
+}
+
+static void MarkUsedSignatureElements(Function *F, DxilModule &DM) {
+  DXASSERT_NOMSG(F != nullptr);
+  // For every loadInput/storeOutput, update the corresponding ReadWriteMask.
+  // F is a pointer to a Function instance
+  for (llvm::inst_iterator I = llvm::inst_begin(F), E = llvm::inst_end(F); I != E; ++I) {
+    DxilInst_LoadInput LI(&*I);
+    DxilInst_StoreOutput SO(&*I);
+    DxilInst_LoadPatchConstant LPC(&*I);
+    DxilInst_StorePatchConstant SPC(&*I);
+    DxilInst_StoreVertexOutput SVO(&*I);
+    DxilInst_StorePrimitiveOutput SPO(&*I);
+    DxilSignature *pSig;
+    uint32_t col, row, sigId;
+    bool bDynIdx = false;
+    if (LI) {
+      if (!GetUnsignedVal(LI.get_inputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(LI.get_colIndex(), &col)) continue;
+      if (!GetUnsignedVal(LI.get_rowIndex(), &row)) bDynIdx = true;
+      pSig = &DM.GetInputSignature();
+    }
+    else if (SO) {
+      if (!GetUnsignedVal(SO.get_outputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(SO.get_colIndex(), &col)) continue;
+      if (!GetUnsignedVal(SO.get_rowIndex(), &row)) bDynIdx = true;
+      pSig = &DM.GetOutputSignature();
+    }
+    else if (SPC) {
+      if (!GetUnsignedVal(SPC.get_outputSigID(), &sigId)) continue;
+      if (!GetUnsignedVal(SPC.get_col(), &col)) continue;
+      if (!GetUnsignedVal(SPC.get_row(), &row)) bDynIdx = true;
+      pSig = &DM.GetPatchConstOrPrimSignature();
+    }
+    else if (LPC) {
+      if (!GetUnsignedVal(LPC.get_inputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(LPC.get_col(), &col)) continue;
+      if (!GetUnsignedVal(LPC.get_row(), &row)) bDynIdx = true;
+      pSig = &DM.GetPatchConstOrPrimSignature();
+    }
+    else if (SVO) {
+      if (!GetUnsignedVal(SVO.get_outputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(SVO.get_colIndex(), &col)) continue;
+      if (!GetUnsignedVal(SVO.get_rowIndex(), &row)) bDynIdx = true;
+      pSig = &DM.GetOutputSignature();
+    }
+    else if (SPO) {
+      if (!GetUnsignedVal(SPO.get_outputSigId(), &sigId)) continue;
+      if (!GetUnsignedVal(SPO.get_colIndex(), &col)) continue;
+      if (!GetUnsignedVal(SPO.get_rowIndex(), &row)) bDynIdx = true;
+      pSig = &DM.GetPatchConstOrPrimSignature();
+    }
+    else {
+      continue;
+    }
+
+    // Consider being more fine-grained about masks.
+    // We report sometimes-read on input as always-read.
+    auto &El = pSig->GetElement(sigId);
+    unsigned UsageMask = El.GetUsageMask();
+    unsigned colBit = 1 << col;
+    if (!(colBit & UsageMask)) {
+      El.SetUsageMask(UsageMask | colBit);
+    }
+    if (bDynIdx && (El.GetDynIdxCompMask() & colBit) == 0) {
+      El.SetDynIdxCompMask(El.GetDynIdxCompMask() | colBit);
+    }
+  }
+}
+
 class DxilFinalizeModule : public ModulePass {
 public:
   static char ID; // Pass identification, replacement for typeid
@@ -283,16 +366,21 @@ public:
   bool runOnModule(Module &M) override {
     if (M.HasDxilModule()) {
       DxilModule &DM = M.GetDxilModule();
+      unsigned ValMajor = 0;
+      unsigned ValMinor = 0;
+      M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
 
       bool IsLib = DM.GetShaderModel()->IsLib();
       // Skip validation patch for lib.
       if (!IsLib) {
-        unsigned ValMajor = 0;
-        unsigned ValMinor = 0;
-        M.GetDxilModule().GetValidatorVersion(ValMajor, ValMinor);
         if (ValMajor == 1 && ValMinor <= 1) {
           patchValidation_1_1(M);
         }
+
+        // Set used masks for signature elements
+        MarkUsedSignatureElements(DM.GetEntryFunction(), DM);
+        if (DM.GetShaderModel()->IsHS())
+          MarkUsedSignatureElements(DM.GetPatchConstantFunction(), DM);
       }
 
       // Remove store undef output.
@@ -319,6 +407,11 @@ public:
       // Clear intermediate options that shouldn't be in the final DXIL
       DM.ClearIntermediateOptions();
 
+      if (IsLib && DXIL::CompareVersions(ValMajor, ValMinor, 1, 4) <= 0) {
+        // 1.4 validator requires function annotations for all functions
+        AddFunctionAnnotationForInitializers(M, DM);
+      }
+
       return true;
     }
 
@@ -468,6 +561,22 @@ private:
       }
     }
   }
+
+  void AddFunctionAnnotationForInitializers(Module &M, DxilModule &DM) {
+    if (GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors")) {
+      ConstantArray *init = cast<ConstantArray>(GV->getInitializer());
+      for (auto V : init->operand_values()) {
+        if (isa<ConstantAggregateZero>(V))
+          continue;
+        ConstantStruct *CS = cast<ConstantStruct>(V);
+        if (isa<ConstantPointerNull>(CS->getOperand(1)))
+          continue;
+        Function *F = cast<Function>(CS->getOperand(1));
+        if (DM.GetTypeSystem().GetFunctionAnnotation(F) == nullptr)
+          DM.GetTypeSystem().AddFunctionAnnotation(F);
+      }
+    }
+  }
 };
 }
 

+ 4 - 9
lib/HLSL/DxilValidation.cpp

@@ -104,7 +104,6 @@ const char *hlsl::GetValidationRuleText(ValidationRule value) {
     case hlsl::ValidationRule::MetaTessellatorOutputPrimitive: return "Invalid Tessellator Output Primitive specified. Must be point, line, triangleCW or triangleCCW.";
     case hlsl::ValidationRule::MetaMaxTessFactor: return "Hull Shader MaxTessFactor must be [%0..%1].  %2 specified";
     case hlsl::ValidationRule::MetaValidSamplerMode: return "Invalid sampler mode on sampler ";
-    case hlsl::ValidationRule::MetaFunctionAnnotation: return "Cannot find function annotation for %0";
     case hlsl::ValidationRule::MetaGlcNotOnAppendConsume: return "globallycoherent cannot be used with append/consume buffers";
     case hlsl::ValidationRule::MetaStructBufAlignment: return "structured buffer element size must be a multiple of %0 bytes (actual size %1 bytes)";
     case hlsl::ValidationRule::MetaStructBufAlignmentOutOfBound: return "structured buffer elements cannot be larger than %0 bytes (actual size %1 bytes)";
@@ -3593,13 +3592,6 @@ static void ValidateFunction(Function &F, ValidationContext &ValCtx) {
     if (isShader && !F.getReturnType()->isVoidTy())
       ValCtx.EmitFormatError(ValidationRule::DeclShaderReturnVoid, { F.getName() });
 
-    DxilFunctionAnnotation *funcAnnotation =
-        ValCtx.DxilMod.GetTypeSystem().GetFunctionAnnotation(&F);
-    if (!funcAnnotation) {
-      ValCtx.EmitFormatError(ValidationRule::MetaFunctionAnnotation, { F.getName() });
-      return;
-    }
-
     auto ArgFormatError = [&](Argument &arg, ValidationRule rule) {
       if (arg.hasName())
         ValCtx.EmitFormatError(rule, { arg.getName().str(), F.getName() });
@@ -5727,7 +5719,10 @@ static void VerifySignatureMatches(_In_ ValidationContext &ValCtx,
     pName = "Program Output Signature";
     break;
   case hlsl::DXIL::SignatureKind::PatchConstOrPrim:
-    pName = "Program Patch Constant or Primitive Signature";
+    if (ValCtx.DxilMod.GetShaderModel()->GetKind() == DXIL::ShaderKind::Mesh)
+      pName = "Program Primitive Signature";
+    else
+      pName = "Program Patch Constant Signature";
     break;
   default:
     break;

+ 2 - 8
lib/Transforms/IPO/GlobalDCE.cpp

@@ -25,10 +25,6 @@
 #include "llvm/Transforms/Utils/GlobalStatus.h"
 #include "llvm/Pass.h"
 #include <unordered_map>
-#include "dxc/HLSL/HLModule.h" // HLSL Change
-#include "dxc/DXIL/DxilModule.h" // HLSL Change
-#include "dxc/DXIL/DxilOperations.h" // HLSL Change
-#include "dxc/DXIL/DxilInstructions.h" // HLSL Change
 using namespace llvm;
 
 #define DEBUG_TYPE "globaldce"
@@ -166,14 +162,12 @@ bool GlobalDCE::runOnModule(Module &M) {
       I->setAliasee(nullptr);
     } 
 
-  hlsl::HLModule *HLM = M.HasHLModule() ? &M.GetHLModule() : nullptr; // HLSL Change
-
   if (!DeadFunctions.empty()) {
     // Now that all interferences have been dropped, delete the actual objects
     // themselves.
     for (unsigned i = 0, e = DeadFunctions.size(); i != e; ++i) {
       RemoveUnusedGlobalValue(*DeadFunctions[i]);
-      if (HLM != nullptr) HLM->RemoveFunction(DeadFunctions[i]); // HLSL Change
+      M.CallRemoveGlobalHook(DeadFunctions[i]); // HLSL Change
       M.getFunctionList().erase(DeadFunctions[i]);
     }
     NumFunctions += DeadFunctions.size();
@@ -183,7 +177,7 @@ bool GlobalDCE::runOnModule(Module &M) {
   if (!DeadGlobalVars.empty()) {
     for (unsigned i = 0, e = DeadGlobalVars.size(); i != e; ++i) {
       RemoveUnusedGlobalValue(*DeadGlobalVars[i]);
-      if (HLM != nullptr) HLM->RemoveGlobal(DeadGlobalVars[i]); // HLSL Change
+      M.CallRemoveGlobalHook(DeadGlobalVars[i]); // HLSL Change
       M.getGlobalList().erase(DeadGlobalVars[i]);
     }
     NumVariables += DeadGlobalVars.size();

+ 16 - 9
tools/clang/lib/CodeGen/CGHLSLMS.cpp

@@ -366,6 +366,22 @@ CGMSHLSLRuntime::CGMSHLSLRuntime(CodeGenModule &CGM)
     Diags.Report(DiagID) << CGM.getCodeGenOpts().HLSLProfile;
     return;
   }
+  if (CGM.getCodeGenOpts().HLSLValidatorMajorVer != 0) {
+    // Check validator version against minimum for target profile:
+    unsigned MinMajor, MinMinor;
+    SM->GetMinValidatorVersion(MinMajor, MinMinor);
+    if (DXIL::CompareVersions(CGM.getCodeGenOpts().HLSLValidatorMajorVer,
+                              CGM.getCodeGenOpts().HLSLValidatorMinorVer,
+                              MinMajor, MinMinor) < 0) {
+      DiagnosticsEngine &Diags = CGM.getDiags();
+      unsigned DiagID =
+          Diags.getCustomDiagID(DiagnosticsEngine::Error,
+            "validator version %0,%1 does not support target profile.");
+      Diags.Report(DiagID) << CGM.getCodeGenOpts().HLSLValidatorMajorVer
+                           << CGM.getCodeGenOpts().HLSLValidatorMinorVer;
+      return;
+    }
+  }
   m_bIsLib = SM->IsLib();
   // TODO: add AllResourceBound.
   if (CGM.getCodeGenOpts().HLSLAvoidControlFlow && !CGM.getCodeGenOpts().HLSLAllResourcesBound) {
@@ -2443,15 +2459,6 @@ void CGMSHLSLRuntime::addSubobject(Decl *D) {
   VarDecl *VD = dyn_cast<VarDecl>(D);
   DXASSERT(VD != nullptr, "must be a global variable");
 
-  if (CGM.getCodeGenOpts().HLSLValidatorMajorVer == 1 &&
-      CGM.getCodeGenOpts().HLSLValidatorMinorVer < 4) {
-    // subobjects unsupported with this validator
-    DiagnosticsEngine &Diags = CGM.getDiags();
-    unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "subobjects are not supported by current validator version");
-    Diags.Report(D->getLocStart(), DiagID);
-    return;
-  }
- 
   DXIL::SubobjectKind subobjKind;
   DXIL::HitGroupType hgType;
   if (!hlsl::GetHLSLSubobjectKind(VD->getType(), subobjKind, hgType)) {

+ 3 - 4
tools/clang/test/CodeGenHLSL/batch/compiler_options/Qstrip_reflect.hlsl

@@ -1,8 +1,7 @@
-// RUN: %dxc -E main -T ps_6_0 %s -Qstrip_reflect | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T ps_6_0 %s -Qstrip_reflect | FileCheck %s
 
-// Make sure only function annotation, no struct annotation.
-// CHECK:!dx.typeAnnotations = !{[[FuncAnnot:[^,]+]]}
-// CHECK:[[FuncAnnot]] = !{i32 1, void ()* @main,
+// Make sure there are no type annotations
+// CHECK-NOT: !dx.typeAnnotations
 
 //--------------------------------------------------------------------------------------
 // File: BasicHLSL11_PS.hlsl

+ 3 - 4
tools/clang/test/CodeGenHLSL/batch/compiler_options/Qstrip_reflect_struct_buf.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_2 -enable-16bit-types -HV 2018 -Qstrip_reflect %s  | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T ps_6_2 -enable-16bit-types -HV 2018 -Qstrip_reflect %s  | FileCheck %s
 
 
 struct MyStruct1
@@ -76,6 +76,5 @@ float4 main() : SV_Target {
     return 1;
 }
 
-// Make sure only function annotation, no struct annotation.
-// CHECK:!dx.typeAnnotations = !{[[FuncAnnot:[^,]+]]}
-// CHECK:[[FuncAnnot]] = !{i32 1, void ()* @main,
+// Make sure there are no type annotations
+// CHECK-NOT: !dx.typeAnnotations

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/optimized2.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 -pack_optimized %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 -pack_optimized %s | FileCheck %s
 
 // CHECK:      ; Output signature:
 // CHECK:      ; Name                 Index   Mask Register SysValue  Format   Used

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/optimized3.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 -pack_optimized %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 -pack_optimized %s | FileCheck %s
 
 // CHECK:      ; Output signature:
 // CHECK:      ; Name                 Index   Mask Register SysValue  Format   Used

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/prefix_stable2.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 -pack_prefix_stable %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 -pack_prefix_stable %s | FileCheck %s
 
 // CHECK:      ; Output signature:
 // CHECK:      ; Name                 Index   Mask Register SysValue  Format   Used

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/compiler_options/pack_clip_cull/prefix_stable3.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 -pack_prefix_stable %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 -pack_prefix_stable %s | FileCheck %s
 
 // CHECK:      ; Output signature:
 // CHECK:      ; Name                 Index   Mask Register SysValue  Format   Used

+ 2 - 2
tools/clang/test/CodeGenHLSL/batch/debug/locals/scalarized_vector.hlsl

@@ -4,8 +4,8 @@
 
 // CHECK: %[[x:.*]] = add i32
 // CHECK: %[[y:.*]] = add i32
-// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %[[x]], i64 0, metadata ![[vec:.*]], metadata ![[xexp:.*]]), !dbg !46
-// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %[[y]], i64 0, metadata ![[vec]], metadata ![[yexp:.*]]), !dbg !46
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %[[x]], i64 0, metadata ![[vec:.*]], metadata ![[xexp:.*]])
+// CHECK-DAG: call void @llvm.dbg.value(metadata i32 %[[y]], i64 0, metadata ![[vec]], metadata ![[yexp:.*]])
 
 // Exclude quoted source file (see readme)
 // CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}

+ 2 - 2
tools/clang/test/CodeGenHLSL/batch/debug/misc/share_mem_dbg.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T cs_6_0 -Zi -Od -DDefineA -DDefineB=0 %s | FileCheck %s
+// RUN: %dxc -E main -T cs_6_0 -Zi -Od -DDefineA -DDefineB=0 %s -Qstrip_reflect | FileCheck %s
 
 // CHECK: threadId
 // CHECK: groupId
@@ -22,7 +22,7 @@
 // Make sure source info contents exist.
 // CHECK: !{!"DefineA=1", !"DefineB=0"}
 // CHECK: share_mem_dbg.hlsl"}
-// CHECK: !{!"-E", !"main", !"-T", !"cs_6_0", !"-Zi", !"-Od", !"-D", !"DefineA", !"-D", !"DefineB=0"}
+// CHECK: !{!"-E", !"main", !"-T", !"cs_6_0", !"-Zi", !"-Od", !"-D", !"DefineA", !"-D", !"DefineB=0", !"-Qstrip_reflect"}
 
 
 struct S {

+ 2 - 2
tools/clang/test/CodeGenHLSL/batch/debug/types/struct_resource_numerical.hlsl

@@ -10,8 +10,8 @@
 // Texture types are currently 64 bits due to an implementation detail.
 // If this changes, this test can be safely updated.
 // CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "TexAndCoord", {{.*}}, size: 96, align: 32
-// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "tex", scope: !53, {{.*}}, size: 64, align: 32
-// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "u", scope: !53, {{.*}}, size: 32, align: 32, offset: 64
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "tex", scope: {{.*}}, size: 64, align: 32
+// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "u", scope: {{.*}}, size: 32, align: 32, offset: 64
 
 // The bit_piece for 'tc.u' should be right after the texture.
 // CHECK-DAG: !DIExpression(DW_OP_bit_piece, 64, 32)

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/declarations/resources/constant_buffers/array1.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T ps_6_0 %s | FileCheck %s
 
 
 // CHECK: cbuffer $Globals

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/cb_sizes.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
 
 // Verify CB variable sizes align with expectations.
 // This also tests some matrix, struct, and array cases that may

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/cbuf-usage-lib.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -auto-binding-space 13 -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -auto-binding-space 13 -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
 
 // Make sure usage flag is set properly for cbuffers used in libraries
 

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/empty_struct2.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
 
 // Make sure nest empty struct works.
 

+ 125 - 0
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/lib_global.hlsl

@@ -0,0 +1,125 @@
+// RUN: %dxilver 1.5 | %dxc -T lib_6_3 -enable-16bit-types %s | %D3DReflect %s | FileCheck %s
+
+// Note: validator version 1.5 is required because these tests use
+// module disassembly -> reassembly between steps, and type annotations
+// compatible with the 1.4 validator does not have usage metadata, so it's lost.
+
+// Make sure CB usage is correct.
+#if 0
+// CHECK: ID3D12LibraryReflection:
+// CHECK-NEXT:   D3D12_LIBRARY_DESC:
+// CHECK-NEXT:     Creator: <nullptr>
+// CHECK-NEXT:     Flags: 0
+// CHECK-NEXT:     FunctionCount: 2
+// CHECK-NEXT:   ID3D12FunctionReflection:
+// CHECK-NEXT:     D3D12_FUNCTION_DESC: Name: _GLOBAL__sub_I_lib_global.hlsl
+// CHECK-NEXT:       Shader Version: Library 6.3
+// CHECK-NEXT:       Creator: <nullptr>
+// CHECK-NEXT:       Flags: 0
+// CHECK-NEXT:       ConstantBuffers: 1
+// CHECK-NEXT:       BoundResources: 1
+// CHECK-NEXT:       FunctionParameterCount: 0
+// CHECK-NEXT:       HasReturn: FALSE
+// CHECK-NEXT:     Constant Buffers:
+// CHECK-NEXT:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK-NEXT:         D3D12_SHADER_BUFFER_DESC: Name: X
+// CHECK-NEXT:           Type: D3D_CT_CBUFFER
+// CHECK-NEXT:           Size: 16
+// CHECK-NEXT:           uFlags: 0
+// CHECK-NEXT:           Num Variables: 2
+// CHECK-NEXT:         {
+// CHECK-NEXT:           ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:             D3D12_SHADER_VARIABLE_DESC: Name: e
+// CHECK-NEXT:               Size: 2
+// CHECK-NEXT:               StartOffset: 0
+// CHECK-NEXT:               uFlags: 0
+// CHECK-NEXT:               DefaultValue: <nullptr>
+// CHECK-NEXT:             ID3D12ShaderReflectionType:
+// CHECK-NEXT:               D3D12_SHADER_TYPE_DESC: Name: float16_t
+// CHECK-NEXT:                 Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                 Type: D3D_SVT_MIN16FLOAT
+// CHECK-NEXT:                 Elements: 0
+// CHECK-NEXT:                 Rows: 1
+// CHECK-NEXT:                 Columns: 1
+// CHECK-NEXT:                 Members: 0
+// CHECK-NEXT:                 Offset: 0
+// CHECK-NEXT:             CBuffer: X
+// CHECK-NEXT:           ID3D12ShaderReflectionVariable:
+// CHECK-NEXT:             D3D12_SHADER_VARIABLE_DESC: Name: f
+// CHECK-NEXT:               Size: 2
+// CHECK-NEXT:               StartOffset: 2
+// CHECK-NEXT:               uFlags: 0x2
+// CHECK-NEXT:               DefaultValue: <nullptr>
+// CHECK-NEXT:             ID3D12ShaderReflectionType:
+// CHECK-NEXT:               D3D12_SHADER_TYPE_DESC: Name: float16_t
+// CHECK-NEXT:                 Class: D3D_SVC_SCALAR
+// CHECK-NEXT:                 Type: D3D_SVT_MIN16FLOAT
+// CHECK-NEXT:                 Elements: 0
+// CHECK-NEXT:                 Rows: 1
+// CHECK-NEXT:                 Columns: 1
+// CHECK-NEXT:                 Members: 0
+// CHECK-NEXT:                 Offset: 0
+// CHECK-NEXT:             CBuffer: X
+// CHECK-NEXT:         }
+// CHECK-NEXT:     Bound Resources:
+// CHECK-NEXT:       D3D12_SHADER_BUFFER_DESC: Name: X
+// CHECK-NEXT:         Type: D3D_SIT_CBUFFER
+// CHECK-NEXT:         uID: 0
+// CHECK-NEXT:         BindCount: 1
+// CHECK-NEXT:         BindPoint: 4294967295
+// CHECK-NEXT:         Space: 4294967295
+// CHECK-NEXT:         ReturnType: <unknown: 0>
+// CHECK-NEXT:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:         NumSamples (or stride): 0
+// CHECK-NEXT:         uFlags: 0
+// CHECK-NEXT:   ID3D12FunctionReflection:
+// CHECK-NEXT:     D3D12_FUNCTION_DESC: Name: test
+// CHECK-NEXT:       Shader Version: Pixel 6.3
+// CHECK-NEXT:       Creator: <nullptr>
+// CHECK-NEXT:       Flags: 0
+// CHECK-NEXT:       ConstantBuffers: 0
+// CHECK-NEXT:       BoundResources: 2
+// CHECK-NEXT:       FunctionParameterCount: 0
+// CHECK-NEXT:       HasReturn: FALSE
+// CHECK-NEXT:     Bound Resources:
+// CHECK-NEXT:       D3D12_SHADER_BUFFER_DESC: Name: g_samLinear
+// CHECK-NEXT:         Type: D3D_SIT_SAMPLER
+// CHECK-NEXT:         uID: 0
+// CHECK-NEXT:         BindCount: 1
+// CHECK-NEXT:         BindPoint: 4294967295
+// CHECK-NEXT:         Space: 4294967295
+// CHECK-NEXT:         ReturnType: <unknown: 0>
+// CHECK-NEXT:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK-NEXT:         NumSamples (or stride): 0
+// CHECK-NEXT:         uFlags: 0
+// CHECK-NEXT:       D3D12_SHADER_BUFFER_DESC: Name: g_txDiffuse
+// CHECK-NEXT:         Type: D3D_SIT_TEXTURE
+// CHECK-NEXT:         uID: 0
+// CHECK-NEXT:         BindCount: 1
+// CHECK-NEXT:         BindPoint: 4294967295
+// CHECK-NEXT:         Space: 4294967295
+// CHECK-NEXT:         ReturnType: D3D_RETURN_TYPE_FLOAT
+// CHECK-NEXT:         Dimension: D3D_SRV_DIMENSION_TEXTURE2D
+// CHECK-NEXT:         NumSamples (or stride): 4294967295
+// CHECK-NEXT:         uFlags: 0xc
+#endif
+
+Texture2D    g_txDiffuse;
+SamplerState    g_samLinear;
+
+cbuffer X {
+  half e, f;
+}
+
+static float g[2] = { 1, f };
+
+[shader("pixel")]
+float4 test(float2 c : C) : SV_TARGET
+{
+  float4 x = g_txDiffuse.Sample( g_samLinear, c );
+  return x + g[1];
+}
+
+void update() {
+  g[1]++;
+}

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/reflect-lib-1.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -T lib_6_3 -auto-binding-space 11 -default-linkage external %s | %D3DReflect %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -T lib_6_3 -auto-binding-space 11 -default-linkage external %s | %D3DReflect %s | FileCheck %s
 
 float cbval1;
 cbuffer MyCB : register(b11, space2) { int4 cbval2, cbval3; }

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/d3dreflect/structured_buffer_layout.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
 
 // Verify SB type description does not follow the CB offseting alignment
 // even when structure is shared with a ConstantBuffer.

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/sig-bool-as-uint.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -E main -T ps_6_0 %s | FileCheck %s
 
 // make sure bool maps to uint in signature
 // CHECK: ; BOOL                     0   x           0     NONE    uint

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/misc/static_const_global.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -T lib_6_3 -auto-binding-space 11 %s | FileCheck %s
 
 // Make sure ST is removed
 // CHECK-NOT: @ST

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/shader_stages/raytracing/subobjects_raytracingPipelineConfig1.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -T lib_6_3 %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -T lib_6_3 %s | FileCheck %s
 
 // CHECK: ; GlobalRootSignature grs = { <48 bytes> };
 // CHECK: ; StateObjectConfig soc = { STATE_OBJECT_FLAG_ALLOW_LOCAL_DEPENDENCIES_ON_EXTERNAL_DEFINITIONS | STATE_OBJECT_FLAG_ALLOW_STATE_OBJECT_ADDITIONS };

+ 1 - 1
tools/clang/test/CodeGenHLSL/batch/validation/rawbufferstore_uav.hlsl

@@ -1,4 +1,4 @@
-// RUN: %dxc -T vs_6_2 -E main %s | FileCheck %s
+// RUN: %dxilver 1.5 | %dxc -T vs_6_2 -E main %s | FileCheck %s
 
 // CHECK: store should be on uav resource
 

+ 4 - 1
tools/clang/test/CodeGenHLSL/lib_global.hlsl

@@ -4,7 +4,10 @@ Texture2D    g_txDiffuse;
 SamplerState    g_samLinear;
 
 cbuffer X {
-float f;
+  // Use min-precision type to force conversion of constant buffer type for legacy.
+  // This has to happen at link time at the moment, so this will break unless type
+  // annotations are retained for library.
+  min16float f;
 }
 
 static float g[2] = { 1, f };

+ 1 - 1
tools/clang/tools/dxcompiler/dxcassembler.cpp

@@ -141,7 +141,7 @@ HRESULT STDMETHODCALLTYPE DxcAssembler::AssembleToContainer(
     outStream.flush();
 
     CComPtr<IDxcBlob> pResultBlob;
-    hlsl::SerializeDxilFlags flags = hlsl::SerializeDxilFlags::None;
+    hlsl::SerializeDxilFlags flags = hlsl::SerializeDxilFlags::IncludeReflectionPart;
     if (HasDebugInfo(*M)) {
       flags |= SerializeDxilFlags::IncludeDebugInfoPart;
       flags |= SerializeDxilFlags::IncludeDebugNamePart;

+ 33 - 3
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -1549,6 +1549,8 @@ namespace dxcutil {
 HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
   const char *pIL = (const char *)pProgram->GetBufferPointer();
   uint32_t pILLength = pProgram->GetBufferSize();
+  const char *pReflectionIL = nullptr;
+  uint32_t pReflectionILLength = 0;
   const DxilPartHeader *pRDATPart = nullptr;
   if (const DxilContainerHeader *pContainer =
           IsDxilContainerLike(pIL, pILLength)) {
@@ -1649,6 +1651,18 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
     }
 
     GetDxilProgramBitcode(pProgramHeader, &pIL, &pILLength);
+
+    it = std::find_if(begin(pContainer), end(pContainer),
+                      DxilPartIsType(DFCC_ShaderStatistics));
+    if (it != end(pContainer)) {
+      // If this part exists, use it for reflection data, probably stripped from DXIL part.
+      const DxilProgramHeader *pReflectionProgramHeader =
+          reinterpret_cast<const DxilProgramHeader *>(GetDxilPartData(*it));
+      if (IsValidDxilProgramHeader(pReflectionProgramHeader, (*it)->PartSize)) {
+        GetDxilProgramBitcode(pReflectionProgramHeader, &pReflectionIL, &pReflectionILLength);
+      }
+    }
+
   } else {
     const DxilProgramHeader *pProgramHeader =
         reinterpret_cast<const DxilProgramHeader *>(pIL);
@@ -1665,8 +1679,20 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
     return DXC_E_IR_VERIFICATION_FAILED;
   }
 
+  std::unique_ptr<llvm::Module> pReflectionModule;
+  if (pReflectionIL && pReflectionILLength) {
+    pReflectionModule = dxilutil::LoadModuleFromBitcode(
+      llvm::StringRef(pReflectionIL, pReflectionILLength), llvmContext, DiagStr);
+    if (pReflectionModule.get() == nullptr) {
+      return DXC_E_IR_VERIFICATION_FAILED;
+    }
+  }
+
   if (pModule->getNamedMetadata("dx.version")) {
     DxilModule &dxilModule = pModule->GetOrCreateDxilModule();
+    DxilModule &dxilReflectionModule = pReflectionModule.get()
+      ? pReflectionModule->GetOrCreateDxilModule()
+      : dxilModule;
 
     if (!dxilModule.GetShaderModel()->IsLib()) {
       PrintDxilSignature("Input", dxilModule.GetInputSignature(), Stream,
@@ -1685,9 +1711,9 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
                            /*comment*/ ";");
       }
     }
-    PrintBufferDefinitions(dxilModule, Stream, /*comment*/ ";");
-    PrintResourceBindings(dxilModule, Stream, /*comment*/ ";");
-    PrintViewIdState(dxilModule, Stream, /*comment*/ ";");
+    PrintBufferDefinitions(dxilReflectionModule, Stream, /*comment*/ ";");
+    PrintResourceBindings(dxilReflectionModule, Stream, /*comment*/ ";");
+    PrintViewIdState(dxilReflectionModule, Stream, /*comment*/ ";");
 
     if (pRDATPart) {
       RDAT::DxilRuntimeData runtimeData(GetDxilPartData(pRDATPart), pRDATPart->PartSize);
@@ -1706,6 +1732,10 @@ HRESULT Disassemble(IDxcBlob *pProgram, raw_string_ostream &Stream) {
   }
   DxcAssemblyAnnotationWriter w;
   pModule->print(Stream, &w);
+  //if (pReflectionModule) {
+  //  Stream << "\n========== Reflection Module from STAT part ==========\n";
+  //  pReflectionModule->print(Stream, &w);
+  //}
   Stream.flush();
   return S_OK;
 }

+ 8 - 0
tools/clang/tools/dxcompiler/dxclinker.cpp

@@ -114,6 +114,8 @@ HRESULT
 DxcLinker::RegisterLibrary(_In_opt_ LPCWSTR pLibName, // Name of the library.
                            _In_ IDxcBlob *pBlob       // Library to add.
 ) {
+  if (!pLibName || !pBlob)
+    return E_INVALIDARG;
   DXASSERT(m_pLinker.get(), "else Initialize() not called or failed silently");
   DxcThreadMalloc TM(m_pMalloc);
   // Prepare UTF8-encoded versions of API values.
@@ -163,6 +165,8 @@ HRESULT STDMETHODCALLTYPE DxcLinker::Link(
     _COM_Outptr_ IDxcOperationResult *
         *ppResult // Linker output status, buffer, and errors
 ) {
+  if (!pTargetProfile || !pLibNames || libCount == 0 || !ppResult)
+    return E_INVALIDARG;
   DxcThreadMalloc TM(m_pMalloc);
   // Prepare UTF8-encoded versions of API values.
   CW2A pUtf8TargetProfile(pTargetProfile, CP_UTF8);
@@ -209,6 +213,10 @@ HRESULT STDMETHODCALLTYPE DxcLinker::Link(
     m_Ctx.setDiagnosticHandler(PrintDiagnosticContext::PrintDiagnosticHandler,
                                &DiagContext, true);
 
+    if (opts.ValVerMajor != UINT32_MAX) {
+      m_pLinker->SetValidatorVersion(opts.ValVerMajor, opts.ValVerMinor);
+    }
+
     // Attach libraries.
     bool bSuccess = true;
     for (unsigned i = 0; i < libCount; i++) {

+ 20 - 11
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -561,8 +561,6 @@ public:
 
       StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
                      utf8Source->GetBufferSize());
-      std::unique_ptr<llvm::MemoryBuffer> pBuffer(
-          llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
 
       // Not very efficient but also not very important.
       std::vector<std::string> defines;
@@ -616,19 +614,29 @@ public:
       // NOTE: this calls the validation component from dxil.dll; the built-in
       // validator can be used as a fallback.
       bool produceFullContainer = !opts.CodeGenHighLevel && !opts.AstDump && !opts.OptDump && rootSigMajor == 0;
-
       bool needsValidation = produceFullContainer && !opts.DisableValidation;
+
       // Disable validation for lib_6_1 and lib_6_2.
+      // This is needed for this API because the profile is provided separately,
+      // so the option parsing will not have verified that /Vd was provided.
       if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_1" ||
           compiler.getCodeGenOpts().HLSLProfile == "lib_6_2") {
         needsValidation = false;
       }
 
-      if (needsValidation || (opts.CodeGenHighLevel && !opts.DisableValidation)) {
-        UINT32 majorVer, minorVer;
-        dxcutil::GetValidatorVersion(&majorVer, &minorVer);
-        compiler.getCodeGenOpts().HLSLValidatorMajorVer = majorVer;
-        compiler.getCodeGenOpts().HLSLValidatorMinorVer = minorVer;
+      if (compiler.getCodeGenOpts().HLSLProfile == "lib_6_x") {
+        // Currently do not support stripping reflection from offline linking target.
+        opts.KeepReflectionInDxil = true;
+      }
+
+      if (opts.ValVerMajor != UINT_MAX) {
+        // user-specified validator version override
+        compiler.getCodeGenOpts().HLSLValidatorMajorVer = opts.ValVerMajor;
+        compiler.getCodeGenOpts().HLSLValidatorMinorVer = opts.ValVerMinor;
+      } else {
+        // Version from dxil.dll, or internal validator if unavailable
+        dxcutil::GetValidatorVersion(&compiler.getCodeGenOpts().HLSLValidatorMajorVer,
+                                     &compiler.getCodeGenOpts().HLSLValidatorMinorVer);
       }
 
       if (opts.AstDump) {
@@ -732,9 +740,12 @@ public:
           // Implies name part
           SerializeFlags |= SerializeDxilFlags::IncludeDebugNamePart;
         }
-        if (opts.StripReflection) {
+        if (!opts.KeepReflectionInDxil) {
           SerializeFlags |= SerializeDxilFlags::StripReflectionFromDxilPart;
         }
+        if (!opts.StripReflection) {
+          SerializeFlags |= SerializeDxilFlags::IncludeReflectionPart;
+        }
 
         // Don't do work to put in a container if an error has occurred
         // Do not create a container when there is only a a high-level representation in the module.
@@ -886,8 +897,6 @@ public:
 
       StringRef Data((LPSTR)utf8Source->GetBufferPointer(),
         utf8Source->GetBufferSize());
-      std::unique_ptr<llvm::MemoryBuffer> pBuffer(
-        llvm::MemoryBuffer::getMemBufferCopy(Data, pUtf8SourceName));
 
       // Not very efficient but also not very important.
       std::vector<std::string> defines;

+ 2 - 1
tools/clang/tools/dxcompiler/dxcontainerbuilder.cpp

@@ -123,7 +123,8 @@ HRESULT STDMETHODCALLTYPE DxcContainerBuilder::RemovePart(_In_ UINT32 fourCC) {
     IFTBOOL(fourCC == DxilFourCC::DFCC_ShaderDebugInfoDXIL ||
                 fourCC == DxilFourCC::DFCC_ShaderDebugName ||
                 fourCC == DxilFourCC::DFCC_RootSignature ||
-                fourCC == DxilFourCC::DFCC_PrivateData,
+                fourCC == DxilFourCC::DFCC_PrivateData ||
+                fourCC == DxilFourCC::DFCC_ShaderStatistics,
             E_INVALIDARG); // You can only remove debug info, debug info name, rootsignature, or private data blob
     PartList::iterator it =
       std::find_if(m_parts.begin(), m_parts.end(),

+ 19 - 0
tools/clang/tools/dxcompiler/dxcutil.cpp

@@ -27,6 +27,7 @@
 #include "llvm/Transforms/Utils/Cloning.h"
 #include "dxc/Support/dxcapi.impl.h"
 #include "dxc/Support/HLSLOptions.h"
+#include "dxc/DXIL/DxilModule.h"
 
 #include "llvm/Support/Path.h"
 
@@ -190,6 +191,24 @@ HRESULT ValidateAndAssembleToContainer(
     llvmModule.SetDebugName(DebugName);
   }
 
+  // Verify validator version can validate this module
+  CComPtr<IDxcVersionInfo> pValidatorVersion;
+  IFT(pValidator->QueryInterface(&pValidatorVersion));
+  UINT32 ValMajor, ValMinor;
+  IFT(pValidatorVersion->GetVersion(&ValMajor, &ValMinor));
+  DxilModule &DM = llvmModule.get()->GetDxilModule();
+  unsigned ReqValMajor, ReqValMinor;
+  DM.GetValidatorVersion(ReqValMajor, ReqValMinor);
+  if (DXIL::CompareVersions(ValMajor, ValMinor, ReqValMajor, ReqValMinor) < 0) {
+    // Module is expecting to be validated by a newer validator.
+    unsigned diagID =
+      Diag.getCustomDiagID(clang::DiagnosticsEngine::Level::Error,
+        "The module cannot be validated by the version of the validator "
+        "currently attached.");
+    Diag.Report(diagID);
+    return E_FAIL;
+  }
+
   llvmModule.WrapModuleInDxilContainer(pMalloc, pOutputStream, pOutputBlob,
                                        SerializeFlags, pShaderHashOut);
 

+ 1 - 0
tools/clang/unittests/HLSL/CMakeLists.txt

@@ -20,6 +20,7 @@ set( LLVM_LINK_COMPONENTS
   analysis
   ipa
   irreader
+  transformutils  # for CloneModule
   )
 
 if(WIN32)

+ 9 - 1
tools/clang/unittests/HLSL/CompilerTest.cpp

@@ -234,7 +234,13 @@ public:
 
 #if _ITERATOR_DEBUG_LEVEL==0 
   // CompileWhenNoMemThenOOM can properly detect leaks only when debug iterators are disabled
-  TEST_METHOD(CompileWhenNoMemThenOOM)
+  BEGIN_TEST_METHOD(CompileWhenNoMemThenOOM)
+    // Disabled because there are problems where we try to allocate memory in destructors,
+    // which causes more bad_alloc() throws while unwinding bad_alloc(), which asserts
+    // If only failing one allocation, there are allocations where failing them is lost,
+    // such as in ~raw_string_ostream(), where it flushes, then eats bad_alloc(), if thrown.
+    TEST_METHOD_PROPERTY(L"Ignore", L"true")
+  END_TEST_METHOD()
 #endif
   TEST_METHOD(CompileWhenShaderModelMismatchAttributeThenFail)
   TEST_METHOD(CompileBadHlslThenFail)
@@ -2871,5 +2877,7 @@ TEST_F(CompilerTest, CodeGenBatch) {
 }
 
 TEST_F(CompilerTest, Mesh) {
+  if (m_ver.SkipDxilVersion(1, 5))
+    return;
   CodeGenTestCheckBatchDir(L"mesh");
 }

+ 30 - 0
tools/clang/unittests/HLSL/DxcTestUtils.cpp

@@ -15,6 +15,7 @@
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/Support/Global.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/APInt.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/FileSystem.h"
@@ -318,6 +319,35 @@ void VerifyCompileOK(dxc::DxcDllSupport &dllSupport, LPCSTR pText,
   VERIFY_SUCCEEDED(pResult->GetResult(ppResult));
 }
 
+HRESULT GetVersion(dxc::DxcDllSupport& DllSupport, REFCLSID clsid, unsigned &Major, unsigned &Minor) {
+  CComPtr<IUnknown> pUnk;
+  if (SUCCEEDED(DllSupport.CreateInstance(clsid, &pUnk))) {
+    CComPtr<IDxcVersionInfo> pVersionInfo;
+    IFR(pUnk.QueryInterface(&pVersionInfo));
+    IFR(pVersionInfo->GetVersion(&Major, &Minor));
+  }
+  return S_OK;
+}
+
+bool ParseTargetProfile(llvm::StringRef targetProfile, llvm::StringRef &outStage, unsigned &outMajor, unsigned &outMinor) {
+  auto stage_model = targetProfile.split("_");
+  auto major_minor = stage_model.second.split("_");
+  llvm::APInt major;
+  if (major_minor.first.getAsInteger(16, major))
+    return false;
+  if (major_minor.second.compare("x") == 0) {
+    outMinor = 0xF;   // indicates offline target
+  } else {
+    llvm::APInt minor;
+    if (major_minor.second.getAsInteger(16, minor))
+      return false;
+    outMinor = (unsigned)minor.getLimitedValue();
+  }
+  outStage = stage_model.first;
+  outMajor = (unsigned)major.getLimitedValue();
+  return true;
+}
+
 // VersionSupportInfo Implementation
 VersionSupportInfo::VersionSupportInfo()
     : m_CompilerIsDebugBuild(false), m_InternalValidator(false), m_DxilMajor(0),

+ 4 - 0
tools/clang/unittests/HLSL/DxcTestUtils.h

@@ -16,6 +16,7 @@
 #include "dxc/dxcapi.h"
 #include "dxc/Support/dxcapi.use.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
 
 namespace hlsl {
 namespace options {
@@ -162,6 +163,9 @@ void VerifyCompileOK(dxc::DxcDllSupport &dllSupport, LPCSTR pText,
                      LPWSTR pTargetProfile, std::vector<LPCWSTR> &args,
                      _Outptr_ IDxcBlob **ppResult);
 
+HRESULT GetVersion(dxc::DxcDllSupport& DllSupport, REFCLSID clsid, unsigned &Major, unsigned &Minor);
+bool ParseTargetProfile(llvm::StringRef targetProfile, llvm::StringRef &outStage, unsigned &outMajor, unsigned &outMinor);
+
 class VersionSupportInfo {
 private:
   bool m_CompilerIsDebugBuild;

+ 73 - 12
tools/clang/unittests/HLSL/DxilContainerTest.cpp

@@ -160,8 +160,12 @@ public:
     VERIFY_ARE_EQUAL(pTestDesc->ComponentType, pBaseDesc->ComponentType);
     VERIFY_ARE_EQUAL(MaskCount(pTestDesc->Mask), MaskCount(pBaseDesc->Mask));
     VERIFY_ARE_EQUAL(pTestDesc->MinPrecision, pBaseDesc->MinPrecision);
-    if (!isInput)
-      VERIFY_ARE_EQUAL(pTestDesc->ReadWriteMask != 0, pBaseDesc->ReadWriteMask != 0); // VERIFY_ARE_EQUAL(pTestDesc->ReadWriteMask, pBaseDesc->ReadWriteMask);
+    if (!isInput) {
+      if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0)
+        VERIFY_ARE_EQUAL(pTestDesc->ReadWriteMask != 0, pBaseDesc->ReadWriteMask != 0);
+      else
+        VERIFY_ARE_EQUAL(MaskCount(pTestDesc->ReadWriteMask), MaskCount(pBaseDesc->ReadWriteMask));
+    }
     // VERIFY_ARE_EQUAL(pTestDesc->Register, pBaseDesc->Register);
     //VERIFY_ARE_EQUAL(pTestDesc->SemanticIndex, pBaseDesc->SemanticIndex);
     VERIFY_ARE_EQUAL(pTestDesc->Stream, pBaseDesc->Stream);
@@ -332,8 +336,12 @@ public:
     std::vector<FileRunCommandPart> parts;
     ParseCommandPartsFromFile(path, parts);
     VERIFY_IS_TRUE(parts.size() > 0);
-    VERIFY_ARE_EQUAL_STR(parts[0].Command.c_str(), "%dxc");
-    FileRunCommandPart &dxc = parts[0];
+    unsigned partIdx = 0;
+    if (parts[0].Command.compare("%dxilver") == 0) {
+      partIdx = 1;
+    }
+    FileRunCommandPart &dxc = parts[partIdx];
+    VERIFY_ARE_EQUAL_STR(dxc.Command.c_str(), "%dxc");
     m_dllSupport.Initialize();
 
     hlsl::options::MainArgs args;
@@ -500,6 +508,18 @@ public:
 
   void ReflectionTest(LPCWSTR name, bool ignoreIfDXBCFails) {
     WEX::Logging::Log::Comment(WEX::Common::String().Format(L"Reflection comparison for %s", name));
+
+    // Skip if unsupported.
+    std::vector<FileRunCommandPart> parts;
+    ParseCommandPartsFromFile(name, parts);
+    VERIFY_IS_TRUE(parts.size() > 0);
+    if (parts[0].Command.compare("%dxilver") == 0) {
+      VERIFY_IS_TRUE(parts.size() > 1);
+      auto result = parts[0].Run(m_dllSupport, nullptr);
+      if (result.ExitCode != 0)
+        return;
+    }
+
     CComPtr<IDxcBlob> pProgram;
     CComPtr<IDxcBlob> pProgramDXBC;
     HRESULT hrDXBC = CompileFromFile(name, true, &pProgramDXBC);
@@ -608,8 +628,8 @@ TEST_F(DxilContainerTest, CompileWhenOKThenIncludesSignatures) {
 
   {
     std::string s = DisassembleProgram(program, L"VSMain", L"vs_6_0");
-    // NOTE: this will change when proper packing is done, and when 'always-writes' is accurately implemented.
-    const char expected[] =
+    // NOTE: this will change when proper packing is done, and when 'always-reads' is accurately implemented.
+    const char expected_1_4[] =
       ";\n"
       "; Input signature:\n"
       ";\n"
@@ -625,14 +645,35 @@ TEST_F(DxilContainerTest, CompileWhenOKThenIncludesSignatures) {
       "; -------------------- ----- ------ -------- -------- ------- ------\n"
       "; SV_Position              0   xyzw        0      POS   float   xyzw\n"  // could read SV_POSITION
       "; COLOR                    0   xyzw        1     NONE   float   xyzw\n"; // should read '1' in register
-    std::string start(s.c_str(), strlen(expected));
-    VERIFY_ARE_EQUAL_STR(expected, start.c_str());
+    const char expected[] =
+      ";\n"
+      "; Input signature:\n"
+      ";\n"
+      "; Name                 Index   Mask Register SysValue  Format   Used\n"
+      "; -------------------- ----- ------ -------- -------- ------- ------\n"
+      "; POSITION                 0   xyzw        0     NONE   float   xyzw\n" // should read 'xyzw' in Used
+      "; COLOR                    0   xyzw        1     NONE   float   xyzw\n" // should read '1' in register
+      ";\n"
+      ";\n"
+      "; Output signature:\n"
+      ";\n"
+      "; Name                 Index   Mask Register SysValue  Format   Used\n"
+      "; -------------------- ----- ------ -------- -------- ------- ------\n"
+      "; SV_Position              0   xyzw        0      POS   float   xyzw\n"  // could read SV_POSITION
+      "; COLOR                    0   xyzw        1     NONE   float   xyzw\n"; // should read '1' in register
+    if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0) {
+      std::string start(s.c_str(), strlen(expected_1_4));
+      VERIFY_ARE_EQUAL_STR(expected_1_4, start.c_str());
+    } else {
+      std::string start(s.c_str(), strlen(expected));
+      VERIFY_ARE_EQUAL_STR(expected, start.c_str());
+    }
   }
 
   {
     std::string s = DisassembleProgram(program, L"PSMain", L"ps_6_0");
-    // NOTE: this will change when proper packing is done, and when 'always-writes' is accurately implemented.
-    const char expected[] =
+    // NOTE: this will change when proper packing is done, and when 'always-reads' is accurately implemented.
+    const char expected_1_4[] =
       ";\n"
       "; Input signature:\n"
       ";\n"
@@ -647,8 +688,28 @@ TEST_F(DxilContainerTest, CompileWhenOKThenIncludesSignatures) {
       "; Name                 Index   Mask Register SysValue  Format   Used\n"
       "; -------------------- ----- ------ -------- -------- ------- ------\n"
       "; SV_Target                0   xyzw        0   TARGET   float   xyzw\n";// could read SV_TARGET
-    std::string start(s.c_str(), strlen(expected));
-    VERIFY_ARE_EQUAL_STR(expected, start.c_str());
+    const char expected[] =
+      ";\n"
+      "; Input signature:\n"
+      ";\n"
+      "; Name                 Index   Mask Register SysValue  Format   Used\n"
+      "; -------------------- ----- ------ -------- -------- ------- ------\n"
+      "; SV_Position              0   xyzw        0      POS   float       \n" // could read SV_POSITION
+      "; COLOR                    0   xyzw        1     NONE   float   xyzw\n" // should read '1' in register, xyzw in Used
+      ";\n"
+      ";\n"
+      "; Output signature:\n"
+      ";\n"
+      "; Name                 Index   Mask Register SysValue  Format   Used\n"
+      "; -------------------- ----- ------ -------- -------- ------- ------\n"
+      "; SV_Target                0   xyzw        0   TARGET   float   xyzw\n";// could read SV_TARGET
+    if (hlsl::DXIL::CompareVersions(m_ver.m_ValMajor, m_ver.m_ValMinor, 1, 5) < 0) {
+      std::string start(s.c_str(), strlen(expected_1_4));
+      VERIFY_ARE_EQUAL_STR(expected_1_4, start.c_str());
+    } else {
+      std::string start(s.c_str(), strlen(expected));
+      VERIFY_ARE_EQUAL_STR(expected, start.c_str());
+    }
   }
 }
 

+ 92 - 1
tools/clang/unittests/HLSL/DxilModuleTest.cpp

@@ -65,6 +65,15 @@ public:
   TEST_METHOD(CSGetNumThreads)
   TEST_METHOD(MSGetNumThreads)
   TEST_METHOD(ASGetNumThreads)
+
+  TEST_METHOD(SetValidatorVersion)
+
+  void VerifyValidatorVersionFails(
+    LPCWSTR shaderModel, const std::vector<LPCWSTR> &arguments,
+    const std::vector<LPCSTR> &expectedErrors);
+  void VerifyValidatorVersionMatches(
+    LPCWSTR shaderModel, const std::vector<LPCWSTR> &arguments,
+    unsigned expectedMajor = UINT_MAX, unsigned expectedMinor = UINT_MAX);
 };
 
 bool DxilModuleTest::InitSupport() {
@@ -154,7 +163,7 @@ public:
     return *DM;
   }
 
-private:
+public:
   static ::llvm::sys::fs::MSFileSystem *CreateMSFileSystem() {
     ::llvm::sys::fs::MSFileSystem *msfPtr;
     VERIFY_SUCCEEDED(CreateMSFileSystemForDisk(&msfPtr));
@@ -487,3 +496,85 @@ TEST_F(DxilModuleTest, ASGetNumThreads) {
   VERIFY_ARE_EQUAL(4, DM.GetNumThreads(1));
   VERIFY_ARE_EQUAL(2, DM.GetNumThreads(2));
 }
+
+void DxilModuleTest::VerifyValidatorVersionFails(
+    LPCWSTR shaderModel, const std::vector<LPCWSTR> &arguments,
+    const std::vector<LPCSTR> &expectedErrors) {
+
+  LPCSTR shader =
+    "[shader(\"pixel\")]"
+    "float4 main() : SV_Target {\n"
+    "  return 0;\n"
+    "}\n";
+
+  Compiler c(m_dllSupport);
+  c.Compile(shader, shaderModel, arguments, {});
+  CheckOperationResultMsgs(c.pCompileResult, expectedErrors, false, false);
+}
+
+void DxilModuleTest::VerifyValidatorVersionMatches(
+    LPCWSTR shaderModel, const std::vector<LPCWSTR> &arguments,
+    unsigned expectedMajor, unsigned expectedMinor) {
+
+  LPCSTR shader =
+    "[shader(\"pixel\")]"
+    "float4 main() : SV_Target {\n"
+    "  return 0;\n"
+    "}\n";
+
+  Compiler c(m_dllSupport);
+  c.Compile(shader, shaderModel, arguments, {});
+  DxilModule &DM = c.GetDxilModule();
+  unsigned vMajor, vMinor;
+  DM.GetValidatorVersion(vMajor, vMinor);
+
+  if (expectedMajor == UINT_MAX) {
+    // Expect current version
+    VERIFY_ARE_EQUAL(vMajor, c.m_ver.m_ValMajor);
+    VERIFY_ARE_EQUAL(vMinor, c.m_ver.m_ValMinor);
+  } else {
+    VERIFY_ARE_EQUAL(vMajor, expectedMajor);
+    VERIFY_ARE_EQUAL(vMinor, expectedMinor);
+  }
+}
+
+TEST_F(DxilModuleTest, SetValidatorVersion) {
+  Compiler c(m_dllSupport);
+  if (c.SkipDxil_Test(1, 4)) return;
+
+  // Current version
+  VerifyValidatorVersionMatches(L"ps_6_2", {});
+  VerifyValidatorVersionMatches(L"lib_6_3", {});
+
+  // Current version, with validation disabled
+  VerifyValidatorVersionMatches(L"ps_6_2", {L"-Vd"});
+  VerifyValidatorVersionMatches(L"lib_6_3", {L"-Vd"});
+
+  // Override validator version
+  VerifyValidatorVersionMatches(L"ps_6_2", {L"-validator-version", L"1.2"}, 1,2);
+  VerifyValidatorVersionMatches(L"lib_6_3", {L"-validator-version", L"1.3"}, 1,3);
+
+  // Override validator version, with validation disabled
+  VerifyValidatorVersionMatches(L"ps_6_2", {L"-Vd", L"-validator-version", L"1.2"}, 1,2);
+  VerifyValidatorVersionMatches(L"lib_6_3", {L"-Vd", L"-validator-version", L"1.3"}, 1,3);
+
+  // Never can validate (version 0,0):
+  VerifyValidatorVersionMatches(L"lib_6_1", {L"-Vd"}, 0, 0);
+  VerifyValidatorVersionMatches(L"lib_6_2", {L"-Vd"}, 0, 0);
+  VerifyValidatorVersionMatches(L"lib_6_2", {L"-Vd", L"-validator-version", L"0.0"}, 0, 0);
+  VerifyValidatorVersionMatches(L"lib_6_x", {}, 0, 0);
+  VerifyValidatorVersionMatches(L"lib_6_x", {L"-validator-version", L"0.0"}, 0, 0);
+
+  // Failure cases:
+  VerifyValidatorVersionFails(L"ps_6_2", {L"-validator-version", L"1.1"}, {
+    "validator version 1,1 does not support target profile."});
+
+  VerifyValidatorVersionFails(L"lib_6_2", {L"-Tlib_6_2"}, {
+    "Must disable validation for unsupported lib_6_1 or lib_6_2 targets"});
+
+  VerifyValidatorVersionFails(L"lib_6_2", {L"-Vd", L"-validator-version", L"1.2"}, {
+    "-validator-version cannot be used with library profiles lib_6_1 or lib_6_2."});
+
+  VerifyValidatorVersionFails(L"lib_6_x", {L"-validator-version", L"1.3"}, {
+    "Offline library profile cannot be used with non-zero -validator-version."});
+}

+ 55 - 31
tools/clang/unittests/HLSL/FileCheckerTest.cpp

@@ -368,6 +368,35 @@ FileRunCommandResult FileRunCommandPart::RunDxcHashTest(dxc::DxcDllSupport &DllS
   return FileRunCommandResult::Success();
 }
 
+static FileRunCommandResult CheckDxilVer(dxc::DxcDllSupport& DllSupport,
+                                         unsigned RequiredDxilMajor,
+                                         unsigned RequiredDxilMinor,
+                                         bool bCheckValidator = true) {
+  bool Supported = true;
+
+  // If the following fails, we have Dxil 1.0 compiler
+  unsigned DxilMajor = 1, DxilMinor = 0;
+  GetVersion(DllSupport, CLSID_DxcCompiler, DxilMajor, DxilMinor);
+  Supported &= hlsl::DXIL::CompareVersions(DxilMajor, DxilMinor, RequiredDxilMajor, RequiredDxilMinor) >= 0;
+
+  if (bCheckValidator) {
+    // If the following fails, we have validator 1.0
+    unsigned ValMajor = 1, ValMinor = 0;
+    GetVersion(DllSupport, CLSID_DxcValidator, ValMajor, ValMinor);
+    Supported &= hlsl::DXIL::CompareVersions(ValMajor, ValMinor, RequiredDxilMajor, RequiredDxilMinor) >= 0;
+  }
+
+  if (!Supported) {
+    FileRunCommandResult result {};
+    result.StdErr = "Skipping test due to unsupported dxil version";
+    result.ExitCode = 0; // Succeed the test
+    result.AbortPipeline = true;
+    return result;
+  }
+
+  return FileRunCommandResult::Success();
+}
+
 FileRunCommandResult FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport, const FileRunCommandResult *Prior) {
   // Support piping stdin from prior if needed.
   UNREFERENCED_PARAMETER(Prior);
@@ -385,6 +414,31 @@ FileRunCommandResult FileRunCommandPart::RunDxc(dxc::DxcDllSupport &DllSupport,
     flags.push_back(L"-fcgl");
   }
 
+  // Skip targets that require a newer compiler or validator.
+  // Some features may require newer compiler/validator than indicated by the
+  // shader model, but these should use %dxilver explicitly.
+  {
+    unsigned RequiredDxilMajor = 1, RequiredDxilMinor = 0;
+    llvm::StringRef stage;
+    IFTBOOL(ParseTargetProfile(opts.TargetProfile, stage, RequiredDxilMajor, RequiredDxilMinor), E_INVALIDARG);
+    if (RequiredDxilMinor != 0xF && stage.compare("rootsig") != 0) {
+      // Convert stage to minimum dxil/validator version:
+      RequiredDxilMajor = std::max(RequiredDxilMajor, (unsigned)6) - 5;
+      FileRunCommandResult result = CheckDxilVer(DllSupport, RequiredDxilMajor, RequiredDxilMinor, !opts.DisableValidation);
+      if (result.AbortPipeline) {
+        return result;
+      }
+    }
+  }
+
+  // For now, too many tests are sensitive to stripping the refleciton info
+  // from the main module, so use this flag to prevent this until tests
+  // can be updated.
+  // That is, unless the test explicitly requests -Qstrip_reflect_from_dxil or -Qstrip_reflect
+  if (!opts.StripReflectionFromDxil && !opts.StripReflection) {
+    flags.push_back(L"-Qkeep_reflect_in_dxil");
+  }
+
   std::vector<std::wstring> argWStrings;
   CopyArgsToWStrings(opts.Args, hlsl::options::CoreOption, argWStrings);
   for (const std::wstring &a : argWStrings)
@@ -643,38 +697,8 @@ FileRunCommandResult FileRunCommandPart::RunDxilVer(dxc::DxcDllSupport& DllSuppo
 
   unsigned RequiredDxilMajor = Arguments[0] - '0';
   unsigned RequiredDxilMinor = Arguments[2] - '0';
-  bool Supported = RequiredDxilMajor >= 1;
-  CComPtr<IDxcCompiler> pCompiler;
-
-  // If the following fails, we have Dxil 1.0 compiler
-  if (SUCCEEDED(DllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler))) {
-    CComPtr<IDxcVersionInfo> pVersionInfo;
-    IFT(pCompiler.QueryInterface(&pVersionInfo));
-    unsigned DxilMajor, DxilMinor;
-    IFT(pVersionInfo->GetVersion(&DxilMajor, &DxilMinor));
-    if (DxilMajor < RequiredDxilMajor || (DxilMajor == RequiredDxilMajor && DxilMinor < RequiredDxilMinor))
-      Supported = false;
-  }
-
-  CComPtr<IDxcValidator> pValidator;
-  if (SUCCEEDED(DllSupport.CreateInstance(CLSID_DxcValidator, &pValidator))) {
-    CComPtr<IDxcVersionInfo> pVersionInfo;
-    IFT(pValidator.QueryInterface(&pVersionInfo));
-    unsigned DxilMajor, DxilMinor;
-    VERIFY_SUCCEEDED(pVersionInfo->GetVersion(&DxilMajor, &DxilMinor));
-    if (DxilMajor < RequiredDxilMajor || (DxilMajor == RequiredDxilMajor && DxilMinor < RequiredDxilMinor))
-      Supported = false;
-  }
 
-  if (!Supported) {
-    FileRunCommandResult result {};
-    result.StdErr = "Skipping test due to unsupported dxil version";
-    result.ExitCode = 0; // Succeed the test
-    result.AbortPipeline = true;
-    return result;
-  }
-
-  return FileRunCommandResult::Success();
+  return CheckDxilVer(DllSupport, RequiredDxilMajor, RequiredDxilMinor);
 }
 
 class FileRunTestResultImpl : public FileRunTestResult {

+ 30 - 4
tools/clang/unittests/HLSL/LinkerTest.cpp

@@ -61,6 +61,7 @@ public:
   TEST_METHOD(RunLinkToLibWithUnusedExport);
   TEST_METHOD(RunLinkToLibWithNoExports);
   TEST_METHOD(RunLinkWithPotentialIntrinsicNameCollisions);
+  TEST_METHOD(RunLinkWithValidatorVersion);
 
 
   dxc::DxcDllSupport m_dllSupport;
@@ -72,7 +73,8 @@ public:
   }
 
   void CompileLib(LPCWSTR filename, IDxcBlob **pResultBlob,
-                  llvm::ArrayRef<LPCWSTR> pArguments = {}) {
+                  llvm::ArrayRef<LPCWSTR> pArguments = {},
+                  LPCWSTR pShaderTarget = L"lib_6_x") {
     std::wstring fullPath = hlsl_test::GetPathToHlslDataFile(filename);
     CComPtr<IDxcBlobEncoding> pSource;
     CComPtr<IDxcLibrary> pLibrary;
@@ -85,10 +87,9 @@ public:
     CComPtr<IDxcOperationResult> pResult;
     CComPtr<IDxcBlob> pProgram;
 
-    CA2W shWide("lib_6_x", CP_UTF8);
     VERIFY_SUCCEEDED(
         m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
-    VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"", shWide,
+    VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"", pShaderTarget,
                                         const_cast<LPCWSTR*>(pArguments.data()), pArguments.size(),
                                         nullptr, 0,
                                         nullptr, &pResult));
@@ -218,7 +219,7 @@ TEST_F(LinkerTest, RunLinkFailReDefine) {
 
 TEST_F(LinkerTest, RunLinkGlobalInit) {
   CComPtr<IDxcBlob> pEntryLib;
-  CompileLib(L"..\\CodeGenHLSL\\lib_global.hlsl", &pEntryLib);
+  CompileLib(L"..\\CodeGenHLSL\\lib_global.hlsl", &pEntryLib, {}, L"lib_6_3");
   CComPtr<IDxcLinker> pLinker;
   CreateLinker(&pLinker);
 
@@ -636,3 +637,28 @@ TEST_F(LinkerTest, RunLinkWithPotentialIntrinsicNameCollisions) {
     "declare %dx.types.Handle @\"dx.op.createHandleForLib.class.Texture2D<float>\"(i32, %\"class.Texture2D<float>\")"
   }, { });
 }
+
+TEST_F(LinkerTest, RunLinkWithValidatorVersion) {
+  if (m_ver.SkipDxilVersion(1, 4)) return;
+
+  CComPtr<IDxcBlob> pEntryLib;
+  CompileLib(L"..\\CodeGenHLSL\\linker\\lib_mat_entry2.hlsl",
+             &pEntryLib, {});
+  CComPtr<IDxcBlob> pLib;
+  CompileLib(
+      L"..\\CodeGenHLSL\\linker\\lib_mat_cast2.hlsl",
+      &pLib, {});
+
+  CComPtr<IDxcLinker> pLinker;
+  CreateLinker(&pLinker);
+
+  LPCWSTR libName = L"ps_main";
+  RegisterDxcModule(libName, pEntryLib, pLinker);
+
+  LPCWSTR libName2 = L"test";
+  RegisterDxcModule(libName2, pLib, pLinker);
+
+  Link(L"", L"lib_6_3", pLinker, {libName, libName2},
+       {"!dx.valver = !{(![0-9]+)}.*\n\\1 = !{i32 1, i32 3}"},
+       {}, {L"-validator-version", L"1.3"}, /*regex*/ true);
+}

+ 2 - 0
tools/clang/unittests/HLSL/OptimizerTest.cpp

@@ -179,12 +179,14 @@ void OptimizerTest::OptimizerWhenSliceNThenOK(int optLevel, LPCWSTR pText, LPCWS
   highLevelArgs.insert(highLevelArgs.end(), args.begin(), args.end());
 
   // Create the target program with a single invocation.
+  highLevelArgs.emplace_back(L"/Qkeep_reflect_in_dxil");
   VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"source.hlsl", L"main", pTarget,
     highLevelArgs.data(), static_cast<UINT32>(highLevelArgs.size()), nullptr, 0, nullptr, &pResult));
   VerifyOperationSucceeded(pResult);
   VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
   pResult.Release();
   std::string originalAssembly = DisassembleProgram(m_dllSupport, pProgram);
+  highLevelArgs.pop_back(); // Remove /keep_reflect_in_dxil
 
   // Get a list of passes for this configuration.
   highLevelArgs.emplace_back(L"/Odump");

+ 116 - 90
tools/clang/unittests/HLSL/ValidationTest.cpp

@@ -8,6 +8,8 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#define NOMINMAX
+
 #include <memory>
 #include <vector>
 #include <string>
@@ -331,7 +333,7 @@ public:
     CheckValidationMsgs(pBlobEncoding, pErrorMsgs, bRegex);
   }
 
-  void CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
+  bool CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
                      LPCWSTR *pArguments, UINT32 argCount, const DxcDefine *pDefines,
                      UINT32 defineCount, IDxcBlob **pResultBlob) {
     CComPtr<IDxcCompiler> pCompiler;
@@ -341,35 +343,51 @@ public:
     CA2W shWide(pShaderModel, CP_UTF8);
 
     wchar_t *pEntryName = L"main";
-    if (llvm::StringRef(pShaderModel).startswith("lib_"))
-      pEntryName = L"";
+
+    llvm::StringRef stage;
+    unsigned RequiredDxilMajor = 1, RequiredDxilMinor = 0;
+    if (ParseTargetProfile(pShaderModel, stage, RequiredDxilMajor, RequiredDxilMinor)) {
+      if (stage.compare("lib") == 0)
+        pEntryName = L"";
+      if (stage.compare("rootsig") != 0) {
+        RequiredDxilMajor = std::max(RequiredDxilMajor, (unsigned)6) - 5;
+        if (m_ver.SkipDxilVersion(RequiredDxilMajor, RequiredDxilMinor))
+          return false;
+      }
+    }
+
+    std::vector<LPCWSTR> args;
+    args.reserve(argCount + 1);
+    args.insert(args.begin(), pArguments, pArguments + argCount);
+    args.emplace_back(L"-Qkeep_reflect_in_dxil");
 
     VERIFY_SUCCEEDED(
         m_dllSupport.CreateInstance(CLSID_DxcCompiler, &pCompiler));
     VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", pEntryName, shWide,
-                                        pArguments, argCount, pDefines,
+                                        args.data(), (UINT32)args.size(), pDefines,
                                         defineCount, nullptr, &pResult));
     CheckOperationResultMsgs(pResult, nullptr, false, false);
     VERIFY_SUCCEEDED(pResult->GetResult(pResultBlob));
+    return true;
   }
 
-  void CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
+  bool CompileSource(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
                      IDxcBlob **pResultBlob) {
-    CompileSource(pSource, pShaderModel, nullptr, 0, nullptr, 0, pResultBlob);
+    return CompileSource(pSource, pShaderModel, nullptr, 0, nullptr, 0, pResultBlob);
   }
 
-  void CompileSource(LPCSTR pSource, LPCSTR pShaderModel,
+  bool CompileSource(LPCSTR pSource, LPCSTR pShaderModel,
                      IDxcBlob **pResultBlob) {
     CComPtr<IDxcBlobEncoding> pSourceBlob;
     Utf8ToBlob(m_dllSupport, pSource, &pSourceBlob);
-    CompileSource(pSourceBlob, pShaderModel, nullptr, 0, nullptr, 0, pResultBlob);
+    return CompileSource(pSourceBlob, pShaderModel, nullptr, 0, nullptr, 0, pResultBlob);
   }
 
   void DisassembleProgram(IDxcBlob *pProgram, std::string *text) {
     *text = ::DisassembleProgram(m_dllSupport, pProgram);
   }
 
-  void RewriteAssemblyCheckMsg(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
+  bool RewriteAssemblyCheckMsg(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
     LPCWSTR *pArguments, UINT32 argCount,
     const DxcDefine *pDefines, UINT32 defineCount,
     llvm::ArrayRef<LPCSTR> pLookFors,
@@ -377,7 +395,8 @@ public:
     llvm::ArrayRef<LPCSTR> pErrorMsgs,
     bool bRegex = false) {
     CComPtr<IDxcBlob> pText;
-    RewriteAssemblyToText(pSource, pShaderModel, pArguments, argCount, pDefines, defineCount, pLookFors, pReplacements, &pText, bRegex);
+    if (!RewriteAssemblyToText(pSource, pShaderModel, pArguments, argCount, pDefines, defineCount, pLookFors, pReplacements, &pText, bRegex))
+      return false;
     CComPtr<IDxcAssembler> pAssembler;
     CComPtr<IDxcOperationResult> pAssembleResult;
     VERIFY_SUCCEEDED(
@@ -390,6 +409,7 @@ public:
       VERIFY_SUCCEEDED(pAssembleResult->GetResult(&pBlob));
       CheckValidationMsgs(pBlob, pErrorMsgs, bRegex);
     }
+    return true;
   }
 
   void RewriteAssemblyCheckMsg(LPCSTR pSource, LPCSTR pShaderModel,
@@ -439,7 +459,7 @@ public:
       pLookFors, pReplacements, pErrorMsgs, bRegex);
   }
 
-  void RewriteAssemblyToText(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
+  bool RewriteAssemblyToText(IDxcBlobEncoding *pSource, LPCSTR pShaderModel,
                              LPCWSTR *pArguments, UINT32 argCount,
                              const DxcDefine *pDefines, UINT32 defineCount,
                              llvm::ArrayRef<LPCSTR> pLookFors,
@@ -447,7 +467,8 @@ public:
                              IDxcBlob **pBlob, bool bRegex = false) {
     CComPtr<IDxcBlob> pProgram;
     std::string disassembly;
-    CompileSource(pSource, pShaderModel, pArguments, argCount, pDefines, defineCount, &pProgram);
+    if (!CompileSource(pSource, pShaderModel, pArguments, argCount, pDefines, defineCount, &pProgram))
+      return false;
     DisassembleProgram(pProgram, &disassembly);
     for (unsigned i = 0; i < pLookFors.size(); ++i) {
       LPCSTR pLookFor = pLookFors[i];
@@ -488,18 +509,21 @@ public:
       }
     }
     Utf8ToBlob(m_dllSupport, disassembly.c_str(), pBlob);
+    return true;
   }
 
 
   // compile one or two sources, validate module from 1 with container parts from 2, check messages
-  void ReplaceContainerPartsCheckMsgs(LPCSTR pSource1, LPCSTR pSource2, LPCSTR pShaderModel,
+  bool ReplaceContainerPartsCheckMsgs(LPCSTR pSource1, LPCSTR pSource2, LPCSTR pShaderModel,
                                      llvm::ArrayRef<DxilFourCC> PartsToReplace,
                                      llvm::ArrayRef<LPCSTR> pErrorMsgs) {
     CComPtr<IDxcBlob> pProgram1, pProgram2;
-    CompileSource(pSource1, pShaderModel, &pProgram1);
+    if (!CompileSource(pSource1, pShaderModel, &pProgram1))
+      return false;
     VERIFY_IS_NOT_NULL(pProgram1);
     if (pSource2) {
-      CompileSource(pSource2, pShaderModel, &pProgram2);
+      if (!CompileSource(pSource2, pShaderModel, &pProgram2))
+        return false;
       VERIFY_IS_NOT_NULL(pProgram2);
     } else {
       pProgram2 = pProgram1;
@@ -551,6 +575,7 @@ public:
     pContainerWriter->write(pOutputStream);
 
     CheckValidationMsgs((const char *)pOutputStream->GetPtr(), pOutputStream->GetPtrSize(), pErrorMsgs, /*bRegex*/false);
+    return true;
   }
 };
 
@@ -798,9 +823,9 @@ TEST_F(ValidationTest, InnerCoverageFail) {
 TEST_F(ValidationTest, InterpChangeFail) {
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\interpChange.hlsl", "ps_6_0",
-      { "i32 1, i8 0, null}",
+      { "i32 1, i8 0, (.*)}",
         "?!dx.viewIdState ="},
-      { "i32 0, i8 2, null}",
+      { "i32 0, i8 2, \\1}",
         "!1012 ="},
       "interpolation mode that differs from another element packed",
       /*bRegex*/true);
@@ -892,18 +917,17 @@ TEST_F(ValidationTest, SamplerKindFail) {
       {"Invalid sampler mode",
        "require sampler declared in comparison mode",
        "requires sampler declared in default mode",
-       "should be on srv resource"});
+       // 1.4: "should", 1.5: "should be "
+       "on srv resource"});
 }
 TEST_F(ValidationTest, SemaOverlapFail) {
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\semaOverlap1.hlsl", "ps_6_0",
-      {"!([0-9]+) = !\\{i32 0, !\"A\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 4, i32 0, i8 0, null\\}\n"
-      "!([0-9]+) = !\\{i32 0\\}\n"
-      "!([0-9]+) = !\\{i32 1, !\"A\", i8 9, i8 0, !([0-9]+)",
+      {"!\\{i32 0, !\"A\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 4, i32 0, i8 0, (.*)"
+      "!\\{i32 1, !\"A\", i8 9, i8 0, !([0-9]+)",
       },
-      {"!\\1 = !\\{i32 0, !\"A\", i8 9, i8 0, !\\2, i8 2, i32 1, i8 4, i32 0, i8 0, null\\}\n"
-      "!\\3 = !\\{i32 0\\}\n"
-      "!\\4 = !\\{i32 1, !\"A\", i8 9, i8 0, !\\2",
+      {"!\\{i32 0, !\"A\", i8 9, i8 0, !\\1, i8 2, i32 1, i8 4, i32 0, i8 0, \\2"
+      "!\\{i32 1, !\"A\", i8 9, i8 0, !\\1",
       },
       {"Semantic 'A' overlap at 0"},
       /*bRegex*/true);
@@ -921,9 +945,9 @@ TEST_F(ValidationTest, SigOutOfRangeFail) {
 TEST_F(ValidationTest, SigOverlapFail) {
   RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\semaOverlap1.hlsl", "ps_6_0",
-      { "i32 1, i8 0, null}",
+      { "i8 2, i32 1, i8 4, i32 1, i8 0,",
         "?!dx.viewIdState =" },
-      { "i32 0, i8 0, null}",
+      { "i8 2, i32 1, i8 4, i32 0, i8 0,",
         "!1012 =" },
       {"signature element A at location (0,0) size (1,4) overlaps another signature element"});
 }
@@ -1016,7 +1040,8 @@ TEST_F(ValidationTest, UavBarrierFail) {
       {"uav load don't support offset",
        "uav load don't support mipLevel/sampleIndex",
        "store on typed uav must write to all four components of the UAV",
-       "sync in a non-Compute/Amplification/Mesh Shader must only sync UAV (sync_uglobal)"});
+       "sync in a non-",    // 1.4: "Compute" 1.5: "Compute/Amplification/Mesh"
+       " Shader must only sync UAV (sync_uglobal)"});
 }
 TEST_F(ValidationTest, UndefValueFail) {
   TestCheck(L"..\\CodeGenHLSL\\UndefValue.hlsl");
@@ -1106,11 +1131,12 @@ TEST_F(ValidationTest, SignatureDataWidth) {
 TEST_F(ValidationTest, SignatureStreamIDForNonGS) {
   RewriteAssemblyCheckMsg(
     L"..\\CodeGenHLSL\\validation\\abs1.hlsl", "ps_6_0",
-    { ", i8 0, i32 1, i8 4, i32 0, i8 0, null}",
+    { ", i8 0, i32 1, i8 4, i32 0, i8 0, [^,]+}",
       "?!dx.viewIdState ="},
-    { ", i8 0, i32 1, i8 4, i32 0, i8 0, !19}\n!19 = !{i32 0, i32 1}",
+    { ", i8 0, i32 1, i8 4, i32 0, i8 0, !1019}\n!1019 = !{i32 0, i32 1}",
       "!1012 =" },
-    "Stream index (1) must between 0 and 0");
+    "Stream index \\(1\\) must between 0 and 0",
+    true);
 }
 
 TEST_F(ValidationTest, TypedUAVStoreFullMask0) {
@@ -1377,8 +1403,8 @@ TEST_F(ValidationTest, PsOutputSemantic) {
 TEST_F(ValidationTest, ArrayOfSVTarget) {
     RewriteAssemblyCheckMsg(
       L"..\\CodeGenHLSL\\targetArray.hlsl", "ps_6_0",
-      "i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 0, i8 0, null}",
-      "i32 2, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 2, i8 4, i32 0, i8 0, null}\n!101 = !{i32 5, i32 6}",
+      "i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 0, i8 0, (.*)}",
+      "i32 2, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 2, i8 4, i32 0, i8 0, \\2}\n!101 = !{i32 5, i32 6}",
       "Pixel shader output registers are not indexable.",
       /*bRegex*/true);
 }
@@ -1830,9 +1856,9 @@ TEST_F(ValidationTest, SemTargetMax) {
 float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
     ",
     "ps_6_0", 
-    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, ![0-9]+, i8 0, i32 1, i8 4, i32 7, i8 0, null}",
+    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, ![0-9]+, i8 0, i32 1, i8 4, i32 7, i8 0, (.*)}",
       "?!dx.viewIdState ="},
-    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 1, i8 4, i32 8, i8 0, null}\n!101 = !{i32 8}",
+    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !101, i8 0, i32 1, i8 4, i32 8, i8 0, \\1}\n!101 = !{i32 8}",
       "!1012 ="},
     "SV_Target semantic index exceeds maximum \\(7\\)",
     /*bRegex*/true);
@@ -1843,9 +1869,9 @@ TEST_F(ValidationTest, SemTargetIndexMatchesRow) {
 float4 main(float4 col : COLOR) : SV_Target7 { return col; } \
     ",
     "ps_6_0", 
-    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 7, i8 0, null}",
+    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 4, i32 7, i8 0, (.*)}",
       "?!dx.viewIdState ="},
-    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 4, i32 6, i8 0, null}",
+    { "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 4, i32 6, i8 0, \\2}",
       "!1012 ="},
     "SV_Target semantic index must match packed row location",
     /*bRegex*/true);
@@ -1856,8 +1882,8 @@ TEST_F(ValidationTest, SemTargetCol0) {
 float3 main(float4 col : COLOR) : SV_Target7 { return col.xyz; } \
     ",
     "ps_6_0", 
-    "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 3, i32 7, i8 0, null}",
-    "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 3, i32 7, i8 1, null}",
+    "!{i32 0, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 3, i32 7, i8 0, (.*)}",
+    "!{i32 0, !\"SV_Target\", i8 9, i8 16, !\\1, i8 0, i32 1, i8 3, i32 7, i8 1, \\2}",
     "SV_Target packed location must start at column 0",
     /*bRegex*/true);
 }
@@ -1869,8 +1895,8 @@ float4 main(uint vid : SV_VertexID, uint iid : SV_InstanceID) : SV_Position { \
 } \
     ",
     "vs_6_0", 
-    "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, ![0-9]+, i8 0, i32 1, i8 1, i32 0, i8 0, null}",
-    "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, !101, i8 0, i32 1, i8 1, i32 0, i8 0, null}\n!101 = !{i32 1}",
+    "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, ![0-9]+, i8 0, i32 1, i8 1, i32 0, i8 0, (.*)}",
+    "!{i32 0, !\"SV_VertexID\", i8 5, i8 1, !101, i8 0, i32 1, i8 1, i32 0, i8 0, \\1}\n!101 = !{i32 1}",
     "SV_VertexID semantic index exceeds maximum \\(0\\)",
     /*bRegex*/true);
 }
@@ -1902,8 +1928,8 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) {
 } \
     ",
     "hs_6_0",
-    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, ![0-9]+, i8 0, i32 3, i8 1, i32 0, i8 3, null}",
-    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !101, i8 0, i32 2, i8 1, i32 0, i8 3, null}\n!101 = !{i32 0, i32 1}",
+    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, ![0-9]+, i8 0, i32 3, i8 1, i32 0, i8 3, (.*)}",
+    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !101, i8 0, i32 2, i8 1, i32 0, i8 3, \\1}\n!101 = !{i32 0, i32 1}",
     "TessFactor rows, columns \\(2, 1\\) invalid for domain Tri.  Expected 3 rows and 1 column.",
     /*bRegex*/true);
 }
@@ -1935,9 +1961,9 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) {
 } \
     ",
     "hs_6_0",
-    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 1, i8 1, i32 3, i8 0, null}",
+    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 1, i8 1, i32 3, i8 0, (.*)}",
       "?!dx.viewIdState =" },
-    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !101, i8 0, i32 2, i8 1, i32 3, i8 0, null}\n!101 = !{i32 0, i32 1}",
+    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !101, i8 0, i32 2, i8 1, i32 3, i8 0, \\2}\n!101 = !{i32 0, i32 1}",
       "!1012 =" },
     "InsideTessFactor rows, columns \\(2, 1\\) invalid for domain Tri.  Expected 1 rows and 1 column.",
     /*bRegex*/true);
@@ -1970,8 +1996,8 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 3 > patch) {
 } \
     ",
     "hs_6_0",
-    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 3, null}",
-    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !\\1, i8 0, i32 3, i8 1, i32 -1, i8 -1, null}",
+    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 3, (.*)}",
+    "!{i32 0, !\"SV_TessFactor\", i8 9, i8 25, !\\1, i8 0, i32 3, i8 1, i32 -1, i8 -1, \\2}",
     "PatchConstant Semantic 'SV_TessFactor' should have a valid packing location",
     /*bRegex*/true);
 }
@@ -1981,8 +2007,8 @@ TEST_F(ValidationTest, SemShouldNotBeAllocated) {
 float4 main(float4 col : COLOR, out uint coverage : SV_Coverage) : SV_Target7 { coverage = 7; return col; } \
     ",
     "ps_6_0",
-    "!\"SV_Coverage\", i8 5, i8 14, !([0-9]+), i8 0, i32 1, i8 1, i32 -1, i8 -1, null}",
-    "!\"SV_Coverage\", i8 5, i8 14, !\\1, i8 0, i32 1, i8 1, i32 2, i8 0, null}",
+    "!\"SV_Coverage\", i8 5, i8 14, !([0-9]+), i8 0, i32 1, i8 1, i32 -1, i8 -1, (.*)}",
+    "!\"SV_Coverage\", i8 5, i8 14, !\\1, i8 0, i32 1, i8 1, i32 2, i8 0, \\2}",
     "Output Semantic 'SV_Coverage' should have a packing location of -1",
     /*bRegex*/true);
 }
@@ -2007,16 +2033,16 @@ void main( \
     ",
     "vs_6_0",
 
-    { "= !{i32 1, !\"f2out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 2, i32 1, i8 0, null}\n"
-      "!([0-9]+) = !{i32 2, !\"f3out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 3, i32 2, i8 0, null}\n"
-      "!([0-9]+) = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !([0-9]+), i8 2, i32 1, i8 2, i32 3, i8 0, null}\n"
-      "!([0-9]+) = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !([0-9]+), i8 2, i32 1, i8 1, i32 3, i8 2, null}\n",
+    { "= !{i32 1, !\"f2out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 2, i32 1, i8 0, (.*)}\n"
+      "!([0-9]+) = !{i32 2, !\"f3out\", i8 9, i8 0, !([0-9]+), i8 2, i32 1, i8 3, i32 2, i8 0, (.*)}\n"
+      "!([0-9]+) = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !([0-9]+), i8 2, i32 1, i8 2, i32 3, i8 0, (.*)}\n"
+      "!([0-9]+) = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !([0-9]+), i8 2, i32 1, i8 1, i32 3, i8 2, (.*)}\n",
       "?!dx.viewIdState =" },
 
-    { "= !{i32 1, !\"f2out\", i8 9, i8 0, !\\1, i8 2, i32 1, i8 2, i32 1, i8 2, null}\n"
-      "!\\2 = !{i32 2, !\"f3out\", i8 9, i8 0, !\\3, i8 2, i32 1, i8 3, i32 2, i8 1, null}\n"
-      "!\\4 = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !\\5, i8 2, i32 1, i8 2, i32 2, i8 0, null}\n"
-      "!\\6 = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !\\7, i8 2, i32 1, i8 1, i32 1, i8 0, null}\n",
+    { "= !{i32 1, !\"f2out\", i8 9, i8 0, !\\1, i8 2, i32 1, i8 2, i32 1, i8 2, \\2}\n"
+      "!\\3 = !{i32 2, !\"f3out\", i8 9, i8 0, !\\4, i8 2, i32 1, i8 3, i32 2, i8 1, \\5}\n"
+      "!\\6 = !{i32 3, !\"SV_ClipDistance\", i8 9, i8 6, !\\7, i8 2, i32 1, i8 2, i32 2, i8 0, \\8}\n"
+      "!\\9 = !{i32 4, !\"SV_CullDistance\", i8 9, i8 7, !\\10, i8 2, i32 1, i8 1, i32 1, i8 0, \\11}\n",
       "!1012 =" },
 
     "signature element SV_ClipDistance at location \\(2,0\\) size \\(1,2\\) violates component ordering rule \\(arb < sv < sgv\\).\n"
@@ -2102,8 +2128,8 @@ void main( \
     ",
     "vs_6_0",
 
-    "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !([0-9]+), i8 1, i32 1, i8 1, i32 3, i8 0, null}",
-    "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !\\1, i8 1, i32 1, i8 1, i32 1, i8 3, null}",
+    "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !([0-9]+), i8 1, i32 1, i8 1, i32 3, i8 0, (.*)}",
+    "!{i32 2, !\"SV_ViewportArrayIndex\", i8 5, i8 5, !\\1, i8 1, i32 1, i8 1, i32 1, i8 3, \\2}",
 
     "signature element SV_ViewportArrayIndex at location \\(1,3\\) size \\(1,1\\) has an indexing conflict with another signature element packed into the same row.",
     /*bRegex*/true);
@@ -2137,9 +2163,9 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) {
     ",
     "hs_6_0",
     //!{i32 0, !"SV_TessFactor", i8 9, i8 25, !23, i8 0, i32 4, i8 1, i32 0, i8 3, null}
-    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 2, i8 1, i32 4, i8 3, null}",
+    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !([0-9]+), i8 0, i32 2, i8 1, i32 4, i8 3, (.*)}",
       "?!dx.viewIdState =" },
-    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 0, i8 2, null}",
+    { "!{i32 1, !\"SV_InsideTessFactor\", i8 9, i8 26, !\\1, i8 0, i32 2, i8 1, i32 0, i8 2, \\2}",
       "!1012 =" },
     "signature element SV_InsideTessFactor at location \\(0,2\\) size \\(2,1\\) has an indexing conflict with another signature element packed into the same row.",
     /*bRegex*/true);
@@ -2174,8 +2200,8 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) {
 } \
     ",
     "hs_6_0",
-    "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
-    "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 2, i8 0, null}",
+    "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, (.*)}",
+    "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 2, i8 0, \\2}",
     "signature element Arb at location \\(2,0\\) size \\(3,1\\) has an indexing conflict with another signature element packed into the same row.",
     /*bRegex*/true);
 }
@@ -2209,9 +2235,9 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) {
 } \
     ",
     "hs_6_0",
-    { "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
+    { "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, (.*)}",
       "?!dx.viewIdState =" },
-    { "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 31, i8 0, null}",
+    { "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 31, i8 0, \\2}",
       "!1012 =" },
     "signature element Arb at location \\(31,0\\) size \\(3,1\\) is out of range.",
     /*bRegex*/true);
@@ -2246,8 +2272,8 @@ Vertex main(uint id : SV_OutputControlPointID, InputPatch< Vertex, 4 > patch) {
 } \
     ",
     "hs_6_0",
-    "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, null}",
-    "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 1, i8 3, null}",
+    "!{i32 2, !\"Arb\", i8 9, i8 0, !([0-9]+), i8 0, i32 3, i8 1, i32 0, i8 0, (.*)}",
+    "!{i32 2, !\"Arb\", i8 9, i8 0, !\\1, i8 0, i32 3, i8 1, i32 1, i8 3, \\2}",
     "signature element Arb at location \\(1,3\\) size \\(3,1\\) overlaps another signature element.",
     /*bRegex*/true);
 }
@@ -2273,13 +2299,13 @@ void main( \
     ",
     "vs_6_0",
 
-    {"!{i32 1, !\"Array\", i8 5, i8 0, !([0-9]+), i8 1, i32 2, i8 1, i32 1, i8 0, null}(.*)"
+    {"!{i32 1, !\"Array\", i8 5, i8 0, !([0-9]+), i8 1, i32 2, i8 1, i32 1, i8 0, (.*)}(.*)"
     "!\\1 = !{i32 0, i32 1}\n",
-    "= !{i32 2, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 3, i32 1, i8 1, null}"},
+    "= !{i32 2, !\"Value\", i8 5, i8 0, !([0-9]+), i8 1, i32 1, i8 3, i32 1, i8 1, (.*)}"},
 
-    {"!{i32 1, !\"Array\", i8 5, i8 0, !\\1, i8 1, i32 2, i8 1, i32 1, i8 1, null}\\2"
+    {"!{i32 1, !\"Array\", i8 5, i8 0, !\\1, i8 1, i32 2, i8 1, i32 1, i8 1, \\2}\\3"
     "!\\1 = !{i32 0, i32 1}\n",
-    "= !{i32 2, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 3, i32 2, i8 0, null}"},
+    "= !{i32 2, !\"Value\", i8 5, i8 0, !\\1, i8 1, i32 1, i8 3, i32 2, i8 0, \\2}"},
 
     "signature element Value at location \\(2,0\\) size \\(1,3\\) overlaps another signature element.",
     /*bRegex*/true);
@@ -2291,8 +2317,8 @@ float4 main(float4 f4 : Input, out float d0 : SV_Depth, out float d1 : SV_Target
 { d0 = f4.z; d1 = f4.w; return f4; } \
     ",
     "ps_6_0",
-    {"!{i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 1, i32 0, i8 0, null}"},
-    {"!{i32 2, !\"SV_DepthGreaterEqual\", i8 9, i8 19, !\\1, i8 0, i32 1, i8 1, i32 -1, i8 -1, null}"},
+    {"!{i32 2, !\"SV_Target\", i8 9, i8 16, !([0-9]+), i8 0, i32 1, i8 1, i32 0, i8 0, (.*)}"},
+    {"!{i32 2, !\"SV_DepthGreaterEqual\", i8 9, i8 19, !\\1, i8 0, i32 1, i8 1, i32 -1, i8 -1, \\2}"},
     "Pixel Shader only allows one type of depth semantic to be declared",
     /*bRegex*/true);
 }
@@ -2863,7 +2889,7 @@ TEST_F(ValidationTest, WhenProgramSigMismatchThenFail) {
     {
       "Container part 'Program Input Signature' does not match expected for module.",
       "Container part 'Program Output Signature' does not match expected for module.",
-      "Container part 'Program Patch Constant or Primitive Signature' does not match expected for module.",
+      "Container part 'Program Patch Constant Signature' does not match expected for module.",
       "Validation failed."
     }
   );
@@ -2909,7 +2935,7 @@ TEST_F(ValidationTest, WhenProgramSigMismatchThenFail2) {
     {
       "Container part 'Program Input Signature' does not match expected for module.",
       "Container part 'Program Output Signature' does not match expected for module.",
-      "Container part 'Program Patch Constant or Primitive Signature' does not match expected for module.",
+      "Container part 'Program Patch Constant Signature' does not match expected for module.",
       "Validation failed."
     }
   );
@@ -3649,10 +3675,10 @@ TEST_F(ValidationTest, MeshGreaterThanMaxXYZ) {
 
 TEST_F(ValidationTest, MeshGreaterThanMaxVSigRowCount) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\mesh-val\\mesh.hlsl", "ms_6_5",
-                          "!([0-9]+) = !{i32 1, !\"COLOR\", i8 9, i8 0, !([0-9]+), i8 2, i32 4, i8 1, i32 1, i8 0, null}\n"
-                          "!([0-9]+) = !{i32 0, i32 1, i32 2, i32 3}",
-                          "!\\1 = !{i32 1, !\"COLOR\", i8 9, i8 0, !\\2, i8 2, i32 32, i8 1, i32 1, i8 0, null}\n"
-                          "!\\3 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
+                          "!([0-9]+) = !{i32 1, !\"COLOR\", i8 9, i8 0, !([0-9]+), i8 2, i32 4, i8 1, i32 1, i8 0, (.*)"
+                          "!\\2 = !{i32 0, i32 1, i32 2, i32 3}",
+                          "!\\1 = !{i32 1, !\"COLOR\", i8 9, i8 0, !\\2, i8 2, i32 32, i8 1, i32 1, i8 0, \\3"
+                          "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
                           "i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20,"
                           "i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31}",
                           "For shader 'main', vertex output signatures are taking up more than 32 rows",
@@ -3661,10 +3687,10 @@ TEST_F(ValidationTest, MeshGreaterThanMaxVSigRowCount) {
 
 TEST_F(ValidationTest, MeshGreaterThanMaxPSigRowCount) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\mesh-val\\mesh.hlsl", "ms_6_5",
-                          "!([0-9]+) = !{i32 4, !\"LAYER\", i8 4, i8 0, !([0-9]+), i8 1, i32 6, i8 1, i32 1, i8 0, null}\n"
-                          "!([0-9]+) = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}",
-                          "!\\1 = !{i32 4, !\"LAYER\", i8 4, i8 0, !\\2, i8 1, i32 32, i8 1, i32 1, i8 0, null}\n"
-                          "!\\3 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
+                          "!([0-9]+) = !{i32 4, !\"LAYER\", i8 4, i8 0, !([0-9]+), i8 1, i32 6, i8 1, i32 1, i8 0, (.*)"
+                          "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}",
+                          "!\\1 = !{i32 4, !\"LAYER\", i8 4, i8 0, !\\2, i8 1, i32 32, i8 1, i32 1, i8 0, \\3"
+                          "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
                           "i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17, i32 18, i32 19, i32 20,"
                           "i32 21, i32 22, i32 23, i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31}",
                           "For shader 'main', primitive output signatures are taking up more than 32 rows",
@@ -3673,15 +3699,15 @@ TEST_F(ValidationTest, MeshGreaterThanMaxPSigRowCount) {
 
 TEST_F(ValidationTest, MeshGreaterThanMaxTotalSigRowCount) {
   RewriteAssemblyCheckMsg(L"..\\CodeGenHLSL\\mesh-val\\mesh.hlsl", "ms_6_5",
-                          { "!([0-9]+) = !{i32 1, !\"COLOR\", i8 9, i8 0, !([0-9]+), i8 2, i32 4, i8 1, i32 1, i8 0, null}\n"
-                            "!([0-9]+) = !{i32 0, i32 1, i32 2, i32 3}",
-                            "!([0-9]+) = !{i32 4, !\"LAYER\", i8 4, i8 0, !([0-9]+), i8 1, i32 6, i8 1, i32 1, i8 0, null}\n"
-                            "!([0-9]+) = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}" },
-                          { "!\\1 = !{i32 1, !\"COLOR\", i8 9, i8 0, !\\2, i8 2, i32 16, i8 1, i32 1, i8 0, null}\n"
-                            "!\\3 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
+                          { "!([0-9]+) = !{i32 1, !\"COLOR\", i8 9, i8 0, !([0-9]+), i8 2, i32 4, i8 1, i32 1, i8 0, (.*)"
+                            "!\\2 = !{i32 0, i32 1, i32 2, i32 3}",
+                            "!([0-9]+) = !{i32 4, !\"LAYER\", i8 4, i8 0, !([0-9]+), i8 1, i32 6, i8 1, i32 1, i8 0, (.*)"
+                            "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5}" },
+                          { "!\\1 = !{i32 1, !\"COLOR\", i8 9, i8 0, !\\2, i8 2, i32 16, i8 1, i32 1, i8 0, \\3"
+                            "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
                             "i32 11, i32 12, i32 13, i32 14, i32 15}",
-                            "!\\1 = !{i32 4, !\"LAYER\", i8 4, i8 0, !\\2, i8 1, i32 16, i8 1, i32 1, i8 0, null}\n"
-                            "!\\3 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
+                            "!\\1 = !{i32 4, !\"LAYER\", i8 4, i8 0, !\\2, i8 1, i32 16, i8 1, i32 1, i8 0, \\3"
+                            "!\\2 = !{i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10,"
                             "i32 11, i32 12, i32 13, i32 14, i32 15}",
                           },
                           "For shader 'main', vertex and primitive output signatures are taking up more than 32 rows",

+ 0 - 1
utils/hct/hctdb.py

@@ -2271,7 +2271,6 @@ class db_dxil(object):
         self.add_valrule("Meta.TessellatorOutputPrimitive", "Invalid Tessellator Output Primitive specified. Must be point, line, triangleCW or triangleCCW.")
         self.add_valrule("Meta.MaxTessFactor", "Hull Shader MaxTessFactor must be [%0..%1].  %2 specified")
         self.add_valrule("Meta.ValidSamplerMode", "Invalid sampler mode on sampler ")
-        self.add_valrule("Meta.FunctionAnnotation", "Cannot find function annotation for %0")
         self.add_valrule("Meta.GlcNotOnAppendConsume", "globallycoherent cannot be used with append/consume buffers")
         self.add_valrule_msg("Meta.StructBufAlignment", "StructuredBuffer stride not aligned","structured buffer element size must be a multiple of %0 bytes (actual size %1 bytes)")
         self.add_valrule_msg("Meta.StructBufAlignmentOutOfBound", "StructuredBuffer stride out of bounds","structured buffer elements cannot be larger than %0 bytes (actual size %1 bytes)")