瀏覽代碼

Initial implementation of ViewId state analysis. (#290)

yurido1 8 年之前
父節點
當前提交
df132d59b4

+ 180 - 0
include/dxc/HLSL/ComputeViewIdState.h

@@ -0,0 +1,180 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ComputeViewIdSets.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.                                     //
+//                                                                           //
+// Computes output registers dependent on ViewID.                            //
+// Computes sets of input registers on which output registers depend.        //
+// Computes which input/output shapes are dynamically indexed.               //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#include "llvm/Pass.h"
+#include "dxc/HLSL/ControlDependence.h"
+
+#include <memory>
+#include <bitset>
+#include <unordered_set>
+#include <unordered_map>
+#include <set>
+#include <map>
+
+namespace llvm {
+  class Module;
+  class Function;
+  class BasicBlock;
+  class Instruction;
+  class ReturnInst;
+  class Value;
+  class AnalysisUsage;
+  class CallGraph;
+  class CallGraphNode;
+  class ModulePass;
+  class raw_ostream;
+}
+
+namespace hlsl {
+
+class DxilModule;
+class DxilSignature;
+class DxilSignatureElement;
+
+class DxilViewIdState {
+  static const unsigned kNumComps = 4;
+  static const unsigned kMaxSigScalars = 32*4;
+public:
+  using OutputsDependentOnViewIdType = std::bitset<kMaxSigScalars>;
+  using InputsContributingToOutputType = std::map<unsigned, std::set<unsigned>>;
+
+  DxilViewIdState(DxilModule *pDxilModule);
+
+  unsigned getNumInputSigScalars() const;
+  unsigned getNumOutputSigScalars() const;
+  unsigned getNumPCSigScalars() const;
+  const OutputsDependentOnViewIdType &getOutputsDependentOnViewId() const;
+  const OutputsDependentOnViewIdType &getPCOutputsDependentOnViewId() const;
+  const InputsContributingToOutputType &getInputsContributingToOutputs() const;
+  const InputsContributingToOutputType &getInputsContributingToPCOutputs() const;
+  const InputsContributingToOutputType &getPCInputsContributingToOutputs() const;
+
+  void Compute();
+  const std::vector<unsigned> &GetSerialized();
+  void Deserialize(const unsigned *pData, unsigned DataSize);
+  void PrintSets(llvm::raw_ostream &OS);
+
+private:
+  DxilModule *m_pModule;
+
+  unsigned m_NumInputSigScalars  = 0;
+  unsigned m_NumOutputSigScalars = 0;
+  unsigned m_NumPCSigScalars     = 0;
+
+  // Dynamically indexed components of signature elements.
+  using DynamicallyIndexedElemsType = std::unordered_map<unsigned, unsigned>;
+  DynamicallyIndexedElemsType m_InpSigDynIdxElems;
+  DynamicallyIndexedElemsType m_OutSigDynIdxElems;
+  DynamicallyIndexedElemsType m_PCSigDynIdxElems;
+
+  // Set of scalar outputs dependent on ViewID.
+  OutputsDependentOnViewIdType m_OutputsDependentOnViewId;
+  OutputsDependentOnViewIdType m_PCOutputsDependentOnViewId;
+
+  // Set of scalar inputs contributing to computation of scalar outputs.
+  InputsContributingToOutputType m_InputsContributingToOutputs;
+  InputsContributingToOutputType m_InputsContributingToPCOutputs; // HS PC only.
+  InputsContributingToOutputType m_PCInputsContributingToOutputs; // DS only.
+
+  // Information per entry point.
+  using FunctionSetType = std::unordered_set<llvm::Function *>;
+  using InstructionSetType = std::unordered_set<llvm::Instruction *>;
+  struct EntryInfo {
+    llvm::Function *pEntryFunc = nullptr;
+    // Sets of functions that may be reachable from an entry.
+    FunctionSetType Functions;
+    // Outputs to analyze.
+    InstructionSetType Outputs;
+    // Contributing instructions per output.
+    std::unordered_map<unsigned, InstructionSetType> ContributingInstructions;
+
+    void Clear();
+  };
+
+  EntryInfo m_Entry;
+  EntryInfo m_PCEntry;
+
+  // Information per function.
+  using FunctionReturnSet = std::unordered_set<llvm::ReturnInst *>;
+  struct FuncInfo {
+    FunctionReturnSet Returns;
+    ControlDependence CtrlDep;
+    void Clear();
+  };
+
+  std::unordered_map<llvm::Function *, std::unique_ptr<FuncInfo>> m_FuncInfo;
+
+  // Cache of decls (global/alloca) reaching a pointer value.
+  using ValueSetType = std::unordered_set<llvm::Value *>;
+  std::unordered_map<llvm::Value *, ValueSetType> m_ReachingDeclsCache;
+  // Cache of stores for each decl.
+  std::unordered_map<llvm::Value *, ValueSetType> m_StoresPerDeclCache;
+
+  // Serialized form.
+  std::vector<unsigned> m_SerializedState;
+
+  void Clear();
+  void DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned &MaxSigLoc);
+  void ComputeReachableFunctionsRec(llvm::CallGraph &CG, llvm::CallGraphNode *pNode, FunctionSetType &FuncSet);
+  void AnalyzeFunctions(EntryInfo &Entry);
+  void CollectValuesContributingToOutputs(EntryInfo &Entry);
+  void CollectValuesContributingToOutputRec(llvm::Value *pContributingValue,
+                                            InstructionSetType &ContributingInstructions);
+  const ValueSetType &CollectReachingDecls(llvm::Value *pValue);
+  void CollectReachingDeclsRec(llvm::Value *pValue, ValueSetType &ReachingDecls, ValueSetType &Visited);
+  const ValueSetType &CollectStores(llvm::Value *pValue);
+  void CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited);
+  void UpdateDynamicIndexUsageState() const;
+  void CreateViewIdSets(EntryInfo &Entry, OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                        InputsContributingToOutputType &InputsContributingToOutputs, bool bPC);
+
+  void UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig, const DynamicallyIndexedElemsType &DynIdxElems) const;
+  void Serialize1(unsigned NumInputs, unsigned NumOutputs,
+                  const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                  const InputsContributingToOutputType &InputsContributingToOutputs,
+                  unsigned *&pData);
+  unsigned Deserialize1(const unsigned *pData, unsigned DataSize,
+                        unsigned &NumInputs, unsigned &NumOutputs,
+                        OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                        InputsContributingToOutputType &InputsContributingToOutputs);
+  unsigned GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const;
+
+  void PrintOutputsDependentOnViewId(llvm::raw_ostream &OS,
+                                     llvm::StringRef SetName, unsigned NumOutputs,
+                                     const OutputsDependentOnViewIdType &OutputsDependentOnViewId);
+  void PrintInputsContributingToOutputs(llvm::raw_ostream &OS,
+                                        llvm::StringRef InputSetName, llvm::StringRef OutputSetName,
+                                        const InputsContributingToOutputType &InputsContributingToOutputs);
+};
+
+} // end of hlsl namespace
+
+
+namespace llvm {
+
+class ComputeViewIdState : public ModulePass {
+public:
+  static char ID; // Pass ID, replacement for typeid
+
+  ComputeViewIdState();
+
+  bool runOnModule(Module &M) override;
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+};
+
+void initializeComputeViewIdStatePass(llvm::PassRegistry &);
+llvm::ModulePass *createComputeViewIdStatePass();
+
+} // end of llvm namespace

+ 51 - 0
include/dxc/HLSL/ControlDependence.h

@@ -0,0 +1,51 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ComputeViewIdSets.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.                                     //
+//                                                                           //
+// Computes control dependence relation for a function.                      //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Dominators.h"
+
+#include <unordered_set>
+#include <unordered_map>
+
+namespace llvm {
+  class Function;
+  class raw_ostream;
+}
+
+
+namespace hlsl {
+
+using BasicBlockSet = std::unordered_set<llvm::BasicBlock *>;
+using PostDomRelationType = llvm::DominatorTreeBase<llvm::BasicBlock>;
+
+class ControlDependence {
+public:
+  void Compute(llvm::Function *F, PostDomRelationType &PostDomRel);
+  void Clear();
+  const BasicBlockSet &GetCDBlocks(llvm::BasicBlock *pBB) const;
+  void print(llvm::raw_ostream &OS);
+  void dump();
+
+private:
+  using BasicBlockVector = std::vector<llvm::BasicBlock *>;
+  using ControlDependenceType = std::unordered_map<llvm::BasicBlock *, BasicBlockSet>;
+
+  llvm::Function *m_pFunc;
+  ControlDependenceType m_ControlDependence;
+  BasicBlockSet m_EmptyBBSet;
+
+  llvm::BasicBlock *GetIPostDom(PostDomRelationType &PostDomRel, llvm::BasicBlock *pBB);
+  void ComputeRevTopOrderRec(PostDomRelationType &PostDomRel, llvm::BasicBlock *pBB,
+                             BasicBlockVector &RevTopOrder, BasicBlockSet &VisitedBBs);
+};
+
+} // end of hlsl namespace

+ 11 - 2
include/dxc/HLSL/DxilMetadataHelper.h

@@ -46,6 +46,7 @@ class DxilFieldAnnotation;
 class DxilFunctionAnnotation;
 class DxilParameterAnnotation;
 class RootSignatureHandle;
+class DxilViewIdState;
 
 
 /// Use this class to manipulate DXIL-spcific metadata.
@@ -75,6 +76,9 @@ public:
   // Root Signature, for intermediate use, not valid in final DXIL module.
   static const char kDxilRootSignatureMDName[];
 
+  // ViewId state.
+  static const char kDxilViewIdStateMDName[];
+
   static const unsigned kDxilEntryPointNumFields  = 5;
   static const unsigned kDxilEntryPointFunction   = 0;  // Entry point function symbol.
   static const unsigned kDxilEntryPointName       = 1;  // Entry point unmangled name.
@@ -103,8 +107,9 @@ public:
   static const unsigned kDxilSignatureElementNameValueList  = 10;  // Name-value list for extended properties.
 
   // Signature Element Extended Properties.
-  static const unsigned kDxilSignatureElementOutputStreamTag = 0;
-  static const unsigned kHLSignatureElementGlobalSymbolTag   = 1;
+  static const unsigned kDxilSignatureElementOutputStreamTag    = 0;
+  static const unsigned kHLSignatureElementGlobalSymbolTag      = 1;
+  static const unsigned kDxilSignatureElementDynIdxCompMaskTag  = 2;
 
   // Resources.
   static const char kDxilResourcesMDName[];
@@ -309,6 +314,10 @@ public:
   llvm::Metadata *EmitDxilParamAnnotation(const DxilParameterAnnotation &PA);
   void LoadDxilParamAnnotation(const llvm::MDOperand &MDO, DxilParameterAnnotation &PA);
 
+  // ViewId state.
+  void EmitDxilViewIdState(DxilViewIdState &ViewIdState);
+  void LoadDxilViewIdState(DxilViewIdState &ViewIdState);
+
   // Control flow hints.
   static llvm::MDNode *EmitControlFlowHints(llvm::LLVMContext &Ctx, std::vector<DXIL::ControlFlowHint> &hints);
 

+ 7 - 0
include/dxc/HLSL/DxilModule.h

@@ -18,6 +18,7 @@
 #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>
@@ -113,6 +114,9 @@ public:
   void EmitLLVMUsed();
   std::vector<llvm::GlobalVariable* > &GetLLVMUsed();
 
+  // ViewId state.
+  DxilViewIdState &GetViewIdState();
+
   // DXIL metadata manipulation.
   /// Serialize DXIL in-memory form to metadata form.
   void EmitDxilMetadata();
@@ -291,6 +295,9 @@ private:
   // Type annotations.
   std::unique_ptr<DxilTypeSystem> m_pTypeSystem;
 
+  // ViewId state.
+  std::unique_ptr<DxilViewIdState> m_pViewIdState;
+
   // DXIL metadata serialization/deserialization.
   llvm::MDTuple *EmitDxilResources();
   void LoadDxilResources(const llvm::MDOperand &MDO);

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

@@ -46,6 +46,7 @@ public:
   void GetDxilVersion(unsigned &DxilMajor, unsigned &DxilMinor) const;
   bool IsSM50Plus() const   { return m_Major >= 5; }
   bool IsSM51Plus() const   { return m_Major > 5 || (m_Major == 5 && m_Minor >= 1); }
+  bool IsSM60Plus() const   { return m_Major >= 6; }
   bool IsSM61Plus() const   { return m_Major > 6 || (m_Major == 6 && m_Minor >= 1); }
   const char *GetName() const { return m_pszName; }
   std::string GetKindName() const;

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

@@ -86,6 +86,8 @@ public:
   void SetCompType(CompType CT);
   uint8_t GetColsAsMask() const;
   bool IsAllocated() const;
+  unsigned GetDynIdxCompMask() const;
+  void SetDynIdxCompMask(unsigned DynIdxCompMask);
 
 protected:
   DXIL::SigPointKind m_sigPointKind;
@@ -102,6 +104,7 @@ protected:
   int m_StartRow;
   int m_StartCol;
   unsigned m_OutputStream;
+  unsigned m_DynIdxCompMask;
 };
 
 } // namespace hlsl

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

@@ -98,3 +98,6 @@
 
 // 0X80AA0017 - DXIL optimization pass failed.
 #define DXC_E_OPTIMIZATION_FAILED                     DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR,FACILITY_DXC,(0x0017))
+
+// 0X80AA0018 - General internal error.
+#define DXC_E_GENERAL_INTERNAL_ERROR                  DXC_MAKE_HRESULT(DXC_SEVERITY_ERROR,FACILITY_DXC,(0x0018))

+ 2 - 0
lib/HLSL/CMakeLists.txt

@@ -1,6 +1,8 @@
 # Copyright (C) Microsoft Corporation. All rights reserved.
 # This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
 add_llvm_library(LLVMHLSL
+  ComputeViewIdState.cpp
+  ControlDependence.cpp
   DxilCBuffer.cpp
   DxilCompType.cpp
   DxilCondenseResources.cpp

+ 821 - 0
lib/HLSL/ComputeViewIdState.cpp

@@ -0,0 +1,821 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ViewIdAnalysis.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/ComputeViewIdState.h"
+#include "dxc/Support/Global.h"
+#include "dxc/HLSL/DxilModule.h"
+#include "dxc/HLSL/DxilOperations.h"
+#include "dxc/HLSL/DxilInstructions.h"
+
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/Pass.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/Analysis/CallGraph.h"
+
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::legacy;
+using namespace hlsl;
+using llvm::legacy::PassManager;
+using llvm::legacy::FunctionPassManager;
+using std::vector;
+
+#define DXILVIEWID_DBG   1
+
+#define DEBUG_TYPE "viewid"
+
+
+DxilViewIdState::DxilViewIdState(DxilModule *pDxilModule) : m_pModule(pDxilModule) {}
+unsigned DxilViewIdState::getNumInputSigScalars() const   { return m_NumInputSigScalars; }
+unsigned DxilViewIdState::getNumOutputSigScalars() const  { return m_NumOutputSigScalars; }
+unsigned DxilViewIdState::getNumPCSigScalars() const      { return m_NumPCSigScalars; }
+const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getOutputsDependentOnViewId() const      { return m_OutputsDependentOnViewId; }
+const DxilViewIdState::OutputsDependentOnViewIdType   &DxilViewIdState::getPCOutputsDependentOnViewId() const    { return m_PCOutputsDependentOnViewId; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToOutputs() const   { return m_InputsContributingToOutputs; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getInputsContributingToPCOutputs() const { return m_InputsContributingToPCOutputs; }
+const DxilViewIdState::InputsContributingToOutputType &DxilViewIdState::getPCInputsContributingToOutputs() const { return m_PCInputsContributingToOutputs; }
+
+void DxilViewIdState::Compute() {
+  Clear();
+
+  // 1. Traverse signature MD to determine max packed location.
+  DetermineMaxPackedLocation(m_pModule->GetInputSignature(), m_NumInputSigScalars);
+  DetermineMaxPackedLocation(m_pModule->GetOutputSignature(), m_NumOutputSigScalars);
+  DetermineMaxPackedLocation(m_pModule->GetPatchConstantSignature(), m_NumPCSigScalars);
+
+  // 2. Collect sets of functions reachable from main and pc entries.
+  CallGraphAnalysis CGA;
+  CallGraph CG = CGA.run(m_pModule->GetModule());
+  m_Entry.pEntryFunc = m_pModule->GetEntryFunction();
+  m_PCEntry.pEntryFunc = m_pModule->GetPatchConstantFunction();
+  ComputeReachableFunctionsRec(CG, CG[m_Entry.pEntryFunc], m_Entry.Functions);
+  if (m_PCEntry.pEntryFunc) {
+    ComputeReachableFunctionsRec(CG, CG[m_PCEntry.pEntryFunc], m_PCEntry.Functions);
+  }
+
+  // 3. Determine shape components that are dynamically accesses and collect all sig outputs.
+  AnalyzeFunctions(m_Entry);
+  AnalyzeFunctions(m_PCEntry);
+
+  // 4. Collect sets of values contributing to outputs.
+  CollectValuesContributingToOutputs(m_Entry);
+  CollectValuesContributingToOutputs(m_PCEntry);
+
+  // 5. Construct dependency sets.
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+  CreateViewIdSets(m_Entry, m_OutputsDependentOnViewId, m_InputsContributingToOutputs, false);
+  if (pSM->IsHS()) {
+    CreateViewIdSets(m_PCEntry, m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs, true);
+  } else if (pSM->IsDS()) {
+    CreateViewIdSets(m_PCEntry, m_OutputsDependentOnViewId, m_PCInputsContributingToOutputs, true);
+  }
+
+  // 6. Update dynamically indexed input/output component masks.
+  UpdateDynamicIndexUsageState();
+
+#if DXILVIEWID_DBG
+  PrintSets(dbgs());
+#endif
+}
+
+void DxilViewIdState::PrintSets(llvm::raw_ostream &OS) {
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+  OS << "ViewId state: \n";
+  OS << "Number of inputs: " << m_NumInputSigScalars  << 
+               ", outputs: " << m_NumOutputSigScalars << 
+            ", patchconst: " << m_NumPCSigScalars     << "\n";
+  PrintOutputsDependentOnViewId(OS, "Outputs", m_NumOutputSigScalars, m_OutputsDependentOnViewId);
+  if (pSM->IsHS()) {
+    PrintOutputsDependentOnViewId(OS, "PCOutputs", m_NumPCSigScalars, m_PCOutputsDependentOnViewId);
+  }
+
+  PrintInputsContributingToOutputs(OS, "Inputs", "Outputs", m_InputsContributingToOutputs);
+  if (pSM->IsHS()) {
+    PrintInputsContributingToOutputs(OS, "Inputs", "PCOutputs", m_InputsContributingToPCOutputs);
+  } else if (pSM->IsDS()) {
+    PrintInputsContributingToOutputs(OS, "PCInputs", "Outputs", m_PCInputsContributingToOutputs);
+  }
+  OS << "\n";
+}
+
+void DxilViewIdState::PrintOutputsDependentOnViewId(llvm::raw_ostream &OS,
+                                                    llvm::StringRef SetName,
+                                                    unsigned NumOutputs,
+                                                    const OutputsDependentOnViewIdType &OutputsDependentOnViewId) {
+  OS << SetName << " dependent on ViewId: { ";
+  bool bFirst = true;
+  for (unsigned i = 0; i < NumOutputs; i++) {
+    if (OutputsDependentOnViewId[i]) {
+      if (!bFirst) OS << ", ";
+      OS << i;
+      bFirst = false;
+    }
+  }
+  OS << " }\n";
+}
+
+void DxilViewIdState::PrintInputsContributingToOutputs(llvm::raw_ostream &OS,
+                                                       llvm::StringRef InputSetName,
+                                                       llvm::StringRef OutputSetName,
+                                                       const InputsContributingToOutputType &InputsContributingToOutputs) {
+  OS << InputSetName << " contributing to computation of " << OutputSetName << ":\n";
+  for (auto &it : InputsContributingToOutputs) {
+    unsigned outIdx = it.first;
+    auto &Inputs = it.second;
+    OS << "output " << outIdx << " depends on inputs: { ";
+    bool bFirst = true;
+    for (unsigned i : Inputs) {
+      if (!bFirst) OS << ", ";
+      OS << i;
+      bFirst = false;
+    }
+    OS << " }\n";
+  }
+}
+
+void DxilViewIdState::Clear() {
+  m_NumInputSigScalars  = 0;
+  m_NumOutputSigScalars = 0;
+  m_NumPCSigScalars     = 0;
+  m_InpSigDynIdxElems.clear();
+  m_OutSigDynIdxElems.clear();
+  m_PCSigDynIdxElems.clear();
+  m_OutputsDependentOnViewId.reset();
+  m_PCOutputsDependentOnViewId.reset();
+  m_InputsContributingToOutputs.clear();
+  m_InputsContributingToPCOutputs.clear();
+  m_PCInputsContributingToOutputs.clear();
+  m_Entry.Clear();
+  m_PCEntry.Clear();
+  m_FuncInfo.clear();
+  m_ReachingDeclsCache.clear();
+  m_SerializedState.clear();
+}
+
+void DxilViewIdState::EntryInfo::Clear() {
+  pEntryFunc = nullptr;
+  Functions.clear();
+  Outputs.clear();
+  ContributingInstructions.clear();
+}
+
+void DxilViewIdState::FuncInfo::Clear() {
+  Returns.clear();
+  CtrlDep.Clear();
+}
+
+void DxilViewIdState::DetermineMaxPackedLocation(DxilSignature &DxilSig, unsigned &MaxSigLoc) {
+  if (&DxilSig == nullptr) return;
+
+  MaxSigLoc = 0;
+  for (auto &E : DxilSig.GetElements()) {
+    if (E->GetStartRow() == Semantic::kUndefinedRow) continue;
+
+    unsigned endLoc = GetLinearIndex(*E, E->GetRows() - 1, E->GetCols() - 1);
+    MaxSigLoc = std::max(MaxSigLoc, endLoc + 1);
+    E->GetCols();
+  }
+}
+
+void DxilViewIdState::ComputeReachableFunctionsRec(CallGraph &CG, CallGraphNode *pNode, FunctionSetType &FuncSet) {
+  Function *F = pNode->getFunction();
+  // Accumulate only functions with bodies.
+  if (F->empty()) return;
+  auto itIns = FuncSet.emplace(F);
+  DXASSERT_NOMSG(itIns.second);
+  for (auto it = pNode->begin(), itEnd = pNode->end(); it != itEnd; ++it) {
+    CallGraphNode *pSuccNode = it->second;
+    ComputeReachableFunctionsRec(CG, pSuccNode, FuncSet);
+  }
+}
+
+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;
+}
+
+void DxilViewIdState::AnalyzeFunctions(EntryInfo &Entry) {
+  for (auto *F : Entry.Functions) {
+    DXASSERT_NOMSG(!F->empty());
+
+    auto itFI = m_FuncInfo.find(F);
+    FuncInfo *pFuncInfo = nullptr;
+    if (itFI != m_FuncInfo.end()) {
+      pFuncInfo = itFI->second.get();
+    } else {
+      m_FuncInfo[F] = make_unique<FuncInfo>();
+      pFuncInfo = m_FuncInfo[F].get();
+    }
+
+    for (auto itBB = F->begin(), endBB = F->end(); itBB != endBB; ++itBB) {
+      BasicBlock *BB = itBB;
+
+      for (auto itInst = BB->begin(), endInst = BB->end(); itInst != endInst; ++itInst) {
+        if (ReturnInst *RI = dyn_cast<ReturnInst>(itInst)) {
+          pFuncInfo->Returns.emplace(RI);
+          continue;
+        }
+
+        CallInst *CI = dyn_cast<CallInst>(itInst);
+        if (!CI) continue;
+
+        DynamicallyIndexedElemsType *pDynIdxElems = nullptr;
+        int row = Semantic::kUndefinedRow;
+        unsigned id, col;
+        if (DxilInst_LoadInput LI = DxilInst_LoadInput(CI)) {
+          pDynIdxElems = &m_InpSigDynIdxElems;
+          IFTBOOL(GetUnsignedVal(LI.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
+          GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&row);
+          IFTBOOL(GetUnsignedVal(LI.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
+        } else if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
+          pDynIdxElems = &m_OutSigDynIdxElems;
+          IFTBOOL(GetUnsignedVal(SO.get_outputtSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
+          GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&row);
+          IFTBOOL(GetUnsignedVal(SO.get_colIndex(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
+          Entry.Outputs.emplace(CI);
+        } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(CI)) {
+          if (m_pModule->GetShaderModel()->IsDS()) {
+            pDynIdxElems = &m_PCSigDynIdxElems;
+            IFTBOOL(GetUnsignedVal(LPC.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
+            GetUnsignedVal(LPC.get_row(), (uint32_t*)&row);
+            IFTBOOL(GetUnsignedVal(LPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
+          } else {
+            // Do nothing. This is an internal helper function for DXBC-2-DXIL converter.
+            DXASSERT_NOMSG(m_pModule->GetShaderModel()->IsHS());
+          }
+        } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
+          pDynIdxElems = &m_PCSigDynIdxElems;
+          IFTBOOL(GetUnsignedVal(SPC.get_outputSigID(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
+          GetUnsignedVal(SPC.get_row(), (uint32_t*)&row);
+          IFTBOOL(GetUnsignedVal(SPC.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
+          Entry.Outputs.emplace(CI);
+        } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(CI)) {
+          if (m_pModule->GetShaderModel()->IsDS()) {
+            pDynIdxElems = &m_InpSigDynIdxElems;
+            IFTBOOL(GetUnsignedVal(LOCP.get_inputSigId(), &id), DXC_E_GENERAL_INTERNAL_ERROR);
+            GetUnsignedVal(LOCP.get_row(), (uint32_t*)&row);
+            IFTBOOL(GetUnsignedVal(LOCP.get_col(), &col), DXC_E_GENERAL_INTERNAL_ERROR);
+          } else if (m_pModule->GetShaderModel()->IsHS()) {
+            // Do nothings, as the information has been captured by the output signature of CP entry.
+          } else {
+            DXASSERT_NOMSG(false);
+          }
+        } else {
+          continue;
+        }
+
+        // Record dynamic index usage.
+        if (pDynIdxElems && row == Semantic::kUndefinedRow) {
+          (*pDynIdxElems)[id] |= (1 << col);
+        }
+      }
+    }
+
+    // Compute postdominator relation.
+    DominatorTreeBase<BasicBlock> PDR(true);
+    PDR.recalculate(*F);
+#if DXILVIEWID_DBG
+    PDR.print(dbgs());
+#endif
+    // Compute control dependence.
+    pFuncInfo->CtrlDep.Compute(F, PDR);
+#if DXILVIEWID_DBG
+    pFuncInfo->CtrlDep.print(dbgs());
+#endif
+  }
+}
+
+void DxilViewIdState::CollectValuesContributingToOutputs(EntryInfo &Entry) {
+  for (auto *CI : Entry.Outputs) {  // CI = call instruction
+    DxilSignature *pDxilSig = nullptr;
+    Value *pContributingValue = nullptr;
+    unsigned id = (unsigned)-1;
+    int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
+    unsigned col = (unsigned)-1;
+    if (DxilInst_StoreOutput SO = DxilInst_StoreOutput(CI)) {
+      pDxilSig = &m_pModule->GetOutputSignature();
+      pContributingValue = SO.get_value();
+      GetUnsignedVal(SO.get_outputtSigId(), &id);
+      GetUnsignedVal(SO.get_colIndex(), &col);
+      GetUnsignedVal(SO.get_rowIndex(), (uint32_t*)&startRow);
+    } else if (DxilInst_StorePatchConstant SPC = DxilInst_StorePatchConstant(CI)) {
+      pDxilSig = &m_pModule->GetPatchConstantSignature();
+      pContributingValue = SPC.get_value();
+      GetUnsignedVal(SPC.get_outputSigID(), &id);
+      GetUnsignedVal(SPC.get_row(), (uint32_t*)&startRow);
+      GetUnsignedVal(SPC.get_col(), &col);
+    } else {
+      IFT(DXC_E_GENERAL_INTERNAL_ERROR);
+    }
+
+    DxilSignatureElement &SigElem = pDxilSig->GetElement(id);
+    if (!SigElem.IsAllocated())
+      continue;
+
+    if (startRow != Semantic::kUndefinedRow) {
+      endRow = startRow;
+    } else {
+      // The entire column is affected by value.
+      DXASSERT_NOMSG(SigElem.GetID() == id && SigElem.GetStartRow() != Semantic::kUndefinedRow);
+      startRow = 0;
+      endRow = SigElem.GetRows() - 1;
+    }
+
+    if (startRow == endRow) {
+      // Scalar or indexable with known index.
+      unsigned index = GetLinearIndex(SigElem, startRow, col);
+      InstructionSetType &ContributingInstructions = Entry.ContributingInstructions[index];
+      CollectValuesContributingToOutputRec(pContributingValue, ContributingInstructions);
+    } else {
+      // Dynamically indexed output.
+      InstructionSetType ContributingInstructions;
+      CollectValuesContributingToOutputRec(pContributingValue, ContributingInstructions);
+
+      for (int row = startRow; row <= endRow; row++) {
+        unsigned index = GetLinearIndex(SigElem, row, col);
+        auto it = Entry.ContributingInstructions.emplace(index, InstructionSetType{});
+        if (it.second) {
+          it.first->second = ContributingInstructions;
+        } else {
+          InstructionSetType NewSet;
+          std::set_union(it.first->second.begin(),
+                         it.first->second.end(),
+                         ContributingInstructions.begin(),
+                         ContributingInstructions.end(),
+                         std::inserter(NewSet, NewSet.end()));
+          it.first->second.swap(NewSet);
+        }
+      }
+    }
+  }
+}
+
+void DxilViewIdState::CollectValuesContributingToOutputRec(Value *pContributingValue,
+                                                           InstructionSetType &ContributingInstructions) {
+  if (Argument *pArg = dyn_cast<Argument>(pContributingValue)) {
+    // TODO: handle multiple functions.
+    return;
+  }
+
+  Instruction *pContributingInst = dyn_cast<Instruction>(pContributingValue);
+  if (pContributingInst == nullptr) {
+    // Can be literal constant, global decl, branch target.
+    DXASSERT_NOMSG(isa<Constant>(pContributingValue) || isa<BasicBlock>(pContributingValue));
+    return;
+  }
+
+  auto itInst = ContributingInstructions.emplace(pContributingInst);
+  // Already visited instruction.
+  if (!itInst.second) return;
+
+  // Handle special cases.
+  if (PHINode *phi = dyn_cast<PHINode>(pContributingInst)) {
+    // For constant operands of phi, handle control dependence on incident edge.
+    unsigned iOp = 0;
+    for (auto it = phi->block_begin(), endIt = phi->block_end(); it != endIt; ++it, iOp++) {
+      Value *O = phi->getOperand(iOp);
+      if (isa<Constant>(O)) {
+        BasicBlock *pPredBB = *it;
+        CollectValuesContributingToOutputRec(pPredBB->getTerminator(), ContributingInstructions);
+      }
+    }
+  } else if (isa<LoadInst>(pContributingInst) || 
+             isa<AtomicCmpXchgInst>(pContributingInst) ||
+             isa<AtomicRMWInst>(pContributingInst)) {
+    Value *pPtrValue = pContributingInst->getOperand(0);
+    DXASSERT_NOMSG(pPtrValue->getType()->isPointerTy());
+    const ValueSetType &ReachingDecls = CollectReachingDecls(pPtrValue);
+    DXASSERT_NOMSG(ReachingDecls.size() > 0);
+    for (Value *pDeclValue : ReachingDecls) {
+      const ValueSetType &Stores = CollectStores(pDeclValue);
+      for (Value *V : Stores) {
+        CollectValuesContributingToOutputRec(V, ContributingInstructions);
+      }
+    }
+  } else if (CallInst *CI = dyn_cast<CallInst>(pContributingInst)) {
+    if (!hlsl::OP::IsDxilOpFuncCallInst(CI)) {
+      // TODO: Return value of a user function.
+      return;
+    }
+  }
+
+  // Handle instruction inputs.
+  unsigned NumOps = pContributingInst->getNumOperands();
+  for (unsigned i = 0; i < NumOps; i++) {
+    Value *O = pContributingInst->getOperand(i);
+    CollectValuesContributingToOutputRec(O, ContributingInstructions);
+  }
+
+  // Handle control dependence of this instruction BB.
+  BasicBlock *pBB = pContributingInst->getParent();
+  Function *F = pBB->getParent();
+  FuncInfo *pFuncInfo = m_FuncInfo[F].get();
+  const BasicBlockSet &CtrlDepSet = pFuncInfo->CtrlDep.GetCDBlocks(pBB);
+  for (BasicBlock *B : CtrlDepSet) {
+    CollectValuesContributingToOutputRec(B->getTerminator(), ContributingInstructions);
+  }
+}
+
+const DxilViewIdState::ValueSetType &DxilViewIdState::CollectReachingDecls(Value *pValue) {
+  auto it = m_ReachingDeclsCache.emplace(pValue, ValueSetType());
+  if (it.second) {
+    // We have not seen this value before.
+    ValueSetType Visited;
+    CollectReachingDeclsRec(pValue, it.first->second, Visited);
+  }
+  return it.first->second;
+}
+
+void DxilViewIdState::CollectReachingDeclsRec(Value *pValue, ValueSetType &ReachingDecls, ValueSetType &Visited) {
+  if (Visited.find(pValue) != Visited.end())
+    return;
+
+  bool bInitialValue = Visited.size() == 0;
+  Visited.emplace(pValue);
+
+  if (!bInitialValue) {
+    auto it = m_ReachingDeclsCache.find(pValue);
+    if (it != m_ReachingDeclsCache.end()) {
+      ValueSetType NewSet;
+      std::set_union(ReachingDecls.begin(), ReachingDecls.end(),
+                     it->second.begin(), it->second.end(),
+                     std::inserter(NewSet, NewSet.end()));
+      ReachingDecls.swap(NewSet);
+      return;
+    }
+  }
+
+  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(pValue)) {
+    ReachingDecls.emplace(pValue);
+    return;
+  }
+
+  if (GetElementPtrInst *pGepInst = dyn_cast<GetElementPtrInst>(pValue)) {
+    Value *pPtrValue = pGepInst->getPointerOperand();
+    CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
+  } else if (GEPOperator *pGepOp = dyn_cast<GEPOperator>(pValue)) {
+    Value *pPtrValue = pGepOp->getPointerOperand();
+    CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
+  } else if (AllocaInst *AI = dyn_cast<AllocaInst>(pValue)) {
+    ReachingDecls.emplace(pValue);
+  } else if (PHINode *phi = dyn_cast<PHINode>(pValue)) {
+    for (Value *pPtrValue : phi->operands()) {
+      CollectReachingDeclsRec(pPtrValue, ReachingDecls, Visited);
+    }
+  } else if (Argument *pArg = dyn_cast<Argument>(pValue)) {
+    ReachingDecls.emplace(pValue);
+  } else {
+    IFT(DXC_E_GENERAL_INTERNAL_ERROR);
+  }
+}
+
+const DxilViewIdState::ValueSetType &DxilViewIdState::CollectStores(llvm::Value *pValue) {
+  auto it = m_StoresPerDeclCache.emplace(pValue, ValueSetType());
+  if (it.second) {
+    // We have not seen this value before.
+    ValueSetType Visited;
+    CollectStoresRec(pValue, it.first->second, Visited);
+  }
+  return it.first->second;
+}
+
+void DxilViewIdState::CollectStoresRec(llvm::Value *pValue, ValueSetType &Stores, ValueSetType &Visited) {
+  if (Visited.find(pValue) != Visited.end())
+    return;
+
+  bool bInitialValue = Visited.size() == 0;
+  Visited.emplace(pValue);
+
+  if (!bInitialValue) {
+    auto it = m_StoresPerDeclCache.find(pValue);
+    if (it != m_StoresPerDeclCache.end()) {
+      ValueSetType NewSet;
+      std::set_union(Stores.begin(), Stores.end(),
+                     it->second.begin(), it->second.end(),
+                     std::inserter(NewSet, NewSet.end()));
+      Stores.swap(NewSet);
+      return;
+    }
+  }
+
+  if (isa<LoadInst>(pValue)) {
+    return;
+  } else if (isa<StoreInst>(pValue) ||
+             isa<AtomicCmpXchgInst>(pValue) ||
+             isa<AtomicRMWInst>(pValue)) {
+    Stores.emplace(pValue);
+    return;
+  }
+
+  for (auto *U : pValue->users()) {
+    CollectStoresRec(U, Stores, Visited);
+  }
+}
+
+void DxilViewIdState::CreateViewIdSets(EntryInfo &Entry, 
+                                       OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                       InputsContributingToOutputType &InputsContributingToOutputs,
+                                       bool bPC) {
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+
+  for (auto &itOut : Entry.ContributingInstructions) {
+    unsigned outIdx = itOut.first;
+    InstructionSetType &ContributingInstrunction = itOut.second;
+    for (Instruction *pInst : ContributingInstrunction) {
+      // Set output dependence on ViewId.
+      if (DxilInst_ViewID VID = DxilInst_ViewID(pInst)) {
+        OutputsDependentOnViewId[outIdx] = true;
+        continue;
+      }
+
+      // Start setting output dependence on inputs.
+      DxilSignatureElement *pSigElem = nullptr;
+      bool bLoadOutputCPInHS = false;
+      unsigned inpId = (unsigned)-1;
+      int startRow = Semantic::kUndefinedRow, endRow = Semantic::kUndefinedRow;
+      unsigned col = (unsigned)-1;
+      if (DxilInst_LoadInput LI = DxilInst_LoadInput(pInst)) {
+        GetUnsignedVal(LI.get_inputSigId(), &inpId);
+        GetUnsignedVal(LI.get_colIndex(), &col);
+        GetUnsignedVal(LI.get_rowIndex(), (uint32_t*)&startRow);
+        pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
+      } else if (DxilInst_LoadOutputControlPoint LOCP = DxilInst_LoadOutputControlPoint(pInst)) {
+        GetUnsignedVal(LOCP.get_inputSigId(), &inpId);
+        GetUnsignedVal(LOCP.get_col(), &col);
+        GetUnsignedVal(LOCP.get_row(), (uint32_t*)&startRow);
+        if (pSM->IsHS()) {
+          pSigElem = &m_pModule->GetOutputSignature().GetElement(inpId);
+          bLoadOutputCPInHS = true;
+        } else if (pSM->IsDS()) {
+          if (!bPC) {
+            pSigElem = &m_pModule->GetInputSignature().GetElement(inpId);
+          }
+        } else {
+          DXASSERT_NOMSG(false);
+        }
+      } else if (DxilInst_LoadPatchConstant LPC = DxilInst_LoadPatchConstant(pInst)) {
+        if (pSM->IsDS() && bPC) {
+          GetUnsignedVal(LPC.get_inputSigId(), &inpId);
+          GetUnsignedVal(LPC.get_col(), &col);
+          GetUnsignedVal(LPC.get_row(), (uint32_t*)&startRow);
+          pSigElem = &m_pModule->GetPatchConstantSignature().GetElement(inpId);
+        }
+      } else {
+        continue;
+      }
+
+      // Finalize setting output dependence on inputs.
+      if (pSigElem && pSigElem->IsAllocated()) {
+        if (startRow != Semantic::kUndefinedRow) {
+          endRow = startRow;
+        } else {
+          // The entire column contributes to output.
+          startRow = 0;
+          endRow = pSigElem->GetRows() - 1;
+        }
+
+        auto &ContributingInputs = InputsContributingToOutputs[outIdx];
+        for (int row = startRow; row <= endRow; row++) {
+          unsigned index = GetLinearIndex(*pSigElem, row, col);
+          if (!bLoadOutputCPInHS) {
+            ContributingInputs.emplace(index);
+          } else {
+            // This HS patch-constant output depends on an input value of LoadOutputControlPoint
+            // that is the output value of the HS main (control-point) function.
+            // Transitively update this (patch-constant) output dependence on main (control-point) output.
+            DXASSERT_NOMSG(&OutputsDependentOnViewId == &m_PCOutputsDependentOnViewId);
+            OutputsDependentOnViewId[outIdx] = OutputsDependentOnViewId[outIdx] || m_OutputsDependentOnViewId[index];
+
+            const auto it = m_InputsContributingToOutputs.find(index);
+            if (it != m_InputsContributingToOutputs.end()) {
+              const std::set<unsigned> &LoadOutputCPInputsContributingToOutputs = it->second;
+              std::set<unsigned> NewSet;
+              std::set_union(ContributingInputs.begin(),
+                             ContributingInputs.end(),
+                             LoadOutputCPInputsContributingToOutputs.begin(),
+                             LoadOutputCPInputsContributingToOutputs.end(),
+                             std::inserter(NewSet, NewSet.end()));
+              ContributingInputs.swap(NewSet);
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+unsigned DxilViewIdState::GetLinearIndex(DxilSignatureElement &SigElem, int row, unsigned col) const {
+  DXASSERT_NOMSG(row >= 0 && col < kNumComps && SigElem.GetStartRow() != Semantic::kUndefinedRow);
+  unsigned idx = (((unsigned)row) + SigElem.GetStartRow())*kNumComps + col + SigElem.GetStartCol();
+  return idx;
+}
+
+void DxilViewIdState::UpdateDynamicIndexUsageState() const {
+  UpdateDynamicIndexUsageStateForSig(m_pModule->GetInputSignature(), m_InpSigDynIdxElems);
+  UpdateDynamicIndexUsageStateForSig(m_pModule->GetOutputSignature(), m_OutSigDynIdxElems);
+  UpdateDynamicIndexUsageStateForSig(m_pModule->GetPatchConstantSignature(), m_PCSigDynIdxElems);
+}
+
+void DxilViewIdState::UpdateDynamicIndexUsageStateForSig(DxilSignature &Sig,
+                                                         const DynamicallyIndexedElemsType &DynIdxElems) const {
+  for (auto it : DynIdxElems) {
+    unsigned id = it.first;
+    unsigned mask = it.second;
+    DxilSignatureElement &E = Sig.GetElement(id);
+    E.SetDynIdxCompMask(mask);
+  }
+}
+
+static unsigned RoundUpToUINT(unsigned x) {
+  return (x + 31)/32;
+}
+
+const vector<unsigned> &DxilViewIdState::GetSerialized() {
+  if (!m_SerializedState.empty())
+    return m_SerializedState;
+
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+  unsigned NumOutUINTs = RoundUpToUINT(m_NumOutputSigScalars);
+  unsigned NumPCUINTs = RoundUpToUINT(m_NumPCSigScalars);
+  unsigned Size1 = 2 + NumOutUINTs * (1 + m_NumInputSigScalars);
+  unsigned Size2 = 0;
+  if (pSM->IsHS()) {
+    Size2 = 2 + NumPCUINTs * (1 + m_NumInputSigScalars);
+  } else if (pSM->IsDS()) {
+    Size2 = 2 + NumOutUINTs * (1 + m_NumPCSigScalars);
+  }
+  unsigned Size = Size1 + Size2;
+
+  m_SerializedState.resize(Size);
+  std::fill(m_SerializedState.begin(), m_SerializedState.end(), 0u);
+
+  unsigned *pData = &m_SerializedState[0];
+  Serialize1(m_NumInputSigScalars, m_NumOutputSigScalars,
+             m_OutputsDependentOnViewId, m_InputsContributingToOutputs, pData);
+  DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size1));
+
+  if (pSM->IsHS()) {
+    Serialize1(m_NumInputSigScalars, m_NumPCSigScalars,
+               m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs, pData);
+  } else if (pSM->IsDS()) {
+    Serialize1(m_NumPCSigScalars, m_NumOutputSigScalars,
+               m_OutputsDependentOnViewId, m_PCInputsContributingToOutputs, pData);
+  }
+  DXASSERT_NOMSG(pData == (&m_SerializedState[0] + Size));
+
+  return m_SerializedState;
+}
+
+void DxilViewIdState::Serialize1(unsigned NumInputs, unsigned NumOutputs,
+                                 const OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                 const InputsContributingToOutputType &InputsContributingToOutputs,
+                                 unsigned *&pData) {
+  unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
+
+  unsigned *p = pData;
+  *p++ = NumInputs;
+  *p++ = NumOutputs;
+
+  // Serialize output dependence on ViewId.
+  for (unsigned i = 0; i < NumOutUINTs; i++) {
+    unsigned x = 0;
+    for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
+      if (OutputsDependentOnViewId[i*32 + j]) {
+        x |= (1u << j);
+      }
+    }
+    *p++ = x;
+  }
+
+  // Serialize output dependence on inputs.
+  for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
+    auto it = InputsContributingToOutputs.find(outputIdx);
+    if (it != InputsContributingToOutputs.end()) {
+      for (unsigned inputIdx : it->second) {
+        unsigned w = outputIdx / 32;
+        unsigned b = outputIdx % 32;
+        p[inputIdx*NumOutUINTs + w] |= (1u << b);
+      }
+    }
+  }
+  p += NumInputs * NumOutUINTs;
+
+  pData = p;
+}
+
+void DxilViewIdState::Deserialize(const unsigned *pData, unsigned DataSize) {
+  Clear();
+
+  const ShaderModel *pSM = m_pModule->GetShaderModel();
+  unsigned ConsumedUINTs;
+  ConsumedUINTs = Deserialize1(pData, DataSize, m_NumInputSigScalars, m_NumOutputSigScalars,
+                               m_OutputsDependentOnViewId, m_InputsContributingToOutputs);
+
+  if (ConsumedUINTs < DataSize) {
+    unsigned t = 0;
+    if (pSM->IsHS()) {
+      unsigned NumInputs;
+      t = Deserialize1(&pData[ConsumedUINTs], DataSize-ConsumedUINTs, NumInputs, m_NumPCSigScalars,
+                       m_PCOutputsDependentOnViewId, m_InputsContributingToPCOutputs);
+      DXASSERT_NOMSG(NumInputs == m_NumInputSigScalars);
+    } else if (pSM->IsDS()) {
+      unsigned NumOutputs;
+      OutputsDependentOnViewIdType OutputsDependentOnViewId;
+      t = Deserialize1(&pData[ConsumedUINTs], DataSize-ConsumedUINTs,
+                       m_NumPCSigScalars, NumOutputs,
+                       OutputsDependentOnViewId, m_PCInputsContributingToOutputs);
+      DXASSERT_NOMSG(NumOutputs == m_NumOutputSigScalars);
+      DXASSERT_NOMSG(OutputsDependentOnViewId == m_OutputsDependentOnViewId);
+    }
+    ConsumedUINTs += t;
+  }
+  DXASSERT_NOMSG(ConsumedUINTs == DataSize);
+}
+
+unsigned DxilViewIdState::Deserialize1(const unsigned *pData, unsigned DataSize,
+                                       unsigned &NumInputs, unsigned &NumOutputs,
+                                       OutputsDependentOnViewIdType &OutputsDependentOnViewId,
+                                       InputsContributingToOutputType &InputsContributingToOutputs) {
+  IFTBOOL(DataSize >= 2, DXC_E_GENERAL_INTERNAL_ERROR);
+  const unsigned *p = pData;
+  NumInputs  = *p++;
+  NumOutputs = *p++;
+  unsigned NumOutUINTs = RoundUpToUINT(NumOutputs);
+
+  unsigned Size = 2 + NumOutUINTs * (1 +  NumInputs);
+  IFTBOOL(Size <= DataSize, DXC_E_GENERAL_INTERNAL_ERROR);
+
+  // Deserialize output dependence on ViewId.
+  for (unsigned i = 0; i < NumOutUINTs; i++) {
+    unsigned x = *p++;
+    for (unsigned j = 0; j < std::min(32u, NumOutputs - 32u*i); j++) {
+      if (x & (1u << j)) {
+        OutputsDependentOnViewId[i*32 + j] = true;
+      }
+    }
+  }
+
+  // Deserialize output dependence on inputs.
+  for (unsigned inputIdx = 0; inputIdx < NumInputs; inputIdx++) {
+    for (unsigned outputIdx = 0; outputIdx < NumOutputs; outputIdx++) {
+      unsigned w = outputIdx / 32;
+      unsigned b = outputIdx % 32;
+      if (p[inputIdx*NumOutUINTs + w] & (1u << b)) {
+        InputsContributingToOutputs[outputIdx].insert(inputIdx);
+      }
+    }
+  }
+
+  return Size;
+}
+
+
+char ComputeViewIdState::ID = 0;
+
+INITIALIZE_PASS_BEGIN(ComputeViewIdState, "viewid_state",
+                "Compute information related to ViewID", true, true)
+INITIALIZE_PASS_END(ComputeViewIdState, "viewid_state",
+                "Compute information related to ViewID", true, true)
+
+ComputeViewIdState::ComputeViewIdState() : ModulePass(ID) {
+}
+
+bool ComputeViewIdState::runOnModule(Module &M) {
+  DxilModule &DxilModule = M.GetOrCreateDxilModule();
+  const ShaderModel *pSM = DxilModule.GetShaderModel();
+  if (!pSM->IsCS()) {
+    DxilViewIdState &ViewIdState = DxilModule.GetViewIdState();
+    ViewIdState.Compute();
+    return true;
+  }
+  return false;
+}
+
+void ComputeViewIdState::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.setPreservesAll();
+}
+
+
+namespace llvm {
+
+ModulePass *createComputeViewIdStatePass() {
+  return new ComputeViewIdState();
+}
+
+} // end of namespace llvm

+ 121 - 0
lib/HLSL/ControlDependence.cpp

@@ -0,0 +1,121 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// ViewIdAnalysis.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/ControlDependence.h"
+#include "dxc/Support/Global.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace hlsl;
+
+
+const BasicBlockSet &ControlDependence::GetCDBlocks(BasicBlock *pBB) const {
+  auto it = m_ControlDependence.find(pBB);
+  if (it != m_ControlDependence.end())
+    return it->second;
+  else
+    return m_EmptyBBSet;
+}
+
+void ControlDependence::print(raw_ostream &OS) {
+  OS << "Control dependence for function '" << m_pFunc->getName() << "'\n";
+  for (auto &it : m_ControlDependence) {
+    BasicBlock *pBB = it.first;
+    OS << "Block " << pBB->getName() << ": { ";
+    bool bFirst = true;
+    for (BasicBlock *pBB2 : it.second) {
+      if (!bFirst) OS << ", ";
+      OS << pBB2->getName();
+      bFirst = false;
+    }
+    OS << " }\n";
+  }
+  OS << "\n";
+}
+
+void ControlDependence::dump() {
+  print(dbgs());
+}
+
+void ControlDependence::Compute(Function *F, PostDomRelationType &PostDomRel) {
+  m_pFunc = F;
+
+  // Compute reverse topological order of PDT.
+  BasicBlockVector RevTopOrder;
+  BasicBlockSet VisitedBBs;
+  for (BasicBlock *pBB : PostDomRel.getRoots()) {
+    ComputeRevTopOrderRec(PostDomRel, pBB, RevTopOrder, VisitedBBs);
+  }
+  DXASSERT_NOMSG(RevTopOrder.size() == VisitedBBs.size());
+
+  // Compute control dependence relation.
+  for (size_t iBB = 0; iBB < RevTopOrder.size(); iBB++) {
+    BasicBlock *x = RevTopOrder[iBB];
+
+    // For each y = pred(x): if ipostdom(y) != x then add "x is control dependent on y"
+    for (auto itPred = pred_begin(x), endPred = pred_end(x); itPred != endPred; ++itPred) {
+      BasicBlock *y = *itPred;  // predecessor of x
+      BasicBlock *pPredIDomBB = GetIPostDom(PostDomRel, y);
+      if (pPredIDomBB != x) {
+        m_ControlDependence[x].insert(y);
+      }
+    }
+
+    SmallVector<BasicBlock *, 8> Descendants;
+    PostDomRel.getDescendants(x, Descendants);
+    // For all z such that ipostdom(z) = x
+    for (BasicBlock *z : Descendants) {
+      if (z == x) continue;
+      auto it = m_ControlDependence.find(z);
+      if (it == m_ControlDependence.end())
+        continue;
+
+      // For all y in CDG(z)
+      for (BasicBlock *y : it->second) {
+        // if ipostdom(y) != x then add "x is control dependent on y" 
+        BasicBlock *pPredIDomBB = GetIPostDom(PostDomRel, y);
+        if (pPredIDomBB != x) {
+          m_ControlDependence[x].insert(y);
+        }
+      }
+    }
+  }
+}
+
+void ControlDependence::Clear() {
+  m_pFunc = nullptr;
+  m_ControlDependence.clear();
+  m_EmptyBBSet.clear();
+}
+
+BasicBlock *ControlDependence::GetIPostDom(PostDomRelationType &PostDomRel, BasicBlock *pBB) {
+  auto *pPDTNode = PostDomRel.getNode(pBB);
+  auto *pIDomNode = pPDTNode->getIDom();
+  BasicBlock *pIDomBB = pIDomNode != nullptr ? pIDomNode->getBlock() : nullptr;
+  return pIDomBB;
+}
+
+void ControlDependence::ComputeRevTopOrderRec(PostDomRelationType &PostDomRel,
+                                              BasicBlock *pBB,
+                                              BasicBlockVector &RevTopOrder,
+                                              BasicBlockSet &VisitedBBs) {
+  if (VisitedBBs.find(pBB) != VisitedBBs.end()) {
+    return;
+  }
+  VisitedBBs.insert(pBB);
+
+  SmallVector<BasicBlock *, 8> Descendants;
+  PostDomRel.getDescendants(pBB, Descendants);
+  for (BasicBlock *pDescBB : Descendants) {
+    if (pDescBB != pBB)
+      ComputeRevTopOrderRec(PostDomRel, pDescBB, RevTopOrder, VisitedBBs);
+  }
+
+  RevTopOrder.emplace_back(pBB);
+}

+ 2 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -19,6 +19,7 @@
 #include "dxc/HLSL/ReducibilityAnalysis.h"
 #include "dxc/HLSL/HLMatrixLowerPass.h"
 #include "dxc/HLSL/DxilGenerationPass.h"
+#include "dxc/HLSL/ComputeViewIdState.h"
 #include "dxc/Support/dxcapi.impl.h"
 
 #include "llvm/Pass.h"
@@ -73,6 +74,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeBasicAliasAnalysisPass(Registry);
     initializeCFGSimplifyPassPass(Registry);
     initializeCFLAliasAnalysisPass(Registry);
+    initializeComputeViewIdStatePass(Registry);
     initializeConstantMergePass(Registry);
     initializeCorrelatedValuePropagationPass(Registry);
     initializeDAEPass(Registry);

+ 53 - 2
lib/HLSL/DxilMetadataHelper.cpp

@@ -17,6 +17,7 @@
 #include "dxc/HLSL/DxilSignature.h"
 #include "dxc/HLSL/DxilTypeSystem.h"
 #include "dxc/HLSL/DxilRootSignature.h"
+#include "dxc/HLSL/ComputeViewIdState.h"
 
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
@@ -25,6 +26,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/Support/raw_ostream.h"
 #include <array>
+#include <algorithm>
 
 #include "dxc/Support/WinIncludes.h"
 
@@ -49,14 +51,16 @@ const char DxilMDHelper::kDxilValidatorVersionMDName[]                = "dx.valv
 
 // This named metadata is not valid in final module (should be moved to DxilContainer)
 const char DxilMDHelper::kDxilRootSignatureMDName[]                   = "dx.rootSignature";
+const char DxilMDHelper::kDxilViewIdStateMDName[]                     = "dx.viewIdState";
 
-static std::array<const char *, 6> DxilMDNames = {
+static std::array<const char *, 7> DxilMDNames = {
   DxilMDHelper::kDxilVersionMDName,
   DxilMDHelper::kDxilShaderModelMDName,
   DxilMDHelper::kDxilEntryPointsMDName,
   DxilMDHelper::kDxilResourcesMDName,
   DxilMDHelper::kDxilTypeSystemMDName,
-  DxilMDHelper::kDxilValidatorVersionMDName
+  DxilMDHelper::kDxilValidatorVersionMDName,
+  DxilMDHelper::kDxilViewIdStateMDName
 };
 
 DxilMDHelper::DxilMDHelper(Module *pModule, std::unique_ptr<ExtraPropertyHelper> EPH)
@@ -814,6 +818,44 @@ void DxilMDHelper::LoadDxilFieldAnnotation(const MDOperand &MDO, DxilFieldAnnota
   }
 }
 
+void DxilMDHelper::EmitDxilViewIdState(DxilViewIdState &ViewIdState) {
+  const vector<unsigned> &Data = ViewIdState.GetSerialized();
+  // If all UINTs are zero, do not emit ViewIdState.
+  if (!std::any_of(Data.begin(), Data.end(), [](unsigned e){return e!=0;}))
+    return;
+
+  Constant *V = ConstantDataArray::get(m_Ctx, ArrayRef<uint32_t>(Data));
+  NamedMDNode *pViewIdNamedMD = m_pModule->getNamedMetadata(kDxilViewIdStateMDName);
+  IFTBOOL(pViewIdNamedMD == nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+  pViewIdNamedMD = m_pModule->getOrInsertNamedMetadata(kDxilViewIdStateMDName);
+  pViewIdNamedMD->addOperand(MDNode::get(m_Ctx, {ConstantAsMetadata::get(V)}));
+}
+
+void DxilMDHelper::LoadDxilViewIdState(DxilViewIdState &ViewIdState) {
+  NamedMDNode *pViewIdStateNamedMD = m_pModule->getNamedMetadata(kDxilViewIdStateMDName);
+  if(!pViewIdStateNamedMD)
+    return;
+
+  IFTBOOL(pViewIdStateNamedMD->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA);
+
+  MDNode *pNode = pViewIdStateNamedMD->getOperand(0);
+  IFTBOOL(pNode->getNumOperands() == 1, DXC_E_INCORRECT_DXIL_METADATA);
+  const MDOperand &MDO = pNode->getOperand(0);
+
+  const ConstantAsMetadata *pMetaData = dyn_cast<ConstantAsMetadata>(MDO.get());
+  IFTBOOL(pMetaData != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+  if (isa<ConstantAggregateZero>(pMetaData->getValue()))
+    return;
+  const ConstantDataArray *pData = dyn_cast<ConstantDataArray>(pMetaData->getValue());
+  IFTBOOL(pData != nullptr, DXC_E_INCORRECT_DXIL_METADATA);
+  IFTBOOL(pData->getElementType() == Type::getInt32Ty(m_Ctx), DXC_E_INCORRECT_DXIL_METADATA);
+  IFTBOOL(pData->getRawDataValues().size() < UINT_MAX && 
+          (pData->getRawDataValues().size() & 3) == 0, DXC_E_INCORRECT_DXIL_METADATA);
+
+  ViewIdState.Deserialize((unsigned *)pData->getRawDataValues().begin(), 
+                          (unsigned)pData->getRawDataValues().size() / 4);
+}
+
 MDNode *DxilMDHelper::EmitControlFlowHints(llvm::LLVMContext &Ctx, std::vector<DXIL::ControlFlowHint> &hints) {
   SmallVector<Metadata *, 4> Args;
   // Reserve operand 0 for self reference.
@@ -1183,6 +1225,12 @@ void DxilExtraPropertyHelper::EmitSignatureElementProperties(const DxilSignature
     MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementOutputStreamTag, m_Ctx));
     MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetOutputStream(), m_Ctx));
   }
+
+  // Mask of Dynamically indexed components.
+  if (SE.GetDynIdxCompMask() != 0) {
+    MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag, m_Ctx));
+    MDVals.emplace_back(DxilMDHelper::Uint32ToConstMD(SE.GetDynIdxCompMask(), m_Ctx));
+  }
 }
 
 void DxilExtraPropertyHelper::LoadSignatureElementProperties(const MDOperand &MDO, DxilSignatureElement &SE) {
@@ -1204,6 +1252,9 @@ void DxilExtraPropertyHelper::LoadSignatureElementProperties(const MDOperand &MD
       break;
     case DxilMDHelper::kHLSignatureElementGlobalSymbolTag:
       break;
+    case DxilMDHelper::kDxilSignatureElementDynIdxCompMaskTag:
+      SE.SetDynIdxCompMask(DxilMDHelper::ConstMDToUint32(MDO));
+      break;
     default:
       DXASSERT(false, "Unknown signature element tag");
     }

+ 10 - 0
lib/HLSL/DxilModule.cpp

@@ -59,6 +59,7 @@ DxilModule::DxilModule(Module *pModule)
 , m_pModule(pModule)
 , m_pOP(std::make_unique<OP>(pModule->getContext(), pModule))
 , m_pTypeSystem(std::make_unique<DxilTypeSystem>(pModule))
+, m_pViewIdState(std::make_unique<DxilViewIdState>(this))
 , m_pMDHelper(std::make_unique<DxilMDHelper>(pModule, std::make_unique<DxilExtraPropertyHelper>(pModule)))
 , m_pDebugInfoFinder(nullptr)
 , m_pEntryFunc(nullptr)
@@ -885,6 +886,10 @@ DxilTypeSystem &DxilModule::GetTypeSystem() {
   return *m_pTypeSystem;
 }
 
+DxilViewIdState &DxilModule::GetViewIdState() {
+  return *m_pViewIdState;
+}
+
 void DxilModule::ResetTypeSystem(DxilTypeSystem *pValue) {
   m_pTypeSystem.reset(pValue);
 }
@@ -943,6 +948,9 @@ void DxilModule::EmitDxilMetadata() {
   MDTuple *pMDResources = EmitDxilResources();
   MDTuple *pMDProperties = EmitDxilShaderProperties();
   m_pMDHelper->EmitDxilTypeSystem(GetTypeSystem(), m_LLVMUsed);
+  if (!m_pSM->IsCS()) {
+    m_pMDHelper->EmitDxilViewIdState(GetViewIdState());
+  }
   EmitLLVMUsed();
   MDTuple *pEntry = m_pMDHelper->EmitDxilEntryPointTuple(GetEntryFunction(), m_EntryName, pMDSignatures, pMDResources, pMDProperties);
   vector<MDNode *> Entries;
@@ -983,6 +991,8 @@ void DxilModule::LoadDxilMetadata() {
   m_pMDHelper->LoadDxilTypeSystem(*m_pTypeSystem.get());
 
   m_pMDHelper->LoadRootSignature(*m_RootSignature.get());
+
+  m_pMDHelper->LoadDxilViewIdState(*m_pViewIdState.get());
 }
 
 MDTuple *DxilModule::EmitDxilResources() {

+ 12 - 1
lib/HLSL/DxilSignatureElement.cpp

@@ -37,7 +37,8 @@ DxilSignatureElement::DxilSignatureElement(DXIL::SigPointKind sigPointKind)
 , m_Rows(0)
 , m_Cols(0)
 , m_StartRow(Semantic::kUndefinedRow)
-, m_StartCol(Semantic::kUndefinedCol) {
+, m_StartCol(Semantic::kUndefinedCol)
+, m_DynIdxCompMask(0) {
 }
 
 DxilSignatureElement::~DxilSignatureElement() {
@@ -262,4 +263,14 @@ bool DxilSignatureElement::IsAllocated() const {
   return (m_StartRow != Semantic::kUndefinedRow) && (m_StartCol != Semantic::kUndefinedCol);
 }
 
+unsigned DxilSignatureElement::GetDynIdxCompMask() const {
+  DXASSERT_NOMSG(m_DynIdxCompMask <= 0xF);
+  return m_DynIdxCompMask;
+}
+
+void DxilSignatureElement::SetDynIdxCompMask(unsigned DynIdxCompMask) {
+  DXASSERT_NOMSG(DynIdxCompMask <= 0xF);
+  m_DynIdxCompMask = DynIdxCompMask;
+}
+
 } // namespace hlsl

+ 3 - 0
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -28,6 +28,7 @@
 #include "llvm/Transforms/Vectorize.h"
 #include "dxc/HLSL/DxilGenerationPass.h" // HLSL Change
 #include "dxc/HLSL/HLMatrixLowerPass.h" // HLSL Change
+#include "dxc/HLSL/ComputeViewIdState.h" // HLSL Change
 
 using namespace llvm;
 
@@ -276,6 +277,7 @@ void PassManagerBuilder::populateModulePassManager(
       MPM.add(createMultiDimArrayToOneDimArrayPass());// HLSL Change
       MPM.add(createDxilCondenseResourcesPass()); // HLSL Change
       MPM.add(createDxilLegalizeSampleOffsetPass()); // HLSL Change
+      MPM.add(createComputeViewIdStatePass());    // HLSL Change
       MPM.add(createDxilEmitMetadataPass());      // HLSL Change
     }
     // HLSL Change Ends.
@@ -545,6 +547,7 @@ void PassManagerBuilder::populateModulePassManager(
     MPM.add(createDxilCondenseResourcesPass());
     if (DisableUnrollLoops)
       MPM.add(createDxilLegalizeSampleOffsetPass()); // HLSL Change
+    MPM.add(createComputeViewIdStatePass()); // HLSL Change
     MPM.add(createDxilEmitMetadataPass());
   }
   // HLSL Change Ends.

+ 2 - 1
tools/clang/tools/dxcompiler/CMakeLists.txt

@@ -1,4 +1,4 @@
-# Copyright (C) Microsoft Corporation. All rights reserved.
+# Copyright (C) Microsoft Corporation. All rights reserved.
 # This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details.
 find_package(DiaSDK REQUIRED) # Used for constants and declarations.
 
@@ -68,6 +68,7 @@ set(LIBRARIES
   clangTooling
   clangBasic
   libclang
+  LLVMHLSL
   )
 
 set(GENERATED_HEADERS

+ 83 - 2
tools/clang/tools/dxcompiler/dxcompilerobj.cpp

@@ -1048,6 +1048,21 @@ static void PrintSignature(LPCSTR pName, const DxilProgramSignature *pSignature,
   OS << comment << "\n";
 }
 
+static void PintCompMaskNameCompact(raw_string_ostream &OS, unsigned CompMask) {
+  char Mask[5];
+  memset(Mask, '\0', sizeof(Mask));
+  unsigned idx = 0;
+  if (CompMask & DxilProgramSigMaskX)
+    Mask[idx++] = 'x';
+  if (CompMask & DxilProgramSigMaskY)
+    Mask[idx++] = 'y';
+  if (CompMask & DxilProgramSigMaskZ)
+    Mask[idx++] = 'z';
+  if (CompMask & DxilProgramSigMaskW)
+    Mask[idx++] = 'w';
+  OS << right_justify(Mask, 4);
+}
+
 static void PrintDxilSignature(LPCSTR pName,
                                      const DxilSignature &Signature,
                                      raw_string_ostream &OS,
@@ -1060,8 +1075,8 @@ static void PrintDxilSignature(LPCSTR pName,
   OS << comment << "\n"
      << comment << " " << pName << " signature:\n"
      << comment << "\n"
-     << comment << " Name                 Index             InterpMode\n"
-     << comment << " -------------------- ----- ----------------------\n";
+     << comment << " Name                 Index             InterpMode DynIdx\n"
+     << comment << " -------------------- ----- ---------------------- ------\n";
 
   for (auto &sigElt : sigElts) {
     OS << comment << " ";
@@ -1070,6 +1085,8 @@ static void PrintDxilSignature(LPCSTR pName,
     OS << ' ' << format("%5u", sigElt->GetSemanticIndexVec()[0]);
     sigElt->GetInterpolationMode()->GetName();
     OS << ' ' << right_justify(sigElt->GetInterpolationMode()->GetName(), 22);
+    OS << "   ";
+    PintCompMaskNameCompact(OS, sigElt->GetDynIdxCompMask());
     OS << "\n";
   }
 }
@@ -1219,6 +1236,69 @@ static void PrintResourceBindings(DxilModule &M, raw_string_ostream &OS, StringR
   OS << comment << "\n";
 }
 
+static void PrintOutputsDependentOnViewId(llvm::raw_ostream &OS,
+                                          llvm::StringRef comment,
+                                          llvm::StringRef SetName,
+                                          unsigned NumOutputs,
+                                          const DxilViewIdState::OutputsDependentOnViewIdType &OutputsDependentOnViewId) {
+  OS << comment << " " << SetName << " dependent on ViewId: { ";
+  bool bFirst = true;
+  for (unsigned i = 0; i < NumOutputs; i++) {
+    if (OutputsDependentOnViewId[i]) {
+      if (!bFirst) OS << ", ";
+      OS << i;
+      bFirst = false;
+    }
+  }
+  OS << " }\n";
+}
+
+static void PrintInputsContributingToOutputs(llvm::raw_ostream &OS,
+                                             llvm::StringRef comment,
+                                             llvm::StringRef InputSetName,
+                                             llvm::StringRef OutputSetName,
+                                             const DxilViewIdState::InputsContributingToOutputType &InputsContributingToOutputs) {
+  OS << comment << " " << InputSetName << " contributing to computation of " << OutputSetName << ":\n";
+  for (auto &it : InputsContributingToOutputs) {
+    unsigned outIdx = it.first;
+    auto &Inputs = it.second;
+    OS << comment << "   output " << outIdx << " depends on inputs: { ";
+    bool bFirst = true;
+    for (unsigned i : Inputs) {
+      if (!bFirst) OS << ", ";
+      OS << i;
+      bFirst = false;
+    }
+    OS << " }\n";
+  }
+}
+
+static void PrintViewIdState(DxilModule &M, raw_string_ostream &OS, StringRef comment) {
+  if (!M.GetModule()->getNamedMetadata("dx.viewIdState")) 
+    return;
+
+  const ShaderModel *pSM = M.GetShaderModel();
+  DxilViewIdState &VID = M.GetViewIdState();
+  OS << comment << "\n";
+  OS << comment << " ViewId state:\n";
+  OS << comment << "\n";
+  OS << comment << " Number of inputs: " << VID.getNumInputSigScalars()  << 
+                           ", outputs: " << VID.getNumOutputSigScalars() << 
+                        ", patchconst: " << VID.getNumPCSigScalars()     << "\n";
+  PrintOutputsDependentOnViewId(OS, comment, "Outputs", VID.getNumOutputSigScalars(), VID.getOutputsDependentOnViewId());
+  if (pSM->IsHS()) {
+    PrintOutputsDependentOnViewId(OS, comment, "PCOutputs", VID.getNumPCSigScalars(), VID.getPCOutputsDependentOnViewId());
+  }
+
+  PrintInputsContributingToOutputs(OS, comment, "Inputs", "Outputs", VID.getInputsContributingToOutputs());
+  if (pSM->IsHS()) {
+    PrintInputsContributingToOutputs(OS, comment, "Inputs", "PCOutputs", VID.getInputsContributingToPCOutputs());
+  } else if (pSM->IsDS()) {
+    PrintInputsContributingToOutputs(OS, comment, "PCInputs", "Outputs", VID.getPCInputsContributingToOutputs());
+  }
+  OS << comment << "\n";
+}
+
 static void PrintStructLayout(StructType *ST, DxilTypeSystem &typeSys,
                               raw_string_ostream &OS, StringRef comment,
                               StringRef varName, unsigned offset, unsigned indent, unsigned arraySize, unsigned sizeOfStruct=0);
@@ -2661,6 +2741,7 @@ public:
                                  /*comment*/ ";");
         PrintBufferDefinitions(dxilModule, Stream, /*comment*/ ";");
         PrintResourceBindings(dxilModule, Stream, /*comment*/ ";");
+        PrintViewIdState(dxilModule, Stream, /*comment*/ ";");
       }
       DxcAssemblyAnnotationWriter w;
       pModule.get()->print(Stream, &w);

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

@@ -44,6 +44,7 @@ target_link_libraries(clang-hlsl-tests PRIVATE
   ${TAEF_LIBRARIES}
   ${DIASDK_LIBRARIES}
   ${D3D12_LIBRARIES}
+  LLVMipa
   )
 
 # Add includes for platform helpers and dxc API.