瀏覽代碼

Merged PR 35: Merge user/kiyoung/function-feature-flag to user/texr/rt-merge-rebase

- Refactoring ShaderFlag out of DxilModule
- Have Shader Flag per function on RDAT blob
Young Kim 7 年之前
父節點
當前提交
20067a37fe

+ 3 - 0
include/dxc/HLSL/DxilConstants.h

@@ -851,6 +851,9 @@ namespace DXIL {
     const unsigned kCreateHandleResIndexOpIdx = 3;
     const unsigned kCreateHandleIsUniformOpIdx = 4;
 
+    // CreateHandleFromResource
+    const unsigned kCreateHandleFromResourceStructForLibResOpIdx = 1;
+
     // TraceRay
     const unsigned kTraceRayRayDescOpIdx = 7;
     const unsigned kTraceRayPayloadOpIdx = 15;

+ 17 - 126
include/dxc/HLSL/DxilModule.h

@@ -15,13 +15,12 @@
 #include "dxc/HLSL/DxilCBuffer.h"
 #include "dxc/HLSL/DxilResource.h"
 #include "dxc/HLSL/DxilSampler.h"
+#include "dxc/HLSL/DxilShaderFlags.h"
 #include "dxc/HLSL/DxilSignature.h"
 #include "dxc/HLSL/DxilConstants.h"
 #include "dxc/HLSL/DxilTypeSystem.h"
 #include "dxc/HLSL/ComputeViewIdState.h"
 
-
-
 #include <memory>
 #include <string>
 #include <vector>
@@ -81,8 +80,7 @@ public:
 
   // Flags.
   unsigned GetGlobalFlags() const;
-  // TODO: move out of DxilModule as a util.
-  void CollectShaderFlags();
+  void CollectShaderFlagsForModule();
 
   // Resources.
   unsigned AddCBuffer(std::unique_ptr<DxilCBuffer> pCB);
@@ -126,7 +124,7 @@ public:
   DxilSignature &GetPatchConstantSignature();
   const DxilSignature &GetPatchConstantSignature() const;
   const RootSignatureHandle &GetRootSignature() const;
-  bool HasDxilEntrySignature(llvm::Function *F) const;
+  bool HasDxilEntrySignature(const llvm::Function *F) const;
   DxilEntrySignature &GetDxilEntrySignature(const llvm::Function *F);
   // Move DxilEntrySignature of F to NewF.
   void ReplaceDxilEntrySignature(llvm::Function *F, llvm::Function *NewF);
@@ -213,128 +211,8 @@ public:
   static bool PreservesFastMathFlags(const llvm::Instruction *inst);
 
 public:
-  // Shader properties.
-  class ShaderFlags {
-  public:
-    ShaderFlags();
-
-    unsigned GetGlobalFlags() const;
-    void SetDisableOptimizations(bool flag) { m_bDisableOptimizations = flag; }
-    bool GetDisableOptimizations() const { return m_bDisableOptimizations; }
-
-    void SetDisableMathRefactoring(bool flag) { m_bDisableMathRefactoring = flag; }
-    bool GetDisableMathRefactoring() const { return m_bDisableMathRefactoring; }
-
-    void SetEnableDoublePrecision(bool flag) { m_bEnableDoublePrecision = flag; }
-    bool GetEnableDoublePrecision() const { return m_bEnableDoublePrecision; }
-
-    void SetForceEarlyDepthStencil(bool flag) { m_bForceEarlyDepthStencil = flag; }
-    bool GetForceEarlyDepthStencil() const { return m_bForceEarlyDepthStencil; }
-
-    void SetEnableRawAndStructuredBuffers(bool flag) { m_bEnableRawAndStructuredBuffers = flag; }
-    bool GetEnableRawAndStructuredBuffers() const { return m_bEnableRawAndStructuredBuffers; }
-
-    void SetLowPrecisionPresent(bool flag) { m_bLowPrecisionPresent = flag; }
-    bool GetLowPrecisionPresent() const { return m_bLowPrecisionPresent; }
-
-    void SetEnableDoubleExtensions(bool flag) { m_bEnableDoubleExtensions = flag; }
-    bool GetEnableDoubleExtensions() const { return m_bEnableDoubleExtensions; }
-
-    void SetEnableMSAD(bool flag) { m_bEnableMSAD = flag; }
-    bool GetEnableMSAD() const { return m_bEnableMSAD; }
-
-    void SetAllResourcesBound(bool flag) { m_bAllResourcesBound = flag; }
-    bool GetAllResourcesBound() const { return m_bAllResourcesBound; }
-
-    uint64_t GetFeatureInfo() const;
-    void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
-    bool GetCSRawAndStructuredViaShader4X() const { return m_bCSRawAndStructuredViaShader4X; }
-
-    void SetROVs(bool flag) { m_bROVS = flag; }
-    bool GetROVs() const { return m_bROVS; }
-
-    void SetWaveOps(bool flag) { m_bWaveOps = flag; }
-    bool GetWaveOps() const { return m_bWaveOps; }
-
-    void SetInt64Ops(bool flag) { m_bInt64Ops = flag; }
-    bool GetInt64Ops() const { return m_bInt64Ops; }
-
-    void SetTiledResources(bool flag) { m_bTiledResources = flag; }
-    bool GetTiledResources() const { return m_bTiledResources; }
-
-    void SetStencilRef(bool flag) { m_bStencilRef = flag; }
-    bool GetStencilRef() const { return m_bStencilRef; }
-
-    void SetInnerCoverage(bool flag) { m_bInnerCoverage = flag; }
-    bool GetInnerCoverage() const { return m_bInnerCoverage; }
-
-    void SetViewportAndRTArrayIndex(bool flag) { m_bViewportAndRTArrayIndex = flag; }
-    bool GetViewportAndRTArrayIndex() const { return m_bViewportAndRTArrayIndex; }
-
-    void SetUAVLoadAdditionalFormats(bool flag) { m_bUAVLoadAdditionalFormats = flag; }
-    bool GetUAVLoadAdditionalFormats() const { return m_bUAVLoadAdditionalFormats; }
-
-    void SetLevel9ComparisonFiltering(bool flag) { m_bLevel9ComparisonFiltering = flag; }
-    bool GetLevel9ComparisonFiltering() const { return m_bLevel9ComparisonFiltering; }
-
-    void Set64UAVs(bool flag) { m_b64UAVs = flag; }
-    bool Get64UAVs() const { return m_b64UAVs; }
-
-    void SetUAVsAtEveryStage(bool flag) { m_UAVsAtEveryStage = flag; }
-    bool GetUAVsAtEveryStage() const { return m_UAVsAtEveryStage; }
-
-    void SetViewID(bool flag) { m_bViewID = flag; }
-    bool GetViewID() const { return m_bViewID; }
-
-    void SetBarycentrics(bool flag) { m_bBarycentrics = flag; }
-    bool GetBarycentrics() const { return m_bBarycentrics; }
-
-    void SetUseNativeLowPrecision(bool flag) { m_bUseNativeLowPrecision = flag; }
-    bool GetUseNativeLowPrecision() const { return m_bUseNativeLowPrecision; }
-
-    static uint64_t GetShaderFlagsRawForCollection(); // some flags are collected (eg use 64-bit), some provided (eg allow refactoring)
-    uint64_t GetShaderFlagsRaw() const;
-    void SetShaderFlagsRaw(uint64_t data);
-
-  private:
-    unsigned m_bDisableOptimizations :1;   // D3D11_1_SB_GLOBAL_FLAG_SKIP_OPTIMIZATION
-    unsigned m_bDisableMathRefactoring :1; //~D3D10_SB_GLOBAL_FLAG_REFACTORING_ALLOWED
-    unsigned m_bEnableDoublePrecision :1; // D3D11_SB_GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS
-    unsigned m_bForceEarlyDepthStencil :1; // D3D11_SB_GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL
-    unsigned m_bEnableRawAndStructuredBuffers :1; // D3D11_SB_GLOBAL_FLAG_ENABLE_RAW_AND_STRUCTURED_BUFFERS
-    unsigned m_bLowPrecisionPresent :1; // D3D11_1_SB_GLOBAL_FLAG_ENABLE_MINIMUM_PRECISION
-    unsigned m_bEnableDoubleExtensions :1; // D3D11_1_SB_GLOBAL_FLAG_ENABLE_DOUBLE_EXTENSIONS
-    unsigned m_bEnableMSAD :1;        // D3D11_1_SB_GLOBAL_FLAG_ENABLE_SHADER_EXTENSIONS
-    unsigned m_bAllResourcesBound :1; // D3D12_SB_GLOBAL_FLAG_ALL_RESOURCES_BOUND
-
-    unsigned m_bViewportAndRTArrayIndex :1;   // SHADER_FEATURE_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER
-    unsigned m_bInnerCoverage :1;             // SHADER_FEATURE_INNER_COVERAGE
-    unsigned m_bStencilRef  :1;               // SHADER_FEATURE_STENCIL_REF
-    unsigned m_bTiledResources  :1;           // SHADER_FEATURE_TILED_RESOURCES
-    unsigned m_bUAVLoadAdditionalFormats :1;  // SHADER_FEATURE_TYPED_UAV_LOAD_ADDITIONAL_FORMATS
-    unsigned m_bLevel9ComparisonFiltering :1; // SHADER_FEATURE_LEVEL_9_COMPARISON_FILTERING
-                                              // SHADER_FEATURE_11_1_SHADER_EXTENSIONS shared with EnableMSAD
-    unsigned m_b64UAVs :1;                    // SHADER_FEATURE_64_UAVS
-    unsigned m_UAVsAtEveryStage :1;           // SHADER_FEATURE_UAVS_AT_EVERY_STAGE
-    unsigned m_bCSRawAndStructuredViaShader4X : 1; // SHADER_FEATURE_COMPUTE_SHADERS_PLUS_RAW_AND_STRUCTURED_BUFFERS_VIA_SHADER_4_X
-    
-    // SHADER_FEATURE_COMPUTE_SHADERS_PLUS_RAW_AND_STRUCTURED_BUFFERS_VIA_SHADER_4_X is specifically
-    // about shader model 4.x.
-
-    unsigned m_bROVS :1;              // SHADER_FEATURE_ROVS
-    unsigned m_bWaveOps :1;           // SHADER_FEATURE_WAVE_OPS
-    unsigned m_bInt64Ops :1;          // SHADER_FEATURE_INT64_OPS
-    unsigned m_bViewID : 1;           // SHADER_FEATURE_VIEWID
-    unsigned m_bBarycentrics : 1;     // SHADER_FEATURE_BARYCENTRICS
-
-    unsigned m_bUseNativeLowPrecision : 1;
-
-    unsigned m_align0 : 8;        // align to 32 bit.
-    uint32_t m_align1;            // align to 64 bit.
-  };
-
   ShaderFlags m_ShaderFlags;
-  void CollectShaderFlags(ShaderFlags &Flags);
+  void CollectShaderFlagsForModule(ShaderFlags &Flags);
 
   // Check if DxilModule contains multi component UAV Loads.
   // This funciton must be called after unused resources are removed from DxilModule
@@ -359,6 +237,14 @@ public:
   void SetActiveStreamMask(unsigned Mask);
   unsigned GetActiveStreamMask() const;
 
+  // Language options
+  void SetUseMinPrecision(bool useMinPrecision);
+  bool GetUseMinPrecision() const;
+  void SetDisableOptimization(bool disableOptimization);
+  bool GetDisableOptimization() const;
+  void SetAllResourcesBound(bool resourcesBound);
+  bool GetAllResourcesBound() const;
+
   // Hull and Domain shaders.
   unsigned GetInputControlPointCount() const;
   void SetInputControlPointCount(unsigned NumICPs);
@@ -448,6 +334,11 @@ private:
   // Helpers.
   template<typename T> unsigned AddResource(std::vector<std::unique_ptr<T> > &Vec, std::unique_ptr<T> pRes);
   void LoadDxilSignature(const llvm::MDTuple *pSigTuple, DxilSignature &Sig, bool bInput);
+
+  // properties from HLModule
+  bool m_bDisableOptimizations;
+  bool m_bUseMinPrecision;
+  bool m_bAllResourcesBound;
 };
 
 } // namespace hlsl

+ 52 - 57
include/dxc/HLSL/DxilPipelineStateValidation.h

@@ -405,15 +405,24 @@ struct PSVInitInfo
   uint8_t SigOutputVectors[4] = {0, 0, 0, 0};
 };
 
+struct ResourceTableReader;
+struct FunctionTableReader;
+
+struct RuntimeDataContext {
+  PSVStringTable *pStringTableReader;
+  IndexTableReader *pIndexTableReader;
+  ResourceTableReader *pResourceTableReader;
+  FunctionTableReader *pFunctionTableReader;
+};
+
 struct ResourceReader {
 private:
   const RuntimeDataResourceInfo *m_ResourceInfo;
-  PSVStringTable *m_StringReader;
+  RuntimeDataContext *m_Context;
 public:
-  ResourceReader() : m_ResourceInfo(nullptr), m_StringReader(nullptr) {}
   ResourceReader(const RuntimeDataResourceInfo *resInfo,
-                 PSVStringTable *stringReader)
-      : m_ResourceInfo(resInfo), m_StringReader(stringReader) {}
+                 RuntimeDataContext *context)
+      : m_ResourceInfo(resInfo), m_Context(context) {}
   PSVResourceType GetResourceType() {
     return (PSVResourceType)m_ResourceInfo->ResType;
   }
@@ -427,13 +436,15 @@ public:
     return m_ResourceInfo->UpperBound;
   }
   PSVResourceKind GetResourceKind() { return (PSVResourceKind)m_ResourceInfo->Kind; }
-  const char* GetName() { return m_StringReader->Get(m_ResourceInfo->Name); }
+  const char *GetName() {
+    return m_Context->pStringTableReader->Get(m_ResourceInfo->Name);
+  }
 };
 
 struct ResourceTableReader {
 private:
   const RuntimeDataResourceInfo *m_ResourceInfo; // pointer to an array of resource bind infos
-  PSVStringTable *m_StringReader;
+  RuntimeDataContext *m_Context;
   uint32_t m_CBufferCount;
   uint32_t m_SamplerCount;
   uint32_t m_SRVCount;
@@ -441,18 +452,18 @@ private:
 
 public:
   ResourceTableReader()
-      : m_ResourceInfo(nullptr), m_StringReader(nullptr), m_CBufferCount(0),
+      : m_ResourceInfo(nullptr), m_Context(nullptr), m_CBufferCount(0),
         m_SamplerCount(0), m_SRVCount(0), m_UAVCount(0){};
   ResourceTableReader(const RuntimeDataResourceInfo *info1,
-                      PSVStringTable *stringTable, uint32_t CBufferCount,
+                      RuntimeDataContext *context, uint32_t CBufferCount,
                       uint32_t SamplerCount, uint32_t SRVCount,
                       uint32_t UAVCount)
-      : m_ResourceInfo(info1), m_StringReader(stringTable),
+      : m_ResourceInfo(info1), m_Context(context),
         m_CBufferCount(CBufferCount), m_SamplerCount(SamplerCount),
         m_SRVCount(SRVCount), m_UAVCount(UAVCount){};
 
   void SetResourceInfo(const RuntimeDataResourceInfo *ptr) { m_ResourceInfo = ptr; }
-  void SetStringReader(PSVStringTable *ptr) { m_StringReader = ptr; }
+  void SetContext(RuntimeDataContext *context) { m_Context = context; }
   void SetCBufferCount(uint32_t count) { m_CBufferCount = count; }
   void SetSamplerCount(uint32_t count) { m_SamplerCount = count; }
   void SetSRVCount(uint32_t count) { m_SRVCount = count; }
@@ -463,58 +474,53 @@ public:
   }
   ResourceReader GetItem(uint32_t i) {
     _Analysis_assume_(i < GetNumResources());
-    return ResourceReader(&m_ResourceInfo[i], m_StringReader);
+    return ResourceReader(&m_ResourceInfo[i], m_Context);
   }
 
 
   uint32_t GetNumCBuffers() { return m_CBufferCount; }
   ResourceReader GetCBuffer(uint32_t i) {
     _Analysis_assume_(i < m_CBufferCount);
-    return ResourceReader(&m_ResourceInfo[i], m_StringReader);
+    return ResourceReader(&m_ResourceInfo[i], m_Context);
   }
 
   uint32_t GetNumSamplers() { return m_SamplerCount; }
   ResourceReader GetSampler(uint32_t i) {
     _Analysis_assume_(i < m_SamplerCount);
     uint32_t offset = (m_CBufferCount + i);
-    return ResourceReader(&m_ResourceInfo[offset], m_StringReader);
+    return ResourceReader(&m_ResourceInfo[offset], m_Context);
   }
 
   uint32_t GetNumSRVs() { return m_SRVCount; }
   ResourceReader GetSRV(uint32_t i) {
     _Analysis_assume_(i < m_SRVCount);
     uint32_t offset = (m_CBufferCount + m_SamplerCount + i);
-    return ResourceReader(&m_ResourceInfo[offset], m_StringReader);
+    return ResourceReader(&m_ResourceInfo[offset], m_Context);
   }
 
   uint32_t GetNumUAVs() { return m_UAVCount; }
   ResourceReader GetUAV(uint32_t i) {
     _Analysis_assume_(i < m_UAVCount);
     uint32_t offset = (m_CBufferCount + m_SamplerCount + m_SRVCount + i);
-    return ResourceReader(&m_ResourceInfo[offset], m_StringReader);
+    return ResourceReader(&m_ResourceInfo[offset], m_Context);
   }
 };
 
 struct FunctionReader {
 private:
   const RuntimeDataFunctionInfo *m_RuntimeDataFunctionInfo;
-  PSVStringTable *m_StringReader;
-  IndexTableReader *m_IndexTableReader;
-  ResourceTableReader *m_ResourceTableReader;
+  RuntimeDataContext *m_Context;
 public:
-  FunctionReader()
-      : m_RuntimeDataFunctionInfo(nullptr), m_StringReader(nullptr),
-        m_IndexTableReader(nullptr), m_ResourceTableReader(nullptr) {}
+  FunctionReader() : m_RuntimeDataFunctionInfo(nullptr), m_Context(nullptr){}
   FunctionReader(const RuntimeDataFunctionInfo *functionInfo,
-                 PSVStringTable *stringReader,
-                 IndexTableReader *indexTableReader,
-                 ResourceTableReader *resourceTableReader)
-      : m_RuntimeDataFunctionInfo(functionInfo), m_StringReader(stringReader),
-        m_IndexTableReader(indexTableReader),
-        m_ResourceTableReader(resourceTableReader) {}
-
-  const char *GetName() { return m_StringReader->Get(m_RuntimeDataFunctionInfo->Name); }
-  const char *GetUnmangledName() { return m_StringReader->Get(m_RuntimeDataFunctionInfo->UnmangledName); }
+                 RuntimeDataContext *context)
+      : m_RuntimeDataFunctionInfo(functionInfo), m_Context(context){}
+
+  const char *GetName() { return m_Context->pStringTableReader->Get(m_RuntimeDataFunctionInfo->Name); }
+  const char *GetUnmangledName() {
+    return m_Context->pStringTableReader->Get(
+        m_RuntimeDataFunctionInfo->UnmangledName);
+  }
   uint64_t GetFeatureFlag() {
     uint64_t flag = static_cast<uint64_t>(m_RuntimeDataFunctionInfo->FeatureInfo2) << 32;
     flag |= static_cast<uint64_t>(m_RuntimeDataFunctionInfo->FeatureInfo1);
@@ -525,11 +531,11 @@ public:
   uint32_t FunctionReader::GetNumResources() {
     if (m_RuntimeDataFunctionInfo->Resources == UINT_MAX)
       return 0;
-    return m_IndexTableReader->getRow(m_RuntimeDataFunctionInfo->Resources).Count();
+    return m_Context->pIndexTableReader->getRow(m_RuntimeDataFunctionInfo->Resources).Count();
   }
   ResourceReader GetResource(uint32_t i) {
-    uint32_t resIndex = m_IndexTableReader->getRow(m_RuntimeDataFunctionInfo->Resources).At(i);
-    return m_ResourceTableReader->GetItem(resIndex);
+    uint32_t resIndex = m_Context->pIndexTableReader->getRow(m_RuntimeDataFunctionInfo->Resources).At(i);
+    return m_Context->pResourceTableReader->GetItem(resIndex);
   }
 
   uint32_t GetPayloadSizeInBytes() { return m_RuntimeDataFunctionInfo->PayloadSizeInBytes; }
@@ -543,32 +549,21 @@ struct FunctionTableReader {
 private:
   const RuntimeDataFunctionInfo *m_infos;
   uint32_t m_count;
-  PSVStringTable *m_StringReader;
-  IndexTableReader *m_IndexTableReader;
-  ResourceTableReader *m_ResourceTableReader;
+  RuntimeDataContext *m_context;
 public:
-  FunctionTableReader()
-      : m_infos(nullptr), m_count(0), m_StringReader(nullptr),
-        m_IndexTableReader(nullptr), m_ResourceTableReader(nullptr) {}
+  FunctionTableReader() : m_infos(nullptr), m_count(0), m_context(nullptr) {}
   FunctionTableReader(const RuntimeDataFunctionInfo *functionInfos,
-                      uint32_t count, PSVStringTable *stringReader = nullptr,
-                      IndexTableReader *indexTableReader = nullptr,
-                      ResourceTableReader *resourceTableReader = nullptr)
-      : m_infos(functionInfos), m_count(count), m_StringReader(stringReader),
-        m_IndexTableReader(indexTableReader),
-        m_ResourceTableReader(resourceTableReader) {}
+                      uint32_t count, RuntimeDataContext *context)
+      : m_infos(functionInfos), m_count(count), m_context(context) {}
 
   FunctionReader GetItem(uint32_t i) {
-    return FunctionReader(&m_infos[i], m_StringReader, m_IndexTableReader,
-                          m_ResourceTableReader);
+    return FunctionReader(&m_infos[i], m_context);
   }
   uint32_t GetNumFunctions() { return m_count; }
 
-  void SetStringReader(PSVStringTable *ptr) { m_StringReader = ptr; }
-  void SetIndexTableReader(IndexTableReader *ptr) { m_IndexTableReader = ptr; }
-  void SetResourceTableReader(ResourceTableReader *ptr) { m_ResourceTableReader = ptr; }
   void SetFunctionInfo(const RuntimeDataFunctionInfo *ptr) { m_infos = ptr; }
   void SetCount(uint32_t count) { m_count = count; }
+  void SetContext(RuntimeDataContext *context) { m_context = context; }
 };
 
 class DxilRuntimeData {
@@ -578,12 +573,14 @@ private:
   IndexTableReader m_IndexTableReader;
   ResourceTableReader m_ResourceTableReader;
   FunctionTableReader m_FunctionTableReader;
-  friend struct FunctionReader;
-  friend struct ResourceReader;
+  RuntimeDataContext m_Context;
 public:
   DxilRuntimeData()
       : m_TableCount(0), m_StringReader(), m_ResourceTableReader(),
-        m_FunctionTableReader(), m_IndexTableReader() {}
+        m_FunctionTableReader(), m_IndexTableReader(), m_Context() {
+    m_Context = {&m_StringReader, &m_IndexTableReader, &m_ResourceTableReader,
+                 &m_FunctionTableReader};
+  }
   DxilRuntimeData(const char *ptr) {
     InitFromRDAT(ptr);
   }
@@ -605,13 +602,11 @@ public:
             m_ResourceTableReader.SetSamplerCount(samplerCount);
             m_ResourceTableReader.SetSRVCount(srvCount);
             m_ResourceTableReader.SetUAVCount(uavCount);
-            m_FunctionTableReader.SetResourceTableReader(&m_ResourceTableReader);
+            m_ResourceTableReader.SetContext(&m_Context);
             break;
           }
           case RuntimeDataTableType::String: {
             m_StringReader = PSVStringTable(ptr + curRecord->offset, curRecord->size);
-            m_ResourceTableReader.SetStringReader(&m_StringReader);
-            m_FunctionTableReader.SetStringReader(&m_StringReader);
             break;
           }
           case RuntimeDataTableType::Function: {
@@ -619,12 +614,12 @@ public:
                 (RuntimeDataFunctionInfo *)(ptr + curRecord->offset);
             m_FunctionTableReader.SetFunctionInfo(funcInfo);
             m_FunctionTableReader.SetCount(curRecord->size / sizeof(RuntimeDataFunctionInfo));
+            m_FunctionTableReader.SetContext(&m_Context);
             break;
           }
           case RuntimeDataTableType::Index: {
             m_IndexTableReader = IndexTableReader(
                 (uint32_t *)(ptr + curRecord->offset), curRecord->size / 4);
-            m_FunctionTableReader.SetIndexTableReader(&m_IndexTableReader);
             break;
           }
           default:

+ 147 - 0
include/dxc/HLSL/DxilShaderFlags.h

@@ -0,0 +1,147 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilShaderFlags.h                                                         //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Shader flags for a dxil shader function.                                  //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace hlsl {
+  class DxilModule;
+}
+
+namespace llvm {
+  class Function;
+}
+
+namespace hlsl {
+  // Shader properties.
+  class ShaderFlags {
+  public:
+    ShaderFlags();
+
+    static ShaderFlags CollectShaderFlags(const llvm::Function *F, const hlsl::DxilModule *M);
+    unsigned GetGlobalFlags() const;
+    uint64_t GetFeatureInfo() const;
+    static uint64_t GetShaderFlagsRawForCollection(); // some flags are collected (eg use 64-bit), some provided (eg allow refactoring)
+    uint64_t GetShaderFlagsRaw() const;
+    void SetShaderFlagsRaw(uint64_t data);
+    void CombineShaderFlags(const ShaderFlags &other);
+
+    void SetDisableOptimizations(bool flag) { m_bDisableOptimizations = flag; }
+    bool GetDisableOptimizations() const { return m_bDisableOptimizations; }
+
+    void SetDisableMathRefactoring(bool flag) { m_bDisableMathRefactoring = flag; }
+    bool GetDisableMathRefactoring() const { return m_bDisableMathRefactoring; }
+
+    void SetEnableDoublePrecision(bool flag) { m_bEnableDoublePrecision = flag; }
+    bool GetEnableDoublePrecision() const { return m_bEnableDoublePrecision; }
+
+    void SetForceEarlyDepthStencil(bool flag) { m_bForceEarlyDepthStencil = flag; }
+    bool GetForceEarlyDepthStencil() const { return m_bForceEarlyDepthStencil; }
+
+    void SetEnableRawAndStructuredBuffers(bool flag) { m_bEnableRawAndStructuredBuffers = flag; }
+    bool GetEnableRawAndStructuredBuffers() const { return m_bEnableRawAndStructuredBuffers; }
+
+    void SetLowPrecisionPresent(bool flag) { m_bLowPrecisionPresent = flag; }
+    bool GetLowPrecisionPresent() const { return m_bLowPrecisionPresent; }
+
+    void SetEnableDoubleExtensions(bool flag) { m_bEnableDoubleExtensions = flag; }
+    bool GetEnableDoubleExtensions() const { return m_bEnableDoubleExtensions; }
+
+    void SetEnableMSAD(bool flag) { m_bEnableMSAD = flag; }
+    bool GetEnableMSAD() const { return m_bEnableMSAD; }
+
+    void SetAllResourcesBound(bool flag) { m_bAllResourcesBound = flag; }
+    bool GetAllResourcesBound() const { return m_bAllResourcesBound; }
+
+    void SetCSRawAndStructuredViaShader4X(bool flag) { m_bCSRawAndStructuredViaShader4X = flag; }
+    bool GetCSRawAndStructuredViaShader4X() const { return m_bCSRawAndStructuredViaShader4X; }
+
+    void SetROVs(bool flag) { m_bROVS = flag; }
+    bool GetROVs() const { return m_bROVS; }
+
+    void SetWaveOps(bool flag) { m_bWaveOps = flag; }
+    bool GetWaveOps() const { return m_bWaveOps; }
+
+    void SetInt64Ops(bool flag) { m_bInt64Ops = flag; }
+    bool GetInt64Ops() const { return m_bInt64Ops; }
+
+    void SetTiledResources(bool flag) { m_bTiledResources = flag; }
+    bool GetTiledResources() const { return m_bTiledResources; }
+
+    void SetStencilRef(bool flag) { m_bStencilRef = flag; }
+    bool GetStencilRef() const { return m_bStencilRef; }
+
+    void SetInnerCoverage(bool flag) { m_bInnerCoverage = flag; }
+    bool GetInnerCoverage() const { return m_bInnerCoverage; }
+
+    void SetViewportAndRTArrayIndex(bool flag) { m_bViewportAndRTArrayIndex = flag; }
+    bool GetViewportAndRTArrayIndex() const { return m_bViewportAndRTArrayIndex; }
+
+    void SetUAVLoadAdditionalFormats(bool flag) { m_bUAVLoadAdditionalFormats = flag; }
+    bool GetUAVLoadAdditionalFormats() const { return m_bUAVLoadAdditionalFormats; }
+
+    void SetLevel9ComparisonFiltering(bool flag) { m_bLevel9ComparisonFiltering = flag; }
+    bool GetLevel9ComparisonFiltering() const { return m_bLevel9ComparisonFiltering; }
+
+    void Set64UAVs(bool flag) { m_b64UAVs = flag; }
+    bool Get64UAVs() const { return m_b64UAVs; }
+
+    void SetUAVsAtEveryStage(bool flag) { m_UAVsAtEveryStage = flag; }
+    bool GetUAVsAtEveryStage() const { return m_UAVsAtEveryStage; }
+
+    void SetViewID(bool flag) { m_bViewID = flag; }
+    bool GetViewID() const { return m_bViewID; }
+
+    void SetBarycentrics(bool flag) { m_bBarycentrics = flag; }
+    bool GetBarycentrics() const { return m_bBarycentrics; }
+
+    void SetUseNativeLowPrecision(bool flag) { m_bUseNativeLowPrecision = flag; }
+    bool GetUseNativeLowPrecision() const { return m_bUseNativeLowPrecision; }
+
+  private:
+    unsigned m_bDisableOptimizations :1;   // D3D11_1_SB_GLOBAL_FLAG_SKIP_OPTIMIZATION
+    unsigned m_bDisableMathRefactoring :1; //~D3D10_SB_GLOBAL_FLAG_REFACTORING_ALLOWED
+    unsigned m_bEnableDoublePrecision :1; // D3D11_SB_GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS
+    unsigned m_bForceEarlyDepthStencil :1; // D3D11_SB_GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL
+    unsigned m_bEnableRawAndStructuredBuffers :1; // D3D11_SB_GLOBAL_FLAG_ENABLE_RAW_AND_STRUCTURED_BUFFERS
+    unsigned m_bLowPrecisionPresent :1; // D3D11_1_SB_GLOBAL_FLAG_ENABLE_MINIMUM_PRECISION
+    unsigned m_bEnableDoubleExtensions :1; // D3D11_1_SB_GLOBAL_FLAG_ENABLE_DOUBLE_EXTENSIONS
+    unsigned m_bEnableMSAD :1;        // D3D11_1_SB_GLOBAL_FLAG_ENABLE_SHADER_EXTENSIONS
+    unsigned m_bAllResourcesBound :1; // D3D12_SB_GLOBAL_FLAG_ALL_RESOURCES_BOUND
+
+    unsigned m_bViewportAndRTArrayIndex :1;   // SHADER_FEATURE_VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER
+    unsigned m_bInnerCoverage :1;             // SHADER_FEATURE_INNER_COVERAGE
+    unsigned m_bStencilRef  :1;               // SHADER_FEATURE_STENCIL_REF
+    unsigned m_bTiledResources  :1;           // SHADER_FEATURE_TILED_RESOURCES
+    unsigned m_bUAVLoadAdditionalFormats :1;  // SHADER_FEATURE_TYPED_UAV_LOAD_ADDITIONAL_FORMATS
+    unsigned m_bLevel9ComparisonFiltering :1; // SHADER_FEATURE_LEVEL_9_COMPARISON_FILTERING
+                                              // SHADER_FEATURE_11_1_SHADER_EXTENSIONS shared with EnableMSAD
+    unsigned m_b64UAVs :1;                    // SHADER_FEATURE_64_UAVS
+    unsigned m_UAVsAtEveryStage :1;           // SHADER_FEATURE_UAVS_AT_EVERY_STAGE
+    unsigned m_bCSRawAndStructuredViaShader4X : 1; // SHADER_FEATURE_COMPUTE_SHADERS_PLUS_RAW_AND_STRUCTURED_BUFFERS_VIA_SHADER_4_X
+    
+    // SHADER_FEATURE_COMPUTE_SHADERS_PLUS_RAW_AND_STRUCTURED_BUFFERS_VIA_SHADER_4_X is specifically
+    // about shader model 4.x.
+
+    unsigned m_bROVS :1;              // SHADER_FEATURE_ROVS
+    unsigned m_bWaveOps :1;           // SHADER_FEATURE_WAVE_OPS
+    unsigned m_bInt64Ops :1;          // SHADER_FEATURE_INT64_OPS
+    unsigned m_bViewID : 1;           // SHADER_FEATURE_VIEWID
+    unsigned m_bBarycentrics : 1;     // SHADER_FEATURE_BARYCENTRICS
+
+    unsigned m_bUseNativeLowPrecision : 1;
+
+    unsigned m_align0 : 8;        // align to 32 bit.
+    uint32_t m_align1;            // align to 64 bit.
+  };
+
+
+
+}

+ 1 - 0
lib/HLSL/CMakeLists.txt

@@ -31,6 +31,7 @@ add_llvm_library(LLVMHLSL
   DxilRootSignature.cpp
   DxilSampler.cpp
   DxilSemantic.cpp
+  DxilShaderFlags.cpp
   DxilShaderAccessTracking.cpp
   DxilShaderModel.cpp
   DxilSignature.cpp

+ 33 - 27
lib/HLSL/DxilContainerAssembler.cpp

@@ -289,16 +289,16 @@ DxilPartWriter *hlsl::NewProgramSignatureWriter(const DxilModule &M, DXIL::Signa
   case DXIL::SignatureKind::Input:
     return new DxilProgramSignatureWriter(
         M.GetInputSignature(), M.GetTessellatorDomain(), true,
-        !M.m_ShaderFlags.GetUseNativeLowPrecision());
+        M.GetUseMinPrecision());
   case DXIL::SignatureKind::Output:
     return new DxilProgramSignatureWriter(
         M.GetOutputSignature(), M.GetTessellatorDomain(), false,
-        !M.m_ShaderFlags.GetUseNativeLowPrecision());
+        M.GetUseMinPrecision());
   case DXIL::SignatureKind::PatchConstant:
     return new DxilProgramSignatureWriter(
         M.GetPatchConstantSignature(), M.GetTessellatorDomain(),
         /*IsInput*/ M.GetShaderModel()->IsDS(),
-        /*UseMinPrecision*/!M.m_ShaderFlags.GetUseNativeLowPrecision());
+        /*UseMinPrecision*/M.GetUseMinPrecision());
   }
   return nullptr;
 }
@@ -727,7 +727,7 @@ private:
   }
 
 public:
-  ResourceTable(uint32_t version) : m_Version(version) {}
+  ResourceTable(uint32_t version) : m_Version(version), CBufferToOffset(), SamplerToOffset(), SRVToOffset(), UAVToOffset() {}
   void AddCBuffer(const DxilCBuffer *resource, uint32_t offset) {
     CBufferToOffset.emplace_back(
         std::pair<const DxilCBuffer *, uint32_t>(resource, offset));
@@ -814,13 +814,13 @@ public:
 
 class FunctionTable : public RDATTable {
 private:
-  std::unordered_map<const llvm::Function*, RuntimeDataFunctionInfo> FuncToInfo;
+  std::vector<std::pair<const llvm::Function *, RuntimeDataFunctionInfo>> FuncToInfo;
 public:
   FunctionTable(): FuncToInfo() {}
   uint32_t NumFunctions() const { return FuncToInfo.size(); }
   void AddFunction(const llvm::Function *func, uint32_t mangledOfffset,
                    uint32_t unmangledOffset, uint32_t shaderKind, uint32_t resourceIndex,
-                   uint32_t payloadSizeInBytes, uint32_t attrSizeInBytes) {
+                   uint32_t payloadSizeInBytes, uint32_t attrSizeInBytes, ShaderFlags flags) {
     RuntimeDataFunctionInfo info = {};
     info.Name = mangledOfffset;
     info.UnmangledName = unmangledOffset;
@@ -828,7 +828,10 @@ public:
     info.Resources = resourceIndex;
     info.PayloadSizeInBytes = payloadSizeInBytes;
     info.AttributeSizeInBytes = attrSizeInBytes;
-    FuncToInfo.insert({func, info});
+    uint64_t rawFlags = flags.GetShaderFlagsRaw();
+    info.FeatureInfo1 = rawFlags & 0xffffffff;
+    info.FeatureInfo2 = (rawFlags >> 32) & 0xffffffff;
+    FuncToInfo.push_back({ func, info });
   }
 
   uint32_t GetBlobSize() const { return NumFunctions() * sizeof(RuntimeDataFunctionInfo); }
@@ -905,7 +908,7 @@ private:
   const DxilModule &m_Module;
   SmallVector<char, 1024> m_RDATBuffer;
 
-  std::vector<std::unique_ptr<RDATTable>> tables;
+  std::vector<std::unique_ptr<RDATTable>> m_tables;
   std::map<llvm::Function *, std::vector<uint32_t>> m_FuncToResNameOffset;
 
   void UpdateFunctionToResourceInfo(const DxilResourceBase *resource, uint32_t offset) {
@@ -928,8 +931,8 @@ private:
   void UpdateResourceInfo(StringTable &stringTable) {
     // Try to allocate string table for resources. String table is a sequence
     // of strings delimited by \0
-    tables.emplace_back(std::make_unique<ResourceTable>(0));
-    ResourceTable &resourceTable = *(ResourceTable*)tables.back().get();
+    m_tables.emplace_back(std::make_unique<ResourceTable>(0));
+    ResourceTable &resourceTable = *(ResourceTable*)m_tables.back().get();
     uint32_t stringIndex;
     uint32_t resourceIndex = 0;
     for (auto &resource : m_Module.GetCBuffers()) {
@@ -957,10 +960,10 @@ private:
     // TODO: get a list of required features
     // TODO: get a list of valid shader flags
     // TODO: get a minimum shader version
-    tables.emplace_back(std::make_unique<FunctionTable>());
-    FunctionTable &functionTable = *(FunctionTable*)(tables.back().get());
-    tables.emplace_back(std::make_unique<IndexTable<uint32_t>>());
-    IndexTable<uint32_t> &indexTable = *(IndexTable<uint32_t>*)(tables.back().get());
+    m_tables.emplace_back(std::make_unique<FunctionTable>());
+    FunctionTable &functionTable = *(FunctionTable*)(m_tables.back().get());
+    m_tables.emplace_back(std::make_unique<IndexTable<uint32_t>>());
+    IndexTable<uint32_t> &indexTable = *(IndexTable<uint32_t>*)(m_tables.back().get());
     for (auto &function : m_Module.GetModule()->getFunctionList()) {
       if (!function.isDeclaration()) {
         StringRef mangled = function.getName();
@@ -988,27 +991,28 @@ private:
           }
           shaderKind = (uint32_t)props.shaderKind;
         }
+        ShaderFlags flags = ShaderFlags::CollectShaderFlags(&function, &m_Module);
         functionTable.AddFunction(&function, mangledIndex, unmangledIndex,
                                     shaderKind, resourceIndex,
-                                    payloadSizeInBytes, attrSizeInBytes);
+                                    payloadSizeInBytes, attrSizeInBytes, flags);
       }
     }
   }
 
 public:
   DxilRDATWriter(const DxilModule &module, uint32_t InfoVersion = 0)
-      : m_Module(module), m_RDATBuffer() {
+      : m_Module(module), m_RDATBuffer(), m_tables(), m_FuncToResNameOffset() {
     // It's important to keep the order of this update
-    tables.emplace_back(std::make_unique<StringTable>());
-    StringTable &stringTable = *(StringTable*)tables.back().get();
+    m_tables.emplace_back(std::make_unique<StringTable>());
+    StringTable &stringTable = *(StringTable*)m_tables.back().get();
     UpdateResourceInfo(stringTable);
     UpdateFunctionInfo(stringTable);
   }
 
   __override uint32_t size() const {
     // one variable to count the number of blobs and two blobs
-    uint32_t total = 4 + tables.size() * sizeof(RuntimeDataTableHeader);
-    for (auto &&table : tables)
+    uint32_t total = 4 + m_tables.size() * sizeof(RuntimeDataTableHeader);
+    for (auto &&table : m_tables)
       total += table->GetBlobSize();
     return total;
   }
@@ -1017,19 +1021,19 @@ public:
     m_RDATBuffer.resize(size());
     char *pCur = m_RDATBuffer.data();
     // write number of tables
-    uint32_t size = tables.size();
+    uint32_t size = m_tables.size();
     memcpy(pCur, &size, sizeof(uint32_t));
     pCur += sizeof(uint32_t);
     // write records
     uint32_t curTableOffset = size * sizeof(RuntimeDataTableHeader) + 4;
-    for (auto &&table : tables) {
+    for (auto &&table : m_tables) {
       RuntimeDataTableHeader record = { table->GetType(), table->GetBlobSize(), curTableOffset };
       memcpy(pCur, &record, sizeof(RuntimeDataTableHeader));
       pCur += sizeof(RuntimeDataTableHeader);
       curTableOffset += record.size;
     }
     // write tables
-    for (auto &&table : tables) {
+    for (auto &&table : m_tables) {
       table->write(pCur);
       pCur += table->GetBlobSize();
     }
@@ -1161,11 +1165,11 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
   DxilProgramSignatureWriter inputSigWriter(
       pModule->GetInputSignature(), pModule->GetTessellatorDomain(),
       /*IsInput*/ true,
-      /*UseMinPrecision*/ !pModule->m_ShaderFlags.GetUseNativeLowPrecision());
+      /*UseMinPrecision*/ pModule->GetUseMinPrecision());
   DxilProgramSignatureWriter outputSigWriter(
       pModule->GetOutputSignature(), pModule->GetTessellatorDomain(),
       /*IsInput*/ false,
-      /*UseMinPrecision*/ !pModule->m_ShaderFlags.GetUseNativeLowPrecision());
+      /*UseMinPrecision*/ pModule->GetUseMinPrecision());
   DxilContainerWriter_impl writer;
 
   // Write the feature part.
@@ -1185,7 +1189,7 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
   DxilProgramSignatureWriter patchConstantSigWriter(
       pModule->GetPatchConstantSignature(), pModule->GetTessellatorDomain(),
       /*IsInput*/ pModule->GetShaderModel()->IsDS(),
-      /*UseMinPrecision*/ !pModule->m_ShaderFlags.GetUseNativeLowPrecision());
+      /*UseMinPrecision*/ pModule->GetUseMinPrecision());
   if (pModule->GetPatchConstantSignature().GetElements().size()) {
     writer.AddPart(DFCC_PatchConstantSignature, patchConstantSigWriter.size(),
                    [&](AbstractMemoryStream *pStream) {
@@ -1196,7 +1200,9 @@ void hlsl::SerializeDxilContainerForModule(DxilModule *pModule,
   // Write the DxilPipelineStateValidation (PSV0) part.
   DxilRDATWriter RDATWriter(*pModule);
   DxilPSVWriter PSVWriter(*pModule);
-  if (pModule->GetShaderModel()->IsLib()) {
+  unsigned int major, minor;
+  pModule->GetDxilVersion(major, minor);
+  if (pModule->GetShaderModel()->IsLib() && (major >= 1 ||  minor == 1 && minor >= 3)) {
     writer.AddPart(DFCC_RuntimeData, RDATWriter.size(), [&](AbstractMemoryStream *pStream) {
         RDATWriter.write(pStream);
     });

+ 4 - 5
lib/HLSL/DxilGenerationPass.cpp

@@ -185,7 +185,7 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *
 
   // Shader properties.
   //bool m_bDisableOptimizations;
-  M.m_ShaderFlags.SetDisableOptimizations(H.GetHLOptions().bDisableOptimizations);
+  M.SetDisableOptimization(H.GetHLOptions().bDisableOptimizations);
   //bool m_bDisableMathRefactoring;
   //bool m_bEnableDoublePrecision;
   //bool m_bEnableDoubleExtensions;
@@ -196,7 +196,7 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *
   //bool m_bEnableMSAD;
   //M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
 
-  M.m_ShaderFlags.SetUseNativeLowPrecision(!H.GetHLOptions().bUseMinPrecision);
+  M.SetUseMinPrecision(H.GetHLOptions().bUseMinPrecision);
 
   if (FnProps)
     M.SetShaderProperties(FnProps);
@@ -212,7 +212,7 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *
   // Keep llvm used.
   M.EmitLLVMUsed();
 
-  M.m_ShaderFlags.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
+  M.SetAllResourcesBound(H.GetHLOptions().bAllResourcesBound);
 
   // Update Validator Version
   M.UpgradeToMinValidatorVersion();
@@ -1547,7 +1547,6 @@ public:
   bool runOnModule(Module &M) {
     unsigned major, minor;
     M.GetDxilModule().GetDxilVersion(major, minor);
-    DxilModule::ShaderFlags flag = M.GetDxilModule().m_ShaderFlags;
     if (major == 1 && minor < 2) {
       for (auto F = M.functions().begin(), E = M.functions().end(); F != E;) {
         Function *func = &*(F++);
@@ -1561,7 +1560,7 @@ public:
           }
         }
       }
-    } else if (!flag.GetUseNativeLowPrecision()) {
+    } else if (M.GetDxilModule().GetUseMinPrecision()) {
       for (auto F = M.functions().begin(), E = M.functions().end(); F != E;) {
         Function *func = &*(F++);
         if (func->hasName()) {

+ 41 - 315
lib/HLSL/DxilModule.cpp

@@ -83,7 +83,10 @@ DxilModule::DxilModule(Module *pModule)
 , m_TessellatorPartitioning(DXIL::TessellatorPartitioning::Undefined)
 , m_TessellatorOutputPrimitive(DXIL::TessellatorOutputPrimitive::Undefined)
 , m_MaxTessellationFactor(0.f)
-, m_RootSignature(nullptr) {
+, m_RootSignature(nullptr)
+, m_bUseMinPrecision(true) // use min precision by default
+, m_bDisableOptimizations(false)
+, m_bAllResourcesBound(false) {
   DXASSERT_NOMSG(m_pModule != nullptr);
 
   m_NumThreads[0] = m_NumThreads[1] = m_NumThreads[2] = 0;
@@ -101,35 +104,6 @@ DxilModule::DxilModule(Module *pModule)
 DxilModule::~DxilModule() {
 }
 
-DxilModule::ShaderFlags::ShaderFlags():
-  m_bDisableOptimizations(false)
-, m_bDisableMathRefactoring(false)
-, m_bEnableDoublePrecision(false)
-, m_bForceEarlyDepthStencil(false)
-, m_bEnableRawAndStructuredBuffers(false)
-, m_bLowPrecisionPresent(false)
-, m_bEnableDoubleExtensions(false)
-, m_bEnableMSAD(false)
-, m_bAllResourcesBound(false)
-, m_bViewportAndRTArrayIndex(false)
-, m_bInnerCoverage(false)
-, m_bStencilRef(false)
-, m_bTiledResources(false)
-, m_bUAVLoadAdditionalFormats(false)
-, m_bLevel9ComparisonFiltering(false)
-, m_bCSRawAndStructuredViaShader4X(false)
-, m_b64UAVs(false)
-, m_UAVsAtEveryStage(false)
-, m_bROVS(false)
-, m_bWaveOps(false)
-, m_bInt64Ops(false)
-, m_bViewID(false)
-, m_bBarycentrics(false)
-, m_bUseNativeLowPrecision(false)
-, m_align0(0)
-, m_align1(0)
-{}
-
 LLVMContext &DxilModule::GetCtx() const { return m_Ctx; }
 Module *DxilModule::GetModule() const { return m_pModule; }
 OP *DxilModule::GetOP() const { return m_pOP.get(); }
@@ -142,7 +116,7 @@ void DxilModule::SetShaderModel(const ShaderModel *pSM) {
   m_pSM->GetDxilVersion(m_DxilMajor, m_DxilMinor);
   m_pMDHelper->SetShaderModel(m_pSM);
   DXIL::ShaderKind shaderKind = pSM->GetKind();
-  m_EntrySignature = llvm::make_unique<DxilEntrySignature>(shaderKind, !m_ShaderFlags.GetUseNativeLowPrecision());
+  m_EntrySignature = llvm::make_unique<DxilEntrySignature>(shaderKind, GetUseMinPrecision());
   m_RootSignature.reset(new RootSignatureHandle());
 }
 
@@ -227,267 +201,16 @@ void DxilModule::SetPatchConstantFunction(llvm::Function *pFunc) {
   m_pPatchConstantFunc = pFunc;
 }
 
-unsigned DxilModule::ShaderFlags::GetGlobalFlags() const {
-  unsigned Flags = 0;
-  Flags |= m_bDisableOptimizations ? DXIL::kDisableOptimizations : 0;
-  Flags |= m_bDisableMathRefactoring ? DXIL::kDisableMathRefactoring : 0;
-  Flags |= m_bEnableDoublePrecision ? DXIL::kEnableDoublePrecision : 0;
-  Flags |= m_bForceEarlyDepthStencil ? DXIL::kForceEarlyDepthStencil : 0;
-  Flags |= m_bEnableRawAndStructuredBuffers ? DXIL::kEnableRawAndStructuredBuffers : 0;
-  Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision? DXIL::kEnableMinPrecision : 0;
-  Flags |= m_bEnableDoubleExtensions ? DXIL::kEnableDoubleExtensions : 0;
-  Flags |= m_bEnableMSAD ? DXIL::kEnableMSAD : 0;
-  Flags |= m_bAllResourcesBound ? DXIL::kAllResourcesBound : 0;
-  return Flags;
-}
-
-uint64_t DxilModule::ShaderFlags::GetFeatureInfo() const {
-  uint64_t Flags = 0;
-  Flags |= m_bEnableDoublePrecision ? hlsl::ShaderFeatureInfo_Doubles : 0;
-  Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision ? hlsl::ShaderFeatureInfo_MinimumPrecision: 0;
-  Flags |= m_bLowPrecisionPresent && m_bUseNativeLowPrecision ? hlsl::ShaderFeatureInfo_NativeLowPrecision : 0;
-  Flags |= m_bEnableDoubleExtensions ? hlsl::ShaderFeatureInfo_11_1_DoubleExtensions : 0;
-  Flags |= m_bWaveOps ? hlsl::ShaderFeatureInfo_WaveOps : 0;
-  Flags |= m_bInt64Ops ? hlsl::ShaderFeatureInfo_Int64Ops : 0;
-  Flags |= m_bROVS ? hlsl::ShaderFeatureInfo_ROVs : 0;
-  Flags |= m_bViewportAndRTArrayIndex ? hlsl::ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer : 0;
-  Flags |= m_bInnerCoverage ? hlsl::ShaderFeatureInfo_InnerCoverage : 0;
-  Flags |= m_bStencilRef ? hlsl::ShaderFeatureInfo_StencilRef : 0;
-  Flags |= m_bTiledResources ? hlsl::ShaderFeatureInfo_TiledResources : 0;
-  Flags |= m_bEnableMSAD ? hlsl::ShaderFeatureInfo_11_1_ShaderExtensions : 0;
-  Flags |= m_bCSRawAndStructuredViaShader4X ? hlsl::ShaderFeatureInfo_ComputeShadersPlusRawAndStructuredBuffersViaShader4X : 0;
-  Flags |= m_UAVsAtEveryStage ? hlsl::ShaderFeatureInfo_UAVsAtEveryStage : 0;
-  Flags |= m_b64UAVs ? hlsl::ShaderFeatureInfo_64UAVs : 0;
-  Flags |= m_bLevel9ComparisonFiltering ? hlsl::ShaderFeatureInfo_LEVEL9ComparisonFiltering : 0;
-  Flags |= m_bUAVLoadAdditionalFormats ? hlsl::ShaderFeatureInfo_TypedUAVLoadAdditionalFormats : 0;
-  Flags |= m_bViewID ? hlsl::ShaderFeatureInfo_ViewID : 0;
-  Flags |= m_bBarycentrics ? hlsl::ShaderFeatureInfo_Barycentrics : 0;
-
-  return Flags;
-}
-
-uint64_t DxilModule::ShaderFlags::GetShaderFlagsRaw() const {
-  union Cast {
-    Cast(const DxilModule::ShaderFlags &flags) {
-      shaderFlags = flags;
-    }
-    DxilModule::ShaderFlags shaderFlags;
-    uint64_t  rawData;
-  };
-  static_assert(sizeof(uint64_t) == sizeof(DxilModule::ShaderFlags),
-                "size must match to make sure no undefined bits when cast");
-  Cast rawCast(*this);
-  return rawCast.rawData;
-}
-void DxilModule::ShaderFlags::SetShaderFlagsRaw(uint64_t data) {
-  union Cast {
-    Cast(uint64_t data) {
-      rawData = data;
-    }
-    DxilModule::ShaderFlags shaderFlags;
-    uint64_t  rawData;
-  };
-
-  Cast rawCast(data);
-  *this = rawCast.shaderFlags;
-}
-
 unsigned DxilModule::GetGlobalFlags() const {
   unsigned Flags = m_ShaderFlags.GetGlobalFlags();
   return Flags;
 }
 
-static bool IsResourceSingleComponent(llvm::Type *Ty) {
-  if (llvm::ArrayType *arrType = llvm::dyn_cast<llvm::ArrayType>(Ty)) {
-    if (arrType->getArrayNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(arrType->getArrayElementType());
-  } else if (llvm::StructType *structType =
-                 llvm::dyn_cast<llvm::StructType>(Ty)) {
-    if (structType->getStructNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(structType->getStructElementType(0));
-  } else if (llvm::VectorType *vectorType =
-                 llvm::dyn_cast<llvm::VectorType>(Ty)) {
-    if (vectorType->getNumElements() > 1) {
-      return false;
-    }
-    return IsResourceSingleComponent(vectorType->getVectorElementType());
-  }
-  return true;
-}
-
-// Given a CreateHandle call, returns arbitrary ConstantInt rangeID
-// Note: HLSL is currently assuming that rangeID is a constant value, but this code is assuming
-// that it can be either constant, phi node, or select instruction
-static ConstantInt *GetArbitraryConstantRangeID(CallInst *handleCall) {
-  Value *rangeID =
-      handleCall->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
-  ConstantInt *ConstantRangeID = dyn_cast<ConstantInt>(rangeID);
-  while (ConstantRangeID == nullptr) {
-    if (ConstantInt *CI = dyn_cast<ConstantInt>(rangeID)) {
-      ConstantRangeID = CI;
-    } else if (PHINode *PN = dyn_cast<PHINode>(rangeID)) {
-      rangeID = PN->getIncomingValue(0);
-    } else if (SelectInst *SI = dyn_cast<SelectInst>(rangeID)) {
-      rangeID = SI->getTrueValue();
-    } else {
-      return nullptr;
-    }
-  }
-  return ConstantRangeID;
-}
-
-void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
-  bool hasDouble = false;
-  // ddiv dfma drcp d2i d2u i2d u2d.
-  // fma has dxil op. Others should check IR instruction div/cast.
-  bool hasDoubleExtension = false;
-  bool has64Int = false;
-  bool has16 = false;
-  bool hasWaveOps = false;
-  bool hasCheckAccessFully = false;
-  bool hasMSAD = false;
-  bool hasInnerCoverage = false;
-  bool hasViewID = false;
-  bool hasMulticomponentUAVLoads = false;
-  bool hasMulticomponentUAVLoadsBackCompat = false;
-
-  // Try to maintain compatibility with a v1.0 validator if that's what we have.
-  {
-    unsigned valMajor, valMinor;
-    GetValidatorVersion(valMajor, valMinor);
-    hasMulticomponentUAVLoadsBackCompat = valMajor <= 1 && valMinor == 0;
-  }
-
-  Type *int16Ty = Type::getInt16Ty(GetCtx());
-  Type *int64Ty = Type::getInt64Ty(GetCtx());
-
+void DxilModule::CollectShaderFlagsForModule(ShaderFlags &Flags) {
   for (Function &F : GetModule()->functions()) {
-    for (BasicBlock &BB : F.getBasicBlockList()) {
-      for (Instruction &I : BB.getInstList()) {
-        // Skip none dxil function call.
-        if (CallInst *CI = dyn_cast<CallInst>(&I)) {
-          if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
-            continue;
-        }
-        Type *Ty = I.getType();
-        bool isDouble = Ty->isDoubleTy();
-        bool isHalf = Ty->isHalfTy();
-        bool isInt16 = Ty == int16Ty;
-        bool isInt64 = Ty == int64Ty;
-        if (isa<ExtractElementInst>(&I) ||
-            isa<InsertElementInst>(&I))
-          continue;
-        for (Value *operand : I.operands()) {
-          Type *Ty = operand->getType();
-          isDouble |= Ty->isDoubleTy();
-          isHalf |= Ty->isHalfTy();
-          isInt16 |= Ty == int16Ty;
-          isInt64 |= Ty == int64Ty;
-        }
-
-        if (isDouble) {
-          hasDouble = true;
-          switch (I.getOpcode()) {
-          case Instruction::FDiv:
-          case Instruction::UIToFP:
-          case Instruction::SIToFP:
-          case Instruction::FPToUI:
-          case Instruction::FPToSI:
-            hasDoubleExtension = true;
-            break;
-          }
-        }
-        
-        has16 |= isHalf;
-        has16 |= isInt16;
-        has64Int |= isInt64;
-
-        if (CallInst *CI = dyn_cast<CallInst>(&I)) {
-          if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
-            continue;
-          Value *opcodeArg = CI->getArgOperand(DXIL::OperandIndex::kOpcodeIdx);
-          ConstantInt *opcodeConst = dyn_cast<ConstantInt>(opcodeArg);
-          DXASSERT(opcodeConst, "DXIL opcode arg must be immediate");
-          unsigned opcode = opcodeConst->getLimitedValue();
-          DXASSERT(opcode < static_cast<unsigned>(DXIL::OpCode::NumOpCodes),
-                   "invalid DXIL opcode");
-          DXIL::OpCode dxilOp = static_cast<DXIL::OpCode>(opcode);
-          if (hlsl::OP::IsDxilOpWave(dxilOp))
-            hasWaveOps = true;
-          switch (dxilOp) {
-          case DXIL::OpCode::CheckAccessFullyMapped:
-            hasCheckAccessFully = true;
-            break;
-          case DXIL::OpCode::Msad:
-            hasMSAD = true;
-            break;
-          case DXIL::OpCode::BufferLoad:
-          case DXIL::OpCode::TextureLoad: {
-            if (hasMulticomponentUAVLoads) continue;
-            // This is the old-style computation (overestimating requirements).
-            Value *resHandle = CI->getArgOperand(DXIL::OperandIndex::kBufferStoreHandleOpIdx);
-            CallInst *handleCall = cast<CallInst>(resHandle);
-
-            if (ConstantInt *resClassArg =
-              dyn_cast<ConstantInt>(handleCall->getArgOperand(
-                DXIL::OperandIndex::kCreateHandleResClassOpIdx))) {
-              DXIL::ResourceClass resClass = static_cast<DXIL::ResourceClass>(
-                resClassArg->getLimitedValue());
-              if (resClass == DXIL::ResourceClass::UAV) {
-                // Validator 1.0 assumes that all uav load is multi component load.
-                if (hasMulticomponentUAVLoadsBackCompat) {
-                  hasMulticomponentUAVLoads = true;
-                  continue;
-                }
-                else {
-                  ConstantInt *rangeID = GetArbitraryConstantRangeID(handleCall);
-                  if (rangeID) {
-                      DxilResource resource = GetUAV(rangeID->getLimitedValue());
-                      if ((resource.IsTypedBuffer() ||
-                           resource.IsAnyTexture()) &&
-                          !IsResourceSingleComponent(resource.GetRetType())) {
-                        hasMulticomponentUAVLoads = true;
-                      }
-                  }
-                }
-              }
-            }
-            else {
-                DXASSERT(false, "Resource class must be constant.");
-            }
-          } break;
-          case DXIL::OpCode::Fma:
-            hasDoubleExtension |= isDouble;
-            break;
-          case DXIL::OpCode::InnerCoverage:
-            hasInnerCoverage = true;
-            break;
-          case DXIL::OpCode::ViewID:
-            hasViewID = true;
-            break;
-          default:
-            // Normal opcodes.
-            break;
-          }
-        }
-      }
-    }
-
-  }
-
-  Flags.SetEnableDoublePrecision(hasDouble);
-  Flags.SetInt64Ops(has64Int);
-  Flags.SetLowPrecisionPresent(has16);
-  Flags.SetEnableDoubleExtensions(hasDoubleExtension);
-  Flags.SetWaveOps(hasWaveOps);
-  Flags.SetTiledResources(hasCheckAccessFully);
-  Flags.SetEnableMSAD(hasMSAD);
-  Flags.SetUAVLoadAdditionalFormats(hasMulticomponentUAVLoads);
-  Flags.SetViewID(hasViewID);
+    ShaderFlags funcFlags = ShaderFlags::CollectShaderFlags(&F, this);
+    Flags.CombineShaderFlags(funcFlags);
+  };
 
   const ShaderModel *SM = GetShaderModel();
   if (SM->IsPS()) {
@@ -497,12 +220,11 @@ void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
       if (E->GetKind() == Semantic::Kind::StencilRef) {
         hasStencilRef = true;
       } else if (E->GetKind() == Semantic::Kind::InnerCoverage) {
-        hasInnerCoverage = true;
+        Flags.SetInnerCoverage(true);
       }
     }
 
     Flags.SetStencilRef(hasStencilRef);
-    Flags.SetInnerCoverage(hasInnerCoverage);
   }
 
   bool checkInputRTArrayIndex =
@@ -580,31 +302,8 @@ void DxilModule::CollectShaderFlags(ShaderFlags &Flags) {
   Flags.SetCSRawAndStructuredViaShader4X(hasCSRawAndStructuredViaShader4X);
 }
 
-void DxilModule::CollectShaderFlags() {
-  CollectShaderFlags(m_ShaderFlags);
-}
-
-uint64_t DxilModule::ShaderFlags::GetShaderFlagsRawForCollection() {
-  // This should be all the flags that can be set by DxilModule::CollectShaderFlags.
-  ShaderFlags Flags;
-  Flags.SetEnableDoublePrecision(true);
-  Flags.SetInt64Ops(true);
-  Flags.SetLowPrecisionPresent(true);
-  Flags.SetEnableDoubleExtensions(true);
-  Flags.SetWaveOps(true);
-  Flags.SetTiledResources(true);
-  Flags.SetEnableMSAD(true);
-  Flags.SetUAVLoadAdditionalFormats(true);
-  Flags.SetStencilRef(true);
-  Flags.SetInnerCoverage(true);
-  Flags.SetViewportAndRTArrayIndex(true);
-  Flags.Set64UAVs(true);
-  Flags.SetUAVsAtEveryStage(true);
-  Flags.SetEnableRawAndStructuredBuffers(true);
-  Flags.SetCSRawAndStructuredViaShader4X(true);
-  Flags.SetViewID(true);
-  Flags.SetBarycentrics(true);
-  return Flags.GetShaderFlagsRaw();
+void DxilModule::CollectShaderFlagsForModule() {
+  CollectShaderFlagsForModule(m_ShaderFlags);
 }
 
 DXIL::InputPrimitive DxilModule::GetInputPrimitive() const {
@@ -692,6 +391,30 @@ unsigned DxilModule::GetActiveStreamMask() const {
   return m_ActiveStreamMask;
 }
 
+void DxilModule::SetUseMinPrecision(bool UseMinPrecision) {
+  m_bUseMinPrecision = UseMinPrecision;
+}
+
+bool DxilModule::GetUseMinPrecision() const {
+  return m_bUseMinPrecision;
+}
+
+void DxilModule::SetDisableOptimization(bool DisableOptimization) {
+  m_bDisableOptimizations = DisableOptimization;
+}
+
+bool DxilModule::GetDisableOptimization() const {
+  return m_bDisableOptimizations;
+}
+
+void DxilModule::SetAllResourcesBound(bool ResourcesBound) {
+  m_bAllResourcesBound = ResourcesBound;
+}
+
+bool DxilModule::GetAllResourcesBound() const {
+  return m_bAllResourcesBound;
+}
+
 unsigned DxilModule::GetInputControlPointCount() const {
   return m_InputControlPointCount;
 }
@@ -1051,7 +774,7 @@ const RootSignatureHandle &DxilModule::GetRootSignature() const {
   return *m_RootSignature;
 }
 
-bool DxilModule::HasDxilEntrySignature(llvm::Function *F) const {
+bool DxilModule::HasDxilEntrySignature(const llvm::Function *F) const {
   return m_DxilEntrySignatureMap.find(F) != m_DxilEntrySignatureMap.end();
 }
 DxilEntrySignature &DxilModule::GetDxilEntrySignature(const llvm::Function *F) {
@@ -1395,7 +1118,7 @@ void DxilModule::LoadDxilMetadata() {
       DXIL::ShaderKind shaderKind = m_DxilFunctionPropsMap[F]->shaderKind;
 
       std::unique_ptr<hlsl::DxilEntrySignature> Sig =
-          llvm::make_unique<hlsl::DxilEntrySignature>(shaderKind, !m_ShaderFlags.GetUseNativeLowPrecision());
+          llvm::make_unique<hlsl::DxilEntrySignature>(shaderKind, GetUseMinPrecision());
 
       m_pMDHelper->LoadDxilSignatures(pSig->getOperand(idx), *Sig);
 
@@ -1577,6 +1300,9 @@ void DxilModule::LoadDxilShaderProperties(const MDOperand &MDO) {
     switch (Tag) {
     case DxilMDHelper::kDxilShaderFlagsTag:
       m_ShaderFlags.SetShaderFlagsRaw(DxilMDHelper::ConstMDToUint64(MDO));
+      m_bUseMinPrecision = !m_ShaderFlags.GetUseNativeLowPrecision();
+      m_bDisableOptimizations = m_ShaderFlags.GetDisableOptimizations();
+      m_bAllResourcesBound = m_ShaderFlags.GetAllResourcesBound();
       break;
 
     case DxilMDHelper::kDxilNumThreadsTag: {

+ 2 - 2
lib/HLSL/DxilOperations.cpp

@@ -931,8 +931,8 @@ bool OP::GetOpCodeClass(const Function *F, OP::OpCodeClass &opClass) {
 bool OP::UseMinPrecision() {
   if (m_LowPrecisionMode == DXIL::LowPrecisionMode::Undefined) {
     if (&m_pModule->GetDxilModule()) {
-      m_LowPrecisionMode = m_pModule->GetDxilModule().m_ShaderFlags.GetUseNativeLowPrecision() ?
-        DXIL::LowPrecisionMode::UseNativeLowPrecision : DXIL::LowPrecisionMode::UseMinPrecision;
+      m_LowPrecisionMode = m_pModule->GetDxilModule().GetUseMinPrecision() ?
+        DXIL::LowPrecisionMode::UseMinPrecision : DXIL::LowPrecisionMode::UseNativeLowPrecision;
     }
     else if (&m_pModule->GetHLModule()) {
       m_LowPrecisionMode = m_pModule->GetHLModule().GetHLOptions().bUseMinPrecision ?

+ 1 - 1
lib/HLSL/DxilPreparePasses.cpp

@@ -272,7 +272,7 @@ public:
 
       // Skip shader flag for library.
       if (!IsLib) {
-        DM.CollectShaderFlags(); // Update flags to reflect any changes.
+        DM.CollectShaderFlagsForModule(); // Update flags to reflect any changes.
                                  // Update Validator Version
         DM.UpgradeToMinValidatorVersion();
       }

+ 380 - 0
lib/HLSL/DxilShaderFlags.cpp

@@ -0,0 +1,380 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// DxilShaderFlags.cpp                                                       //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/HLSL/DxilContainer.h"
+#include "dxc/HLSL/DxilModule.h"
+#include "dxc/HLSL/DxilShaderFlags.h"
+#include "dxc/HLSL/DxilOperations.h"
+#include "dxc/HLSL/DxilResource.h"
+#include "dxc/Support/Global.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/Support/Casting.h"
+
+using namespace hlsl;
+using namespace llvm;
+
+ShaderFlags::ShaderFlags():
+  m_bDisableOptimizations(false)
+, m_bDisableMathRefactoring(false)
+, m_bEnableDoublePrecision(false)
+, m_bForceEarlyDepthStencil(false)
+, m_bEnableRawAndStructuredBuffers(false)
+, m_bLowPrecisionPresent(false)
+, m_bEnableDoubleExtensions(false)
+, m_bEnableMSAD(false)
+, m_bAllResourcesBound(false)
+, m_bViewportAndRTArrayIndex(false)
+, m_bInnerCoverage(false)
+, m_bStencilRef(false)
+, m_bTiledResources(false)
+, m_bUAVLoadAdditionalFormats(false)
+, m_bLevel9ComparisonFiltering(false)
+, m_bCSRawAndStructuredViaShader4X(false)
+, m_b64UAVs(false)
+, m_UAVsAtEveryStage(false)
+, m_bROVS(false)
+, m_bWaveOps(false)
+, m_bInt64Ops(false)
+, m_bViewID(false)
+, m_bBarycentrics(false)
+, m_bUseNativeLowPrecision(false)
+, m_align0(0)
+, m_align1(0)
+{}
+
+uint64_t ShaderFlags::GetFeatureInfo() const {
+  uint64_t Flags = 0;
+  Flags |= m_bEnableDoublePrecision ? hlsl::ShaderFeatureInfo_Doubles : 0;
+  Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision ? hlsl::ShaderFeatureInfo_MinimumPrecision: 0;
+  Flags |= m_bLowPrecisionPresent && m_bUseNativeLowPrecision ? hlsl::ShaderFeatureInfo_NativeLowPrecision : 0;
+  Flags |= m_bEnableDoubleExtensions ? hlsl::ShaderFeatureInfo_11_1_DoubleExtensions : 0;
+  Flags |= m_bWaveOps ? hlsl::ShaderFeatureInfo_WaveOps : 0;
+  Flags |= m_bInt64Ops ? hlsl::ShaderFeatureInfo_Int64Ops : 0;
+  Flags |= m_bROVS ? hlsl::ShaderFeatureInfo_ROVs : 0;
+  Flags |= m_bViewportAndRTArrayIndex ? hlsl::ShaderFeatureInfo_ViewportAndRTArrayIndexFromAnyShaderFeedingRasterizer : 0;
+  Flags |= m_bInnerCoverage ? hlsl::ShaderFeatureInfo_InnerCoverage : 0;
+  Flags |= m_bStencilRef ? hlsl::ShaderFeatureInfo_StencilRef : 0;
+  Flags |= m_bTiledResources ? hlsl::ShaderFeatureInfo_TiledResources : 0;
+  Flags |= m_bEnableMSAD ? hlsl::ShaderFeatureInfo_11_1_ShaderExtensions : 0;
+  Flags |= m_bCSRawAndStructuredViaShader4X ? hlsl::ShaderFeatureInfo_ComputeShadersPlusRawAndStructuredBuffersViaShader4X : 0;
+  Flags |= m_UAVsAtEveryStage ? hlsl::ShaderFeatureInfo_UAVsAtEveryStage : 0;
+  Flags |= m_b64UAVs ? hlsl::ShaderFeatureInfo_64UAVs : 0;
+  Flags |= m_bLevel9ComparisonFiltering ? hlsl::ShaderFeatureInfo_LEVEL9ComparisonFiltering : 0;
+  Flags |= m_bUAVLoadAdditionalFormats ? hlsl::ShaderFeatureInfo_TypedUAVLoadAdditionalFormats : 0;
+  Flags |= m_bViewID ? hlsl::ShaderFeatureInfo_ViewID : 0;
+  Flags |= m_bBarycentrics ? hlsl::ShaderFeatureInfo_Barycentrics : 0;
+
+  return Flags;
+}
+
+uint64_t ShaderFlags::GetShaderFlagsRaw() const {
+  union Cast {
+    Cast(const ShaderFlags &flags) {
+      shaderFlags = flags;
+    }
+    ShaderFlags shaderFlags;
+    uint64_t  rawData;
+  };
+  static_assert(sizeof(uint64_t) == sizeof(ShaderFlags),
+                "size must match to make sure no undefined bits when cast");
+  Cast rawCast(*this);
+  return rawCast.rawData;
+}
+
+void ShaderFlags::SetShaderFlagsRaw(uint64_t data) {
+  union Cast {
+    Cast(uint64_t data) {
+      rawData = data;
+    }
+    ShaderFlags shaderFlags;
+    uint64_t  rawData;
+  };
+
+  Cast rawCast(data);
+  *this = rawCast.shaderFlags;
+}
+
+uint64_t ShaderFlags::GetShaderFlagsRawForCollection() {
+  // This should be all the flags that can be set by DxilModule::CollectShaderFlags.
+  ShaderFlags Flags;
+  Flags.SetEnableDoublePrecision(true);
+  Flags.SetInt64Ops(true);
+  Flags.SetLowPrecisionPresent(true);
+  Flags.SetEnableDoubleExtensions(true);
+  Flags.SetWaveOps(true);
+  Flags.SetTiledResources(true);
+  Flags.SetEnableMSAD(true);
+  Flags.SetUAVLoadAdditionalFormats(true);
+  Flags.SetStencilRef(true);
+  Flags.SetInnerCoverage(true);
+  Flags.SetViewportAndRTArrayIndex(true);
+  Flags.Set64UAVs(true);
+  Flags.SetUAVsAtEveryStage(true);
+  Flags.SetEnableRawAndStructuredBuffers(true);
+  Flags.SetCSRawAndStructuredViaShader4X(true);
+  Flags.SetViewID(true);
+  Flags.SetBarycentrics(true);
+  return Flags.GetShaderFlagsRaw();
+}
+
+unsigned ShaderFlags::GetGlobalFlags() const {
+  unsigned Flags = 0;
+  Flags |= m_bDisableOptimizations ? DXIL::kDisableOptimizations : 0;
+  Flags |= m_bDisableMathRefactoring ? DXIL::kDisableMathRefactoring : 0;
+  Flags |= m_bEnableDoublePrecision ? DXIL::kEnableDoublePrecision : 0;
+  Flags |= m_bForceEarlyDepthStencil ? DXIL::kForceEarlyDepthStencil : 0;
+  Flags |= m_bEnableRawAndStructuredBuffers ? DXIL::kEnableRawAndStructuredBuffers : 0;
+  Flags |= m_bLowPrecisionPresent && !m_bUseNativeLowPrecision? DXIL::kEnableMinPrecision : 0;
+  Flags |= m_bEnableDoubleExtensions ? DXIL::kEnableDoubleExtensions : 0;
+  Flags |= m_bEnableMSAD ? DXIL::kEnableMSAD : 0;
+  Flags |= m_bAllResourcesBound ? DXIL::kAllResourcesBound : 0;
+  return Flags;
+}
+
+// Given a CreateHandle call, returns arbitrary ConstantInt rangeID
+// Note: HLSL is currently assuming that rangeID is a constant value, but this code is assuming
+// that it can be either constant, phi node, or select instruction
+static ConstantInt *GetArbitraryConstantRangeID(CallInst *handleCall) {
+  Value *rangeID =
+      handleCall->getArgOperand(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
+  ConstantInt *ConstantRangeID = dyn_cast<ConstantInt>(rangeID);
+  while (ConstantRangeID == nullptr) {
+    if (ConstantInt *CI = dyn_cast<ConstantInt>(rangeID)) {
+      ConstantRangeID = CI;
+    } else if (PHINode *PN = dyn_cast<PHINode>(rangeID)) {
+      rangeID = PN->getIncomingValue(0);
+    } else if (SelectInst *SI = dyn_cast<SelectInst>(rangeID)) {
+      rangeID = SI->getTrueValue();
+    } else {
+      return nullptr;
+    }
+  }
+  return ConstantRangeID;
+}
+
+static bool IsResourceSingleComponent(llvm::Type *Ty) {
+  if (llvm::ArrayType *arrType = llvm::dyn_cast<llvm::ArrayType>(Ty)) {
+    if (arrType->getArrayNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(arrType->getArrayElementType());
+  } else if (llvm::StructType *structType =
+                 llvm::dyn_cast<llvm::StructType>(Ty)) {
+    if (structType->getStructNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(structType->getStructElementType(0));
+  } else if (llvm::VectorType *vectorType =
+                 llvm::dyn_cast<llvm::VectorType>(Ty)) {
+    if (vectorType->getNumElements() > 1) {
+      return false;
+    }
+    return IsResourceSingleComponent(vectorType->getVectorElementType());
+  }
+  return true;
+}
+
+// Given a handle type, find an arbitrary call instructions to create handle
+static CallInst *FindCallToCreateHandle(Value *handleType) {
+  Value *curVal = handleType;
+  CallInst *CI = dyn_cast<CallInst>(handleType);
+  while (CI == nullptr) {
+    if (PHINode *PN = dyn_cast<PHINode>(curVal)) {
+      curVal = PN->getIncomingValue(0);
+    }
+    else if (SelectInst *SI = dyn_cast<SelectInst>(curVal)) {
+      curVal = SI->getTrueValue();
+    }
+    else {
+      return nullptr;
+    }
+    CI = dyn_cast<CallInst>(curVal);
+  }
+  return CI;
+}
+
+ShaderFlags ShaderFlags::CollectShaderFlags(const Function *F,
+                                           const hlsl::DxilModule *M) {
+  ShaderFlags flag;
+  // Module level options
+  flag.SetUseNativeLowPrecision(!M->GetUseMinPrecision());
+  flag.SetDisableOptimizations(M->GetDisableOptimization());
+  flag.SetAllResourcesBound(M->GetAllResourcesBound());
+
+  bool hasDouble = false;
+  // ddiv dfma drcp d2i d2u i2d u2d.
+  // fma has dxil op. Others should check IR instruction div/cast.
+  bool hasDoubleExtension = false;
+  bool has64Int = false;
+  bool has16 = false;
+  bool hasWaveOps = false;
+  bool hasCheckAccessFully = false;
+  bool hasMSAD = false;
+  bool hasInnerCoverage = false;
+  bool hasViewID = false;
+  bool hasMulticomponentUAVLoads = false;
+  // Try to maintain compatibility with a v1.0 validator if that's what we have.
+  uint32_t valMajor, valMinor;
+  M->GetValidatorVersion(valMajor, valMinor);
+  bool hasMulticomponentUAVLoadsBackCompat = valMajor <= 1 && valMinor == 0;
+
+  Type *int16Ty = Type::getInt16Ty(F->getContext());
+  Type *int64Ty = Type::getInt64Ty(F->getContext());
+
+  for (const BasicBlock &BB : F->getBasicBlockList()) {
+    for (const Instruction &I : BB.getInstList()) {
+      // Skip none dxil function call.
+      if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
+        if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
+          continue;
+      }
+      Type *Ty = I.getType();
+      bool isDouble = Ty->isDoubleTy();
+      bool isHalf = Ty->isHalfTy();
+      bool isInt16 = Ty == int16Ty;
+      bool isInt64 = Ty == int64Ty;
+      if (isa<ExtractElementInst>(&I) ||
+        isa<InsertElementInst>(&I))
+        continue;
+      for (Value *operand : I.operands()) {
+        Type *Ty = operand->getType();
+        isDouble |= Ty->isDoubleTy();
+        isHalf |= Ty->isHalfTy();
+        isInt16 |= Ty == int16Ty;
+        isInt64 |= Ty == int64Ty;
+      }
+        if (isDouble) {
+          hasDouble = true;
+          switch (I.getOpcode()) {
+          case Instruction::FDiv:
+          case Instruction::UIToFP:
+          case Instruction::SIToFP:
+          case Instruction::FPToUI:
+          case Instruction::FPToSI:
+            hasDoubleExtension = true;
+            break;
+          }
+        }
+
+      has16 |= isHalf;
+      has16 |= isInt16;
+      has64Int |= isInt64;
+      if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
+        if (!OP::IsDxilOpFunc(CI->getCalledFunction()))
+          continue;
+        Value *opcodeArg = CI->getArgOperand(DXIL::OperandIndex::kOpcodeIdx);
+        ConstantInt *opcodeConst = dyn_cast<ConstantInt>(opcodeArg);
+        DXASSERT(opcodeConst, "DXIL opcode arg must be immediate");
+        unsigned opcode = opcodeConst->getLimitedValue();
+        DXASSERT(opcode < static_cast<unsigned>(DXIL::OpCode::NumOpCodes),
+          "invalid DXIL opcode");
+        DXIL::OpCode dxilOp = static_cast<DXIL::OpCode>(opcode);
+        if (hlsl::OP::IsDxilOpWave(dxilOp))
+          hasWaveOps = true;
+        switch (dxilOp) {
+        case DXIL::OpCode::CheckAccessFullyMapped:
+          hasCheckAccessFully = true;
+          break;
+        case DXIL::OpCode::Msad:
+          hasMSAD = true;
+          break;
+        case DXIL::OpCode::BufferLoad:
+        case DXIL::OpCode::TextureLoad: {
+          if (hasMulticomponentUAVLoads) continue;
+          // This is the old-style computation (overestimating requirements).
+          Value *resHandle = CI->getArgOperand(DXIL::OperandIndex::kBufferStoreHandleOpIdx);
+          CallInst *handleCall = FindCallToCreateHandle(resHandle);
+          // Check if this is a library handle or general create handle
+          if (handleCall) {
+            ConstantInt *HandleOpCodeConst = cast<ConstantInt>(
+                handleCall->getArgOperand(DXIL::OperandIndex::kOpcodeIdx));
+            DXIL::OpCode handleOp = static_cast<DXIL::OpCode>(HandleOpCodeConst->getLimitedValue());
+            if (handleOp == DXIL::OpCode::CreateHandle) {
+              if (ConstantInt *resClassArg =
+                dyn_cast<ConstantInt>(handleCall->getArgOperand(
+                  DXIL::OperandIndex::kCreateHandleResClassOpIdx))) {
+                DXIL::ResourceClass resClass = static_cast<DXIL::ResourceClass>(
+                  resClassArg->getLimitedValue());
+                if (resClass == DXIL::ResourceClass::UAV) {
+                  // Validator 1.0 assumes that all uav load is multi component load.
+                  if (hasMulticomponentUAVLoadsBackCompat) {
+                    hasMulticomponentUAVLoads = true;
+                    continue;
+                  }
+                  else {
+                    ConstantInt *rangeID = GetArbitraryConstantRangeID(handleCall);
+                    if (rangeID) {
+                      DxilResource resource = M->GetUAV(rangeID->getLimitedValue());
+                      if ((resource.IsTypedBuffer() ||
+                        resource.IsAnyTexture()) &&
+                        !IsResourceSingleComponent(resource.GetRetType())) {
+                        hasMulticomponentUAVLoads = true;
+                      }
+                    }
+                  }
+                }
+              }
+              else {
+                DXASSERT(false, "Resource class must be constant.");
+              }
+            }
+            else if (handleOp == DXIL::OpCode::CreateHandleFromResourceStructForLib) {
+              // If library handle, find DxilResource by checking the name
+              if (LoadInst *LI = dyn_cast<LoadInst>(handleCall->getArgOperand(
+                      DXIL::OperandIndex::
+                          kCreateHandleFromResourceStructForLibResOpIdx))) {
+                Value *resType = LI->getOperand(0);
+                for (auto &&res : M->GetUAVs()) {
+                  if (res->GetGlobalSymbol() == resType) {
+                    if ((res->IsTypedBuffer() || res->IsAnyTexture()) &&
+                        !IsResourceSingleComponent(res->GetRetType())) {
+                      hasMulticomponentUAVLoads = true;
+                    }
+                  }
+                }
+              }
+            }
+          }
+       } break;
+        case DXIL::OpCode::Fma:
+          hasDoubleExtension |= isDouble;
+          break;
+        case DXIL::OpCode::InnerCoverage:
+          hasInnerCoverage = true;
+          break;
+        case DXIL::OpCode::ViewID:
+          hasViewID = true;
+          break;
+        default:
+          // Normal opcodes.
+          break;
+        }
+      }
+    }
+  }
+    
+  flag.SetEnableDoublePrecision(hasDouble);
+  flag.SetInnerCoverage(hasInnerCoverage);
+  flag.SetInt64Ops(has64Int);
+  flag.SetLowPrecisionPresent(has16);
+  flag.SetEnableDoubleExtensions(hasDoubleExtension);
+  flag.SetWaveOps(hasWaveOps);
+  flag.SetTiledResources(hasCheckAccessFully);
+  flag.SetEnableMSAD(hasMSAD);
+  flag.SetUAVLoadAdditionalFormats(hasMulticomponentUAVLoads);
+  flag.SetViewID(hasViewID);
+
+  return flag;
+}
+
+void ShaderFlags::CombineShaderFlags(const ShaderFlags &other) {
+  SetShaderFlagsRaw(GetShaderFlagsRaw() | other.GetShaderFlagsRaw());
+}

+ 2 - 2
lib/HLSL/DxilTypeSystem.cpp

@@ -415,8 +415,8 @@ DXIL::SigPointKind SigPointFromInputQual(DxilParamInputQual Q, DXIL::ShaderKind
 bool DxilTypeSystem::UseMinPrecision() {
   if (m_LowPrecisionMode == DXIL::LowPrecisionMode::Undefined) {
     if (&m_pModule->GetDxilModule()) {
-      m_LowPrecisionMode = m_pModule->GetDxilModule().m_ShaderFlags.GetUseNativeLowPrecision() ?
-        DXIL::LowPrecisionMode::UseNativeLowPrecision : DXIL::LowPrecisionMode::UseMinPrecision;
+      m_LowPrecisionMode = m_pModule->GetDxilModule().GetUseMinPrecision() ?
+        DXIL::LowPrecisionMode::UseMinPrecision : DXIL::LowPrecisionMode::UseNativeLowPrecision;
     }
     else if (&m_pModule->GetHLModule()) {
       m_LowPrecisionMode = m_pModule->GetHLModule().GetHLOptions().bUseMinPrecision ?

+ 9 - 9
lib/HLSL/DxilValidation.cpp

@@ -2648,7 +2648,7 @@ static void ValidateFunctionBody(Function *F, ValidationContext &ValCtx) {
         bool IsMinPrecisionTy =
             (ValCtx.DL.getTypeStoreSize(FromTy) < 4 ||
              ValCtx.DL.getTypeStoreSize(ToTy) < 4) &&
-            !ValCtx.DxilMod.m_ShaderFlags.GetUseNativeLowPrecision();
+            ValCtx.DxilMod.GetUseMinPrecision();
         if (IsMinPrecisionTy) {
           ValCtx.EmitInstrError(Cast, ValidationRule::InstrMinPrecisonBitCast);
         }
@@ -3032,7 +3032,7 @@ static void ValidateResource(hlsl::DxilResource &res,
   if (res.IsStructuredBuffer()) {
     unsigned stride = res.GetElementStride();
     bool alignedTo4Bytes = (stride & 3) == 0;
-    if (!alignedTo4Bytes && !ValCtx.M.GetDxilModule().m_ShaderFlags.GetUseNativeLowPrecision()) {
+    if (!alignedTo4Bytes && ValCtx.M.GetDxilModule().GetUseMinPrecision()) {
       ValCtx.EmitResourceFormatError(
           &res, ValidationRule::MetaStructBufAlignment,
           {std::to_string(4), std::to_string(stride)});
@@ -3224,9 +3224,9 @@ static void ValidateResources(ValidationContext &ValCtx) {
 }
 
 static void ValidateShaderFlags(ValidationContext &ValCtx) {
-  DxilModule::ShaderFlags calcFlags;
-  ValCtx.DxilMod.CollectShaderFlags(calcFlags);
-  const uint64_t mask = DxilModule::ShaderFlags::GetShaderFlagsRawForCollection();
+  ShaderFlags calcFlags;
+  ValCtx.DxilMod.CollectShaderFlagsForModule(calcFlags);
+  const uint64_t mask = ShaderFlags::GetShaderFlagsRawForCollection();
   uint64_t declaredFlagsRaw = ValCtx.DxilMod.m_ShaderFlags.GetShaderFlagsRaw();
   uint64_t calcFlagsRaw = calcFlags.GetShaderFlagsRaw();
 
@@ -3608,10 +3608,10 @@ static void ValidateSignatureOverlap(
 static void ValidateSignature(ValidationContext &ValCtx, const DxilSignature &S,
                               unsigned maxScalars) {
   DxilSignatureAllocator allocator[DXIL::kNumOutputStreams] = {
-      {32, !ValCtx.DxilMod.m_ShaderFlags.GetUseNativeLowPrecision()},
-      {32, !ValCtx.DxilMod.m_ShaderFlags.GetUseNativeLowPrecision()},
-      {32, !ValCtx.DxilMod.m_ShaderFlags.GetUseNativeLowPrecision()},
-      {32, !ValCtx.DxilMod.m_ShaderFlags.GetUseNativeLowPrecision()}};
+      {32, ValCtx.DxilMod.GetUseMinPrecision()},
+      {32, ValCtx.DxilMod.GetUseMinPrecision()},
+      {32, ValCtx.DxilMod.GetUseMinPrecision()},
+      {32, ValCtx.DxilMod.GetUseMinPrecision()}};
   unordered_set<Semantic::Kind> semanticUsageSet[DXIL::kNumOutputStreams];
   StringMap<unordered_set<unsigned>> semanticIndexMap[DXIL::kNumOutputStreams];
   unordered_set<unsigned> clipcullRowSet[DXIL::kNumOutputStreams];

+ 96 - 1
tools/clang/unittests/HLSL/DxilContainerTest.cpp

@@ -33,6 +33,8 @@
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/HLSL/DxilContainer.h"
+#include "dxc/HLSL/DxilPipelineStateValidation.h"
+#include "dxc/HLSL/DxilShaderFlags.h"
 
 #include <fstream>
 #include <filesystem>
@@ -66,7 +68,10 @@ public:
     TEST_METHOD_PROPERTY(L"Priority", L"0")
   END_TEST_CLASS()
 
+  TEST_CLASS_SETUP(InitSupport);
+
   TEST_METHOD(CompileWhenDebugSourceThenSourceMatters)
+  TEST_METHOD(CompileWhenOkThenCheckRDAT)
   TEST_METHOD(CompileWhenOKThenIncludesFeatureInfo)
   TEST_METHOD(CompileWhenOKThenIncludesSignatures)
   TEST_METHOD(CompileWhenSigSquareThenIncludeSplit)
@@ -83,6 +88,7 @@ public:
   END_TEST_METHOD()
 
   dxc::DxcDllSupport m_dllSupport;
+  VersionSupportInfo m_ver;
 
   void CreateBlobPinned(_In_bytecount_(size) LPCVOID data, SIZE_T size,
                         UINT32 codePage, _Outptr_ IDxcBlobEncoding **ppBlob) {
@@ -522,6 +528,14 @@ public:
   }
 };
 
+bool DxilContainerTest::InitSupport() {
+  if (!m_dllSupport.IsEnabled()) {
+    VERIFY_SUCCEEDED(m_dllSupport.Initialize());
+    m_ver.Initialize(m_dllSupport);
+  }
+  return true;
+}
+
 TEST_F(DxilContainerTest, CompileWhenDebugSourceThenSourceMatters) {
   char program1[] = "float4 main() : SV_Target { return 0; }";
   char program2[] = "  float4 main() : SV_Target { return 0; }  ";
@@ -650,6 +664,87 @@ TEST_F(DxilContainerTest, CompileWhenSigSquareThenIncludeSplit) {
 #endif
 }
 
+TEST_F(DxilContainerTest, CompileWhenOkThenCheckRDAT) {
+  if (m_ver.SkipDxilVersion(1, 3)) return;
+  const char *shader = "float c_buf;"
+    "RWTexture1D<int4> tex : register(u5);"
+    "Texture1D<float4> tex2 : register(t0);"
+    "RWByteAddressBuffer b_buf;"
+    "float function0(min16float x) { "
+    "  return x + 1 + tex[0].x; }"
+    "float function1(float x, min12int i) {"
+    "  return x + c_buf + b_buf.Load(x) + tex2[i].x; }"
+                       "float function2(float x) {"
+                       "  return x; }";
+  CComPtr<IDxcCompiler> pCompiler;
+  CComPtr<IDxcBlobEncoding> pSource;
+  CComPtr<IDxcBlob> pProgram;
+  CComPtr<IDxcBlobEncoding> pDisassembly;
+  CComPtr<IDxcOperationResult> pResult;
+
+  VERIFY_SUCCEEDED(CreateCompiler(&pCompiler));
+  CreateBlobFromText(shader, &pSource);
+  VERIFY_SUCCEEDED(pCompiler->Compile(pSource, L"hlsl.hlsl", L"main",
+                                      L"lib_6_3", nullptr, 0, nullptr, 0,
+                                      nullptr, &pResult));
+  VERIFY_SUCCEEDED(pResult->GetResult(&pProgram));
+  CComPtr<IDxcContainerReflection> pReflection;
+  uint32_t partCount;
+  IFT(m_dllSupport.CreateInstance(CLSID_DxcContainerReflection, &pReflection));
+  IFT(pReflection->Load(pProgram));
+  IFT(pReflection->GetPartCount(&partCount));
+  bool blobFound = false;
+  for (uint32_t i = 0; i < partCount; ++i) {
+    uint32_t kind;
+    IFT(pReflection->GetPartKind(i, &kind));
+    if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_RuntimeData) {
+      blobFound = true;
+      using namespace hlsl::DXIL::PSV;
+      CComPtr<IDxcBlob> pBlob;
+      IFT(pReflection->GetPartContent(i, &pBlob));
+      DxilRuntimeData context;
+      context.InitFromRDAT((char *)pBlob->GetBufferPointer());
+      FunctionTableReader *funcTableReader = context.GetFunctionTableReader();
+      ResourceTableReader *resTableReader = context.GetResourceTableReader();
+      VERIFY_IS_TRUE(funcTableReader->GetNumFunctions() == 3);
+      std::string str("function");
+      for (uint32_t j = 0; j < funcTableReader->GetNumFunctions(); ++j) {
+        FunctionReader funcReader = funcTableReader->GetItem(j);
+        std::string funcName(funcReader.GetUnmangledName());
+        VERIFY_IS_TRUE(str.compare(funcName.substr(0,8)) == 0);
+        std::string cur_str = str;
+        cur_str.push_back('0' + j);
+        if (cur_str.compare("function0") == 0) {
+          VERIFY_IS_TRUE(funcReader.GetNumResources() == 1);
+          hlsl::ShaderFlags flag;
+          flag.SetUAVLoadAdditionalFormats(true);
+          flag.SetLowPrecisionPresent(true);
+          uint64_t rawFlag = flag.GetShaderFlagsRaw();
+          VERIFY_IS_TRUE(funcReader.GetFeatureFlag() == rawFlag);
+          ResourceReader resReader = funcReader.GetResource(0);
+          VERIFY_IS_TRUE(resReader.GetResourceKind() == PSVResourceKind::Texture1D);
+        }
+        else if (cur_str.compare("function1") == 0) {
+          hlsl::ShaderFlags flag;
+          flag.SetLowPrecisionPresent(true);
+          uint64_t rawFlag = flag.GetShaderFlagsRaw();
+          VERIFY_IS_TRUE(funcReader.GetFeatureFlag() == rawFlag);
+          VERIFY_IS_TRUE(funcReader.GetNumResources() == 3);
+        }
+        else if (cur_str.compare("function2") == 0) {
+          VERIFY_IS_TRUE((funcReader.GetFeatureFlag() & 0xffffffffffffffff) == 0);
+          VERIFY_IS_TRUE(funcReader.GetNumResources() == 0);
+        }
+        else {
+          IFTBOOLMSG(false, E_FAIL, "unknown function name");
+        }
+      }
+      VERIFY_IS_TRUE(resTableReader->GetNumResources() == 4);
+    }
+  }
+  IFTBOOLMSG(blobFound, E_FAIL, "failed to find RDAT blob after compiling");
+}
+
 TEST_F(DxilContainerTest, CompileWhenOKThenIncludesFeatureInfo) {
   CComPtr<IDxcCompiler> pCompiler;
   CComPtr<IDxcBlobEncoding> pSource;
@@ -995,4 +1090,4 @@ TEST_F(DxilContainerTest, DxilContainerUnitTest) {
   VERIFY_IS_NULL(hlsl::GetDxilProgramHeader(&header, hlsl::DxilFourCC::DFCC_DXIL));
   VERIFY_IS_NULL(hlsl::GetDxilPartByType(&header, hlsl::DxilFourCC::DFCC_DXIL));
 
-}
+}