Browse Source

Lower createHandelForLib.
TODO: fix nonUniform, resource array fails and remove LinkInfo.

Xiang Li 7 years ago
parent
commit
dc3ad5efe5

+ 2 - 0
include/dxc/HLSL/DxilGenerationPass.h

@@ -44,6 +44,7 @@ namespace llvm {
 /// \brief Create and return a pass that tranform the module into a DXIL module
 /// Note that this pass is designed for use with the legacy pass manager.
 ModulePass *createDxilCondenseResourcesPass();
+ModulePass *createDxilLowerCreateHandleForLibPass();
 ModulePass *createDxilEliminateOutputDynamicIndexingPass();
 ModulePass *createDxilGenerationPass(bool NotOptimized, hlsl::HLSLExtensionsCodegenHelper *extensionsHelper);
 ModulePass *createHLEmitMetadataPass();
@@ -68,6 +69,7 @@ ModulePass *createPausePassesPass();
 ModulePass *createResumePassesPass();
 
 void initializeDxilCondenseResourcesPass(llvm::PassRegistry&);
+void initializeDxilLowerCreateHandleForLibPass(llvm::PassRegistry&);
 void initializeDxilEliminateOutputDynamicIndexingPass(llvm::PassRegistry&);
 void initializeDxilGenerationPassPass(llvm::PassRegistry&);
 void initializeHLEnsureMetadataPass(llvm::PassRegistry&);

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

@@ -113,6 +113,7 @@ public:
   void LoadDxilSamplerFromMDNode(llvm::MDNode *MD, DxilSampler &S);
 
   void RemoveUnusedResources();
+  void RemoveUnusedResourceSymbols();
   void RemoveFunction(llvm::Function *F);
 
   // Signatures.

+ 12 - 1
include/dxc/HLSL/DxilUtil.h

@@ -37,7 +37,18 @@ namespace dxilutil {
   bool IsSharedMemoryGlobal(llvm::GlobalVariable *GV);
   bool RemoveUnusedFunctions(llvm::Module &M, llvm::Function *EntryFunc,
                              llvm::Function *PatchConstantFunc, bool IsLib);
-
+  void EmitResMappingError(llvm::Instruction *Res);
+  // Change select/phi on operands into select/phi on operation.
+  // phi0 = phi a0, b0, c0
+  // phi1 = phi a1, b1, c1
+  // Inst = Add(phi0, phi1);
+  // into
+  // A = Add(a0, a1);
+  // B = Add(b0, b1);
+  // C = Add(c0, c1);
+  // NewInst = phi A, B, C
+  // Only support 1 operand now, other oerands should be Constant.
+  llvm::Value * SelectOnOperation(llvm::Instruction *Inst, unsigned operandIdx);
   std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
     llvm::LLVMContext &Ctx, std::string &DiagStr);
   std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::MemoryBuffer *MB,

+ 1 - 0
lib/HLSL/DxcOptimizer.cpp

@@ -100,6 +100,7 @@ HRESULT SetupRegistryPassForHLSL() {
     initializeDxilLegalizeSampleOffsetPassPass(Registry);
     initializeDxilLegalizeStaticResourceUsePassPass(Registry);
     initializeDxilLoadMetadataPass(Registry);
+    initializeDxilLowerCreateHandleForLibPass(Registry);
     initializeDxilOutputColorBecomesConstantPass(Registry);
     initializeDxilPrecisePropagatePassPass(Registry);
     initializeDxilPreserveAllOutputsPass(Registry);

+ 1132 - 173
lib/HLSL/DxilCondenseResources.cpp

@@ -17,12 +17,15 @@
 #include "dxc/HLSL/DxilTypeSystem.h"
 #include "dxc/HLSL/DxilInstructions.h"
 #include "dxc/HLSL/DxilSpanAllocator.h"
+#include "dxc/HLSL/HLMatrixLowerHelper.h"
+#include "dxc/HLSL/DxilUtil.h"
 
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/PassManager.h"
+#include "llvm/IR/DebugInfo.h"
 #include "llvm/ADT/BitVector.h"
 #include "llvm/Pass.h"
 #include "llvm/Transforms/Utils/Local.h"
@@ -32,14 +35,19 @@
 using namespace llvm;
 using namespace hlsl;
 
+// Resource rangeID remap.
+namespace {
 struct ResourceID {
-  DXIL::ResourceClass Class;  // Resource class.
-  unsigned ID;                // Resource ID, as specified on entry.
-
-  bool operator<(const ResourceID& other) const {
-    if (Class < other.Class) return true;
-    if (Class > other.Class) return false;
-    if (ID < other.ID) return true;
+  DXIL::ResourceClass Class; // Resource class.
+  unsigned ID;               // Resource ID, as specified on entry.
+
+  bool operator<(const ResourceID &other) const {
+    if (Class < other.Class)
+      return true;
+    if (Class > other.Class)
+      return false;
+    if (ID < other.ID)
+      return true;
     return false;
   }
 };
@@ -47,11 +55,128 @@ struct ResourceID {
 struct RemapEntry {
   ResourceID ResID;           // Resource identity, as specified on entry.
   DxilResourceBase *Resource; // In-memory resource representation.
-  unsigned Index;             // Index in resource vector - new ID for the resource.
+  unsigned Index; // Index in resource vector - new ID for the resource.
 };
 
 typedef std::map<ResourceID, RemapEntry> RemapEntryCollection;
 
+template <typename TResource>
+void BuildRewrites(const std::vector<std::unique_ptr<TResource>> &Rs,
+                   RemapEntryCollection &C) {
+  const unsigned s = (unsigned)Rs.size();
+  for (unsigned i = 0; i < s; ++i) {
+    const std::unique_ptr<TResource> &R = Rs[i];
+    if (R->GetID() != i) {
+      ResourceID RId = {R->GetClass(), R->GetID()};
+      RemapEntry RE = {RId, R.get(), i};
+      C[RId] = RE;
+    }
+  }
+}
+
+// Build m_rewrites, returns 'true' if any rewrites are needed.
+bool BuildRewriteMap(RemapEntryCollection &rewrites, DxilModule &DM) {
+  BuildRewrites(DM.GetCBuffers(), rewrites);
+  BuildRewrites(DM.GetSRVs(), rewrites);
+  BuildRewrites(DM.GetUAVs(), rewrites);
+  BuildRewrites(DM.GetSamplers(), rewrites);
+
+  return !rewrites.empty();
+}
+
+void ApplyRewriteMapOnResTable(RemapEntryCollection &rewrites, DxilModule &DM) {
+  for (auto &entry : rewrites) {
+    entry.second.Resource->SetID(entry.second.Index);
+  }
+}
+
+} // namespace
+
+// Resource lowerBound allocation.
+namespace {
+
+template <typename T>
+static void
+AllocateDxilResource(const std::vector<std::unique_ptr<T>> &resourceList,
+                     LLVMContext &Ctx) {
+  SpacesAllocator<unsigned, T> SAlloc;
+
+  for (auto &res : resourceList) {
+    const unsigned space = res->GetSpaceID();
+    typename SpacesAllocator<unsigned, T>::Allocator &alloc = SAlloc.Get(space);
+
+    if (res->IsAllocated()) {
+      const unsigned reg = res->GetLowerBound();
+      const T *conflict = nullptr;
+      if (res->IsUnbounded()) {
+        const T *unbounded = alloc.GetUnbounded();
+        if (unbounded) {
+          Ctx.emitError(Twine("more than one unbounded resource (") +
+                        unbounded->GetGlobalName() + (" and ") +
+                        res->GetGlobalName() + (") in space ") + Twine(space));
+        } else {
+          conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
+          if (!conflict)
+            alloc.SetUnbounded(res.get());
+        }
+      } else {
+        conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
+      }
+      if (conflict) {
+        Ctx.emitError(((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
+                      Twine("resource ") + res->GetGlobalName() +
+                      Twine(" at register ") + Twine(reg) +
+                      Twine(" overlaps with resource ") +
+                      conflict->GetGlobalName() + Twine(" at register ") +
+                      Twine(conflict->GetLowerBound()) + Twine(", space ") +
+                      Twine(space));
+      }
+    }
+  }
+
+  // Allocate.
+  const unsigned space = 0;
+  typename SpacesAllocator<unsigned, T>::Allocator &alloc0 = SAlloc.Get(space);
+  for (auto &res : resourceList) {
+    if (!res->IsAllocated()) {
+      DXASSERT(res->GetSpaceID() == 0,
+               "otherwise non-zero space has no user register assignment");
+      unsigned reg = 0;
+      bool success = false;
+      if (res->IsUnbounded()) {
+        const T *unbounded = alloc0.GetUnbounded();
+        if (unbounded) {
+          Ctx.emitError(Twine("more than one unbounded resource (") +
+                        unbounded->GetGlobalName() + Twine(" and ") +
+                        res->GetGlobalName() + Twine(") in space ") +
+                        Twine(space));
+        } else {
+          success = alloc0.AllocateUnbounded(res.get(), reg);
+          if (success)
+            alloc0.SetUnbounded(res.get());
+        }
+      } else {
+        success = alloc0.Allocate(res.get(), res->GetRangeSize(), reg);
+      }
+      if (success) {
+        res->SetLowerBound(reg);
+      } else {
+        Ctx.emitError(((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
+                      Twine("resource ") + res->GetGlobalName() +
+                      Twine(" could not be allocated"));
+      }
+    }
+  }
+}
+
+void AllocateDxilResources(DxilModule &DM) {
+  AllocateDxilResource(DM.GetCBuffers(), DM.GetCtx());
+  AllocateDxilResource(DM.GetSamplers(), DM.GetCtx());
+  AllocateDxilResource(DM.GetUAVs(), DM.GetCtx());
+  AllocateDxilResource(DM.GetSRVs(), DM.GetCtx());
+}
+} // namespace
+
 class DxilCondenseResources : public ModulePass {
 private:
   RemapEntryCollection m_rewrites;
@@ -65,15 +190,11 @@ public:
   bool runOnModule(Module &M) override {
     DxilModule &DM = M.GetOrCreateDxilModule();
 
-    // Switch tbuffers to SRVs, as they have been treated as cbuffers up to this point.
-    if (DM.GetCBuffers().size())
-      PatchTBuffers(DM);
-
     // Remove unused resource.
     DM.RemoveUnusedResources();
 
     // Make sure all resource types are dense; build a map of rewrites.
-    if (BuildRewriteMap(DM)) {
+    if (BuildRewriteMap(m_rewrites, DM)) {
       // Rewrite all instructions that refer to resources in the map.
       ApplyRewriteMap(DM);
     }
@@ -92,9 +213,6 @@ public:
     return true;
   }
 
-  // Build m_rewrites, returns 'true' if any rewrites are needed.
-  bool BuildRewriteMap(DxilModule &DM);
-
   DxilResourceBase &GetFirstRewrite() const {
     DXASSERT_NOMSG(!m_rewrites.empty());
     return *m_rewrites.begin()->second.Resource;
@@ -102,13 +220,10 @@ public:
 
 private:
   void ApplyRewriteMap(DxilModule &DM);
-  void AllocateDxilResources(DxilModule &DM);
   // Add lowbound to create handle range index.
   void PatchCreateHandle(DxilModule &DM);
   // Add lowbound to create handle range index for library.
   void PatchCreateHandleForLib(DxilModule &DM);
-  // Switch CBuffer for SRV for TBuffers.
-  void PatchTBuffers(DxilModule &DM);
 };
 
 void DxilCondenseResources::ApplyRewriteMap(DxilModule &DM) {
@@ -139,111 +254,11 @@ void DxilCondenseResources::ApplyRewriteMap(DxilModule &DM) {
     }
   }
 
-  for (auto &entry : m_rewrites) {
-    entry.second.Resource->SetID(entry.second.Index);
-  }
-}
-
-template <typename TResource>
-static void BuildRewrites(const std::vector<std::unique_ptr<TResource>> &Rs,
-                          RemapEntryCollection &C) {
-  const unsigned s = (unsigned)Rs.size();
-  for (unsigned i = 0; i < s; ++i) {
-    const std::unique_ptr<TResource> &R = Rs[i];
-    if (R->GetID() != i) {
-      ResourceID RId = {R->GetClass(), R->GetID()};
-      RemapEntry RE = {RId, R.get(), i};
-      C[RId] = RE;
-    }
-  }
-}
-
-bool DxilCondenseResources::BuildRewriteMap(DxilModule &DM) {
-  BuildRewrites(DM.GetCBuffers(), m_rewrites);
-  BuildRewrites(DM.GetSRVs(), m_rewrites);
-  BuildRewrites(DM.GetUAVs(), m_rewrites);
-  BuildRewrites(DM.GetSamplers(), m_rewrites);
-
-  return !m_rewrites.empty();
+  ApplyRewriteMapOnResTable(m_rewrites, DM);
 }
 
 namespace {
 
-template<typename T>
-static void AllocateDxilResource(const std::vector<std::unique_ptr<T> > &resourceList, LLVMContext &Ctx) {
-  SpacesAllocator<unsigned, T> SAlloc;
-
-  for (auto &res : resourceList) {
-    const unsigned space = res->GetSpaceID();
-    typename SpacesAllocator<unsigned, T>::Allocator &alloc = SAlloc.Get(space);
-
-    if (res->IsAllocated()) {
-      const unsigned reg = res->GetLowerBound();
-      const T *conflict = nullptr;
-      if (res->IsUnbounded()) {
-        const T *unbounded = alloc.GetUnbounded();
-        if (unbounded) {
-          Ctx.emitError(
-            Twine("more than one unbounded resource (") +
-            unbounded->GetGlobalName() +
-            (" and ") + res->GetGlobalName() +
-            (") in space ") + Twine(space));
-        } else {
-          conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
-          if (!conflict)
-            alloc.SetUnbounded(res.get());
-        }
-      } else {
-        conflict = alloc.Insert(res.get(), reg, res->GetUpperBound());
-      }
-      if (conflict) {
-        Ctx.emitError(
-          ((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
-          Twine("resource ") + res->GetGlobalName() +
-          Twine(" at register ") + Twine(reg) +
-          Twine(" overlaps with resource ") + conflict->GetGlobalName() +
-          Twine(" at register ") + Twine(conflict->GetLowerBound()) +
-          Twine(", space ") + Twine(space));
-      }
-    }
-  }
-
-  // Allocate.
-  const unsigned space = 0;
-  typename SpacesAllocator<unsigned, T>::Allocator &alloc0 = SAlloc.Get(space);
-  for (auto &res : resourceList) {
-    if (!res->IsAllocated()) {
-      DXASSERT(res->GetSpaceID() == 0, "otherwise non-zero space has no user register assignment");
-      unsigned reg = 0;
-      bool success = false;
-      if (res->IsUnbounded()) {
-        const T *unbounded = alloc0.GetUnbounded();
-        if (unbounded) {
-          Ctx.emitError(
-            Twine("more than one unbounded resource (") +
-            unbounded->GetGlobalName() +
-            Twine(" and ") + res->GetGlobalName() +
-            Twine(") in space ") + Twine(space));
-        } else {
-          success = alloc0.AllocateUnbounded(res.get(), reg);
-          if (success)
-            alloc0.SetUnbounded(res.get());
-        }
-      } else {
-        success = alloc0.Allocate(res.get(), res->GetRangeSize(), reg);
-      }
-      if (success) {
-        res->SetLowerBound(reg);
-      } else {
-        Ctx.emitError(
-          ((res->IsUnbounded()) ? Twine("unbounded ") : Twine("")) +
-          Twine("resource ") + res->GetGlobalName() +
-          Twine(" could not be allocated"));
-      }
-    }
-  }
-}
-
 void PatchLowerBoundOfCreateHandle(CallInst *handle, DxilModule &DM) {
   DxilInst_CreateHandle createHandle(handle);
   DXASSERT_NOMSG(createHandle);
@@ -397,56 +412,6 @@ static void PatchTBufferCreateHandle(CallInst *handle, DxilModule &DM, std::unor
 
 }
 
-
-void DxilCondenseResources::AllocateDxilResources(DxilModule &DM) {
-  AllocateDxilResource(DM.GetCBuffers(), DM.GetCtx());
-  AllocateDxilResource(DM.GetSamplers(), DM.GetCtx());
-  AllocateDxilResource(DM.GetUAVs(), DM.GetCtx());
-  AllocateDxilResource(DM.GetSRVs(), DM.GetCtx());
-}
-
-void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) {
-  pDest->SetKind(pSource->GetKind());
-  pDest->SetCompType(DXIL::ComponentType::U32);
-  pDest->SetSampleCount(0);
-  pDest->SetElementStride(0);
-  pDest->SetGloballyCoherent(false);
-  pDest->SetHasCounter(false);
-  pDest->SetRW(false);
-  pDest->SetROV(false);
-  pDest->SetID(pSource->GetID());
-  pDest->SetSpaceID(pSource->GetSpaceID());
-  pDest->SetLowerBound(pSource->GetLowerBound());
-  pDest->SetRangeSize(pSource->GetRangeSize());
-  pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
-  pDest->SetGlobalName(pSource->GetGlobalName());
-  pDest->SetHandle(pSource->GetHandle());
-}
-
-void DxilCondenseResources::PatchTBuffers(DxilModule &DM) {
-  Function *createHandle = DM.GetOP()->GetOpFunc(DXIL::OpCode::CreateHandle,
-                                                 Type::getVoidTy(DM.GetCtx()));
-
-  std::unordered_set<unsigned> tbufferIDs;
-  for (User *U : createHandle->users()) {
-    PatchTBufferCreateHandle(cast<CallInst>(U), DM, tbufferIDs);
-  }
-
-  // move tbuffer resources to SRVs
-  unsigned offset = DM.GetSRVs().size();
-  for (auto it = DM.GetCBuffers().begin(); it != DM.GetCBuffers().end(); it++) {
-    DxilCBuffer *CB = it->get();
-    unsigned resID = CB->GetID();
-    if (tbufferIDs.find(resID) != tbufferIDs.end()) {
-      auto srv = make_unique<DxilResource>();
-      InitTBuffer(CB, srv.get());
-      srv->SetID(resID + offset);
-      DM.AddSRV(std::move(srv));
-      // cbuffer should get cleaned up since it's now unused.
-    }
-  }
-}
-
 void DxilCondenseResources::PatchCreateHandle(DxilModule &DM) {
   Function *createHandle = DM.GetOP()->GetOpFunc(DXIL::OpCode::CreateHandle,
                                                  Type::getVoidTy(DM.GetCtx()));
@@ -554,9 +519,9 @@ char DxilCondenseResources::ID = 0;
 
 bool llvm::AreDxilResourcesDense(llvm::Module *M, hlsl::DxilResourceBase **ppNonDense) {
   DxilModule &DM = M->GetOrCreateDxilModule();
-  DxilCondenseResources Pass;
-  if (Pass.BuildRewriteMap(DM)) {
-    *ppNonDense = &Pass.GetFirstRewrite();
+  RemapEntryCollection rewrites;
+  if (BuildRewriteMap(rewrites, DM)) {
+    *ppNonDense = rewrites.begin()->second.Resource;
     return false;
   }
   else {
@@ -570,3 +535,997 @@ ModulePass *llvm::createDxilCondenseResourcesPass() {
 }
 
 INITIALIZE_PASS(DxilCondenseResources, "hlsl-dxil-condense", "DXIL Condense Resources", false, false)
+
+namespace {
+class DxilLowerCreateHandleForLib : public ModulePass {
+private:
+  RemapEntryCollection m_rewrites;
+  DxilModule *m_DM;
+  bool m_HasDbgInfo;
+  bool m_bIsLib;
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+  explicit DxilLowerCreateHandleForLib() : ModulePass(ID) {}
+
+  const char *getPassName() const override {
+    return "DXIL Lower createHandleForLib";
+  }
+
+  bool runOnModule(Module &M) override {
+    DxilModule &DM = M.GetOrCreateDxilModule();
+    m_DM = &DM;
+    m_bIsLib = DM.GetShaderModel()->IsLib();
+
+    // Switch tbuffers to SRVs, as they have been treated as cbuffers up to this
+    // point.
+    if (DM.GetCBuffers().size())
+      PatchTBuffers(DM);
+
+    // Remove unused resource.
+    DM.RemoveUnusedResourceSymbols();
+
+    bool hasResource = DM.GetCBuffers().size() || DM.GetUAVs().size() ||
+                       DM.GetSRVs().size() || DM.GetSamplers().size();
+
+    // TODO: remove this.
+    // Create resoure link info for lib.
+    if (hasResource && m_bIsLib)
+      DM.CreateResourceLinkInfo();
+
+    if (!hasResource || m_bIsLib)
+      return false;
+
+    BuildRewriteMap(m_rewrites, DM);
+    ApplyRewriteMapOnResTable(m_rewrites, DM);
+
+    // Load up debug information, to cross-reference values and the instructions
+    // used to load them.
+    m_HasDbgInfo = getDebugMetadataVersionFromModule(M) != 0;
+
+    AllocateDxilResources(DM);
+
+    GenerateDxilCBufferHandles();
+    GenerateDxilResourceHandles();
+    AddCreateHandleForPhiNodeAndSelect(DM.GetOP());
+
+    if (DM.GetOP()->UseMinPrecision())
+      UpdateStructTypeForLegacyLayout();
+    // Change resource symbol into undef.
+    UpdateResourceSymbols();
+
+    return true;
+  }
+
+private:
+  void UpdateResourceSymbols();
+  void TranslateDxilResourceUses(DxilResourceBase &res);
+  void GenerateDxilResourceHandles();
+  void AddCreateHandleForPhiNodeAndSelect(OP *hlslOP);
+  // Generate DXIL cbuffer handles.
+  void GenerateDxilCBufferHandles();
+  void UpdateStructTypeForLegacyLayout();
+  // Switch CBuffer for SRV for TBuffers.
+  void PatchTBuffers(DxilModule &DM);
+  void PatchTBufferUse(Value *V, DxilModule &DM);
+};
+
+// LegacyLayout.
+namespace {
+
+StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
+                                            DxilTypeSystem &TypeSys, Module &M);
+
+Type *UpdateFieldTypeForLegacyLayout(Type *Ty, bool IsCBuf,
+                                     DxilFieldAnnotation &annotation,
+                                     DxilTypeSystem &TypeSys, Module &M) {
+  DXASSERT(!Ty->isPointerTy(), "struct field should not be a pointer");
+
+  if (Ty->isArrayTy()) {
+    Type *EltTy = Ty->getArrayElementType();
+    Type *UpdatedTy =
+        UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
+    if (EltTy == UpdatedTy)
+      return Ty;
+    else
+      return ArrayType::get(UpdatedTy, Ty->getArrayNumElements());
+  } else if (HLMatrixLower::IsMatrixType(Ty)) {
+    DXASSERT(annotation.HasMatrixAnnotation(), "must a matrix");
+    unsigned rows, cols;
+    Type *EltTy = HLMatrixLower::GetMatrixInfo(Ty, cols, rows);
+
+    // Get cols and rows from annotation.
+    const DxilMatrixAnnotation &matrix = annotation.GetMatrixAnnotation();
+    if (matrix.Orientation == MatrixOrientation::RowMajor) {
+      rows = matrix.Rows;
+      cols = matrix.Cols;
+    } else {
+      DXASSERT(matrix.Orientation == MatrixOrientation::ColumnMajor, "");
+      cols = matrix.Rows;
+      rows = matrix.Cols;
+    }
+    // CBuffer matrix must 4 * 4 bytes align.
+    if (IsCBuf)
+      cols = 4;
+
+    EltTy =
+        UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
+    Type *rowTy = VectorType::get(EltTy, cols);
+    return ArrayType::get(rowTy, rows);
+  } else if (StructType *ST = dyn_cast<StructType>(Ty)) {
+    return UpdateStructTypeForLegacyLayout(ST, IsCBuf, TypeSys, M);
+  } else if (Ty->isVectorTy()) {
+    Type *EltTy = Ty->getVectorElementType();
+    Type *UpdatedTy =
+        UpdateFieldTypeForLegacyLayout(EltTy, IsCBuf, annotation, TypeSys, M);
+    if (EltTy == UpdatedTy)
+      return Ty;
+    else
+      return VectorType::get(UpdatedTy, Ty->getVectorNumElements());
+  } else {
+    Type *i32Ty = Type::getInt32Ty(Ty->getContext());
+    // Basic types.
+    if (Ty->isHalfTy()) {
+      return Type::getFloatTy(Ty->getContext());
+    } else if (IntegerType *ITy = dyn_cast<IntegerType>(Ty)) {
+      if (ITy->getBitWidth() < 32)
+        return i32Ty;
+      else
+        return Ty;
+    } else
+      return Ty;
+  }
+}
+
+StructType *UpdateStructTypeForLegacyLayout(StructType *ST, bool IsCBuf,
+                                            DxilTypeSystem &TypeSys,
+                                            Module &M) {
+  bool bUpdated = false;
+  unsigned fieldsCount = ST->getNumElements();
+  std::vector<Type *> fieldTypes(fieldsCount);
+  DxilStructAnnotation *SA = TypeSys.GetStructAnnotation(ST);
+  DXASSERT(SA, "must have annotation for struct type");
+
+  for (unsigned i = 0; i < fieldsCount; i++) {
+    Type *EltTy = ST->getElementType(i);
+    Type *UpdatedTy = UpdateFieldTypeForLegacyLayout(
+        EltTy, IsCBuf, SA->GetFieldAnnotation(i), TypeSys, M);
+    fieldTypes[i] = UpdatedTy;
+    if (EltTy != UpdatedTy)
+      bUpdated = true;
+  }
+
+  if (!bUpdated) {
+    return ST;
+  } else {
+    std::string legacyName = "dx.alignment.legacy." + ST->getName().str();
+    if (StructType *legacyST = M.getTypeByName(legacyName))
+      return legacyST;
+
+    StructType *NewST =
+        StructType::create(ST->getContext(), fieldTypes, legacyName);
+    DxilStructAnnotation *NewSA = TypeSys.AddStructAnnotation(NewST);
+    // Clone annotation.
+    *NewSA = *SA;
+    return NewST;
+  }
+}
+
+void UpdateStructTypeForLegacyLayout(DxilResourceBase &Res,
+                                     DxilTypeSystem &TypeSys, Module &M) {
+  GlobalVariable *GV = cast<GlobalVariable>(Res.GetGlobalSymbol());
+  Type *Ty = GV->getType()->getPointerElementType();
+  bool IsResourceArray = Res.GetRangeSize() != 1;
+  if (IsResourceArray) {
+    // Support Array of struct buffer.
+    if (Ty->isArrayTy())
+      Ty = Ty->getArrayElementType();
+  }
+  StructType *ST = cast<StructType>(Ty);
+  if (ST->isOpaque()) {
+    DXASSERT(Res.GetClass() == DxilResourceBase::Class::CBuffer,
+             "Only cbuffer can have opaque struct.");
+    return;
+  }
+
+  Type *UpdatedST =
+      UpdateStructTypeForLegacyLayout(ST, IsResourceArray, TypeSys, M);
+  if (ST != UpdatedST) {
+    Type *Ty = GV->getType()->getPointerElementType();
+    if (IsResourceArray) {
+      // Support Array of struct buffer.
+      if (Ty->isArrayTy()) {
+        UpdatedST = ArrayType::get(UpdatedST, Ty->getArrayNumElements());
+      }
+    }
+    GlobalVariable *NewGV = cast<GlobalVariable>(
+        M.getOrInsertGlobal(GV->getName().str() + "_legacy", UpdatedST));
+    Res.SetGlobalSymbol(NewGV);
+    // Delete old GV.
+    for (auto UserIt = GV->user_begin(); UserIt != GV->user_end();) {
+      Value *User = *(UserIt++);
+      if (Instruction *I = dyn_cast<Instruction>(User)) {
+        if (!User->user_empty())
+          I->replaceAllUsesWith(UndefValue::get(I->getType()));
+
+        I->eraseFromParent();
+      } else {
+        ConstantExpr *CE = cast<ConstantExpr>(User);
+        if (!CE->user_empty())
+          CE->replaceAllUsesWith(UndefValue::get(CE->getType()));
+      }
+    }
+    GV->removeDeadConstantUsers();
+    GV->eraseFromParent();
+  }
+}
+
+void UpdateStructTypeForLegacyLayoutOnDM(DxilModule &DM) {
+  DxilTypeSystem &TypeSys = DM.GetTypeSystem();
+  Module &M = *DM.GetModule();
+  for (auto &CBuf : DM.GetCBuffers()) {
+    UpdateStructTypeForLegacyLayout(*CBuf.get(), TypeSys, M);
+  }
+
+  for (auto &UAV : DM.GetUAVs()) {
+    if (UAV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
+      UpdateStructTypeForLegacyLayout(*UAV.get(), TypeSys, M);
+  }
+
+  for (auto &SRV : DM.GetSRVs()) {
+    if (SRV->GetKind() == DxilResourceBase::Kind::StructuredBuffer)
+      UpdateStructTypeForLegacyLayout(*SRV.get(), TypeSys, M);
+  }
+}
+
+} // namespace
+
+void DxilLowerCreateHandleForLib::UpdateStructTypeForLegacyLayout() {
+  UpdateStructTypeForLegacyLayoutOnDM(*m_DM);
+}
+
+// Change ResourceSymbol to undef if don't need.
+void DxilLowerCreateHandleForLib::UpdateResourceSymbols() {
+  std::vector<GlobalVariable *> &LLVMUsed = m_DM->GetLLVMUsed();
+
+  auto UpdateResourceSymbol = [&LLVMUsed, this](DxilResourceBase *res) {
+    GlobalVariable *GV = cast<GlobalVariable>(res->GetGlobalSymbol());
+    GV->removeDeadConstantUsers();
+    DXASSERT(GV->user_empty(), "else resource not lowered");
+    Type *Ty = GV->getType();
+    res->SetGlobalSymbol(UndefValue::get(Ty));
+    if (m_HasDbgInfo)
+      LLVMUsed.emplace_back(GV);
+
+    res->SetGlobalSymbol(UndefValue::get(Ty));
+  };
+
+  for (auto &&C : m_DM->GetCBuffers()) {
+    UpdateResourceSymbol(C.get());
+  }
+  for (auto &&Srv : m_DM->GetSRVs()) {
+    UpdateResourceSymbol(Srv.get());
+  }
+  for (auto &&Uav : m_DM->GetUAVs()) {
+    UpdateResourceSymbol(Uav.get());
+  }
+  for (auto &&S : m_DM->GetSamplers()) {
+    UpdateResourceSymbol(S.get());
+  }
+}
+
+// Lower createHandleForLib
+namespace {
+
+void ReplaceResourceUserWithHandle(LoadInst *Res, Value *handle) {
+  for (auto resUser = Res->user_begin(); resUser != Res->user_end();) {
+    CallInst *CI = dyn_cast<CallInst>(*(resUser++));
+    DxilInst_CreateHandleFromResourceStructForLib createHandle(CI);
+
+    DXASSERT(createHandle, "must be createHandle");
+    CI->replaceAllUsesWith(handle);
+    CI->eraseFromParent();
+  }
+  Res->eraseFromParent();
+}
+
+DIGlobalVariable *FindGlobalVariableDebugInfo(GlobalVariable *GV,
+                                              DebugInfoFinder &DbgInfoFinder) {
+  struct GlobalFinder {
+    GlobalVariable *GV;
+    bool operator()(llvm::DIGlobalVariable *const arg) const {
+      return arg->getVariable() == GV;
+    }
+  };
+  GlobalFinder F = {GV};
+  DebugInfoFinder::global_variable_iterator Found =
+      std::find_if(DbgInfoFinder.global_variables().begin(),
+                   DbgInfoFinder.global_variables().end(), F);
+  if (Found != DbgInfoFinder.global_variables().end()) {
+    return *Found;
+  }
+  return nullptr;
+}
+} // namespace
+void DxilLowerCreateHandleForLib::TranslateDxilResourceUses(
+    DxilResourceBase &res) {
+  OP *hlslOP = m_DM->GetOP();
+  Function *createHandle = hlslOP->GetOpFunc(
+      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_DM->GetCtx()));
+  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
+  bool isViewResource = res.GetClass() == DXIL::ResourceClass::SRV ||
+                        res.GetClass() == DXIL::ResourceClass::UAV;
+  bool isROV = isViewResource && static_cast<DxilResource &>(res).IsROV();
+  std::string handleName =
+      (res.GetGlobalName() + Twine("_") + Twine(res.GetResClassName())).str();
+  if (isViewResource)
+    handleName += (Twine("_") + Twine(res.GetResDimName())).str();
+  if (isROV)
+    handleName += "_ROV";
+
+  Value *resClassArg = hlslOP->GetU8Const(
+      static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
+          res.GetClass()));
+  Value *resIDArg = hlslOP->GetU32Const(res.GetID());
+  // resLowerBound will be added after allocation in DxilCondenseResources.
+  Value *resLowerBound = hlslOP->GetU32Const(res.GetLowerBound());
+  // TODO: Set Non-uniform resource bit based on whether index comes from
+  // IOP_NonUniformResourceIndex.
+  Value *isUniformRes = hlslOP->GetI1Const(0);
+
+  Value *GV = res.GetGlobalSymbol();
+  Module *pM = m_DM->GetModule();
+  // TODO: add debug info to create handle.
+  DIVariable *DIV = nullptr;
+  DILocation *DL = nullptr;
+  if (m_HasDbgInfo) {
+    DebugInfoFinder &Finder = m_DM->GetOrCreateDebugInfoFinder();
+    DIV = FindGlobalVariableDebugInfo(cast<GlobalVariable>(GV), Finder);
+    if (DIV)
+      // TODO: how to get col?
+      DL =
+          DILocation::get(pM->getContext(), DIV->getLine(), 1, DIV->getScope());
+  }
+
+  bool isResArray = res.GetRangeSize() > 1;
+  std::unordered_map<Function *, Instruction *> handleMapOnFunction;
+
+  Value *createHandleArgs[] = {opArg, resClassArg, resIDArg, resLowerBound,
+                               isUniformRes};
+
+  for (iplist<Function>::iterator F : pM->getFunctionList()) {
+    if (!F->isDeclaration()) {
+      if (!isResArray) {
+        IRBuilder<> Builder(F->getEntryBlock().getFirstInsertionPt());
+        if (m_HasDbgInfo) {
+          // TODO: set debug info.
+          // Builder.SetCurrentDebugLocation(DL);
+        }
+        handleMapOnFunction[F] =
+            Builder.CreateCall(createHandle, createHandleArgs, handleName);
+      }
+    }
+  }
+
+  for (auto U = GV->user_begin(), E = GV->user_end(); U != E;) {
+    User *user = *(U++);
+    // Skip unused user.
+    if (user->user_empty())
+      continue;
+
+    if (CallInst *CI = dyn_cast<CallInst>(user)) {
+      Function *userF = CI->getParent()->getParent();
+      DXASSERT(handleMapOnFunction.count(userF), "must exist");
+      Value *handle = handleMapOnFunction[userF];
+      CI->replaceAllUsesWith(handle);
+      CI->eraseFromParent();
+    } else {
+      DXASSERT(dyn_cast<GEPOperator>(user) != nullptr,
+               "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
+               "to only have ld/st refer to temp object");
+      GEPOperator *GEP = cast<GEPOperator>(user);
+      Value *idx = nullptr;
+      if (GEP->getNumIndices() == 2) {
+        // one dim array of resource
+        idx = (GEP->idx_begin() + 1)->get();
+      } else {
+        gep_type_iterator GEPIt = gep_type_begin(GEP), E = gep_type_end(GEP);
+        // Must be instruction for multi dim array.
+        std::unique_ptr<IRBuilder<>> Builder;
+        if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
+          Builder = std::make_unique<IRBuilder<>>(GEPInst);
+        } else {
+          Builder = std::make_unique<IRBuilder<>>(GV->getContext());
+        }
+        for (; GEPIt != E; ++GEPIt) {
+          if (GEPIt->isArrayTy()) {
+            unsigned arraySize = GEPIt->getArrayNumElements();
+            Value *tmpIdx = GEPIt.getOperand();
+            if (idx == nullptr)
+              idx = tmpIdx;
+            else {
+              idx = Builder->CreateMul(idx, Builder->getInt32(arraySize));
+              idx = Builder->CreateAdd(idx, tmpIdx);
+            }
+          }
+        }
+      }
+      createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = idx;
+      // if (!NonUniformSet.count(idx))
+      //  createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+      //      isUniformRes;
+      // else
+      //  createHandleArgs[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+      //      hlslOP->GetI1Const(1);
+
+      Value *handle = nullptr;
+      if (GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(GEP)) {
+        IRBuilder<> Builder = IRBuilder<>(GEPInst);
+        createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
+            Builder.CreateAdd(idx, resLowerBound);
+        handle = Builder.CreateCall(createHandle, createHandleArgs, handleName);
+      }
+
+      for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end();
+           GEPU != GEPE;) {
+        // Must be load inst.
+        CallInst *CI = cast<CallInst>(*(GEPU++));
+        if (!handle) {
+          IRBuilder<> Builder = IRBuilder<>(CI);
+          createHandleArgs[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
+              Builder.CreateAdd(idx, resLowerBound);
+          Value *localHandle =
+              Builder.CreateCall(createHandle, createHandleArgs, handleName);
+          CI->replaceAllUsesWith(localHandle);
+        } else {
+          CI->replaceAllUsesWith(handle);
+        }
+        CI->eraseFromParent();
+      }
+
+      if (Instruction *I = dyn_cast<Instruction>(GEP)) {
+        I->eraseFromParent();
+      }
+    }
+  }
+  // Erase unused handle.
+  for (auto It : handleMapOnFunction) {
+    Instruction *I = It.second;
+    if (I->user_empty())
+      I->eraseFromParent();
+  }
+}
+
+void DxilLowerCreateHandleForLib::GenerateDxilResourceHandles() {
+  // Create sampler handle first, may be used by SRV operations.
+  for (size_t i = 0; i < m_DM->GetSamplers().size(); i++) {
+    DxilSampler &S = m_DM->GetSampler(i);
+    TranslateDxilResourceUses(S);
+  }
+
+  for (size_t i = 0; i < m_DM->GetSRVs().size(); i++) {
+    DxilResource &SRV = m_DM->GetSRV(i);
+    TranslateDxilResourceUses(SRV);
+  }
+
+  for (size_t i = 0; i < m_DM->GetUAVs().size(); i++) {
+    DxilResource &UAV = m_DM->GetUAV(i);
+    TranslateDxilResourceUses(UAV);
+  }
+}
+
+void DxilLowerCreateHandleForLib::GenerateDxilCBufferHandles() {
+  // For CBuffer, handle are mapped to HLCreateHandle.
+  OP *hlslOP = m_DM->GetOP();
+  Function *createHandle = hlslOP->GetOpFunc(
+      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_DM->GetCtx()));
+  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
+
+  Value *resClassArg = hlslOP->GetU8Const(
+      static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
+          DXIL::ResourceClass::CBuffer));
+
+  for (size_t i = 0; i < m_DM->GetCBuffers().size(); i++) {
+    DxilCBuffer &CB = m_DM->GetCBuffer(i);
+    GlobalVariable *GV = cast<GlobalVariable>(CB.GetGlobalSymbol());
+    // Remove GEP created in HLObjectOperationLowerHelper::UniformCbPtr.
+    GV->removeDeadConstantUsers();
+    std::string handleName = std::string(GV->getName()) + "_buffer";
+
+    Value *args[] = {opArg, resClassArg, nullptr, nullptr,
+                     hlslOP->GetI1Const(0)};
+    DIVariable *DIV = nullptr;
+    DILocation *DL = nullptr;
+    if (m_HasDbgInfo) {
+      DebugInfoFinder &Finder = m_DM->GetOrCreateDebugInfoFinder();
+      DIV = FindGlobalVariableDebugInfo(GV, Finder);
+      if (DIV)
+        // TODO: how to get col?
+        DL = DILocation::get(createHandle->getContext(), DIV->getLine(), 1,
+                             DIV->getScope());
+    }
+
+    Value *resIDArg = hlslOP->GetU32Const(CB.GetID());
+    args[DXIL::OperandIndex::kCreateHandleResIDOpIdx] = resIDArg;
+
+    // resLowerBound will be added after allocation in DxilCondenseResources.
+    Value *resLowerBound = hlslOP->GetU32Const(CB.GetLowerBound());
+
+    if (CB.GetRangeSize() == 1) {
+      args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = resLowerBound;
+      for (auto U = GV->user_begin(); U != GV->user_end();) {
+        // Must CreateHandleForLib.
+        CallInst *CI = cast<CallInst>(*(U++));
+        DxilInst_CreateHandleFromResourceStructForLib createHandleForLib(CI);
+        // Put createHandle to entry block.
+        auto InsertPt =
+            CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt();
+        IRBuilder<> Builder(InsertPt);
+
+        CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
+        if (m_HasDbgInfo) {
+          // TODO: add debug info.
+          // handle->setDebugLoc(DL);
+        }
+        CI->replaceAllUsesWith(handle);
+        CI->eraseFromParent();
+      }
+    } else {
+      for (auto U = GV->user_begin(); U != GV->user_end();) {
+        // Must GEP
+        GEPOperator *GEP = cast<GEPOperator>(*(U++));
+        DXASSERT(GEP->getNumIndices() == 2, "else invalid cbv array ptr");
+        auto *it = GEP->idx_begin();
+        it++;
+        Value *CBIndex = *it;
+        for (auto GEPU = GEP->user_begin(); GEPU != GEP->user_end();) {
+          CallInst *CI = cast<CallInst>(*(GEPU++));
+          IRBuilder<> Builder(CI);
+          args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
+              Builder.CreateAdd(CBIndex, resLowerBound);
+          if (isa<ConstantInt>(CBIndex)) {
+            // Put createHandle to entry block for const index.
+            auto InsertPt = CI->getParent()
+                                ->getParent()
+                                ->getEntryBlock()
+                                .getFirstInsertionPt();
+            Builder.SetInsertPoint(InsertPt);
+          }
+          // if (!NonUniformSet.count(CBIndex))
+          //  args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+          //      hlslOP->GetI1Const(0);
+          // else
+          //  args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
+          //      hlslOP->GetI1Const(1);
+
+          CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
+          CI->replaceAllUsesWith(handle);
+          CI->eraseFromParent();
+        }
+        if (Instruction *I = dyn_cast<Instruction>(GEP)) {
+          I->eraseFromParent();
+        }
+      }
+    }
+  }
+}
+
+// TBuffer.
+namespace {
+void InitTBuffer(const DxilCBuffer *pSource, DxilResource *pDest) {
+  pDest->SetKind(pSource->GetKind());
+  pDest->SetCompType(DXIL::ComponentType::U32);
+  pDest->SetSampleCount(0);
+  pDest->SetElementStride(0);
+  pDest->SetGloballyCoherent(false);
+  pDest->SetHasCounter(false);
+  pDest->SetRW(false);
+  pDest->SetROV(false);
+  pDest->SetID(pSource->GetID());
+  pDest->SetSpaceID(pSource->GetSpaceID());
+  pDest->SetLowerBound(pSource->GetLowerBound());
+  pDest->SetRangeSize(pSource->GetRangeSize());
+  pDest->SetGlobalSymbol(pSource->GetGlobalSymbol());
+  pDest->SetGlobalName(pSource->GetGlobalName());
+  pDest->SetHandle(pSource->GetHandle());
+}
+
+void PatchTBufferLoad(CallInst *handle, DxilModule &DM) {
+  hlsl::OP *hlslOP = DM.GetOP();
+  llvm::LLVMContext &Ctx = DM.GetCtx();
+  Type *doubleTy = Type::getDoubleTy(Ctx);
+  Type *i64Ty = Type::getInt64Ty(Ctx);
+
+  // Replace corresponding cbuffer loads with typed buffer loads
+  for (auto U = handle->user_begin(); U != handle->user_end();) {
+    CallInst *I = cast<CallInst>(*(U++));
+    DXASSERT(I && OP::IsDxilOpFuncCallInst(I),
+             "otherwise unexpected user of CreateHandle value");
+    DXIL::OpCode opcode = OP::GetDxilOpFuncCallInst(I);
+    if (opcode == DXIL::OpCode::CBufferLoadLegacy) {
+      DxilInst_CBufferLoadLegacy cbLoad(I);
+
+      // Replace with appropriate buffer load instruction
+      IRBuilder<> Builder(I);
+      opcode = OP::OpCode::BufferLoad;
+      Type *Ty = Type::getInt32Ty(Ctx);
+      Function *BufLoad = hlslOP->GetOpFunc(opcode, Ty);
+      Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
+      Value *undefI = UndefValue::get(Type::getInt32Ty(Ctx));
+      Value *offset = cbLoad.get_regIndex();
+      CallInst *load =
+          Builder.CreateCall(BufLoad, {opArg, handle, offset, undefI});
+
+      // Find extractelement uses of cbuffer load and replace + generate bitcast
+      // as necessary
+      for (auto LU = I->user_begin(); LU != I->user_end();) {
+        ExtractValueInst *evInst = dyn_cast<ExtractValueInst>(*(LU++));
+        DXASSERT(evInst && evInst->getNumIndices() == 1,
+                 "user of cbuffer load result should be extractvalue");
+        uint64_t idx = evInst->getIndices()[0];
+        Type *EltTy = evInst->getType();
+        IRBuilder<> EEBuilder(evInst);
+        Value *result = nullptr;
+        if (EltTy != Ty) {
+          // extract two values and DXIL::OpCode::MakeDouble or construct i64
+          if ((EltTy == doubleTy) || (EltTy == i64Ty)) {
+            DXASSERT(idx < 2, "64-bit component index out of range");
+
+            // This assumes big endian order in tbuffer elements (is this
+            // correct?)
+            Value *low = EEBuilder.CreateExtractValue(load, idx * 2);
+            Value *high = EEBuilder.CreateExtractValue(load, idx * 2 + 1);
+            if (EltTy == doubleTy) {
+              opcode = OP::OpCode::MakeDouble;
+              Function *MakeDouble = hlslOP->GetOpFunc(opcode, doubleTy);
+              Constant *opArg = hlslOP->GetU32Const((unsigned)opcode);
+              result = EEBuilder.CreateCall(MakeDouble, {opArg, low, high});
+            } else {
+              high = EEBuilder.CreateZExt(high, i64Ty);
+              low = EEBuilder.CreateZExt(low, i64Ty);
+              high = EEBuilder.CreateShl(high, hlslOP->GetU64Const(32));
+              result = EEBuilder.CreateOr(high, low);
+            }
+          } else {
+            result = EEBuilder.CreateExtractValue(load, idx);
+            result = EEBuilder.CreateBitCast(result, EltTy);
+          }
+        } else {
+          result = EEBuilder.CreateExtractValue(load, idx);
+        }
+
+        evInst->replaceAllUsesWith(result);
+        evInst->eraseFromParent();
+      }
+    } else if (opcode == DXIL::OpCode::CBufferLoad) {
+      // TODO: Handle this, or prevent this for tbuffer
+      DXASSERT(false, "otherwise CBufferLoad used for tbuffer rather than "
+                      "CBufferLoadLegacy");
+    } else {
+      DXASSERT(false, "otherwise unexpected user of CreateHandle value");
+    }
+    I->eraseFromParent();
+  }
+}
+} // namespace
+void DxilLowerCreateHandleForLib::PatchTBufferUse(Value *V, DxilModule &DM) {
+  for (User *U : V->users()) {
+    if (CallInst *CI = dyn_cast<CallInst>(U)) {
+      // Patch dxil call.
+      if (hlsl::OP::IsDxilOpFuncCallInst(CI))
+        PatchTBufferLoad(CI, DM);
+    } else {
+      PatchTBufferUse(U, DM);
+    }
+  }
+}
+
+void DxilLowerCreateHandleForLib::PatchTBuffers(DxilModule &DM) {
+  // move tbuffer resources to SRVs
+  unsigned offset = DM.GetSRVs().size();
+  Module &M = *DM.GetModule();
+  for (auto it = DM.GetCBuffers().begin(); it != DM.GetCBuffers().end(); it++) {
+    DxilCBuffer *CB = it->get();
+    if (CB->GetKind() == DXIL::ResourceKind::TBuffer) {
+      auto srv = make_unique<DxilResource>();
+      InitTBuffer(CB, srv.get());
+      srv->SetID(offset++);
+      DM.AddSRV(std::move(srv));
+      GlobalVariable *GV = cast<GlobalVariable>(CB->GetGlobalSymbol());
+      PatchTBufferUse(GV, DM);
+      // Set global symbol for cbuffer to an unused value so it can be removed
+      // in RemoveUnusedResourceSymbols.
+      Type *Ty = GV->getType()->getElementType();
+      GlobalVariable *NewGV = new GlobalVariable(
+          M, Ty, GV->isConstant(), GV->getLinkage(), /*Initializer*/ nullptr,
+          GV->getName(),
+          /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
+          GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
+      CB->SetGlobalSymbol(NewGV);
+    }
+  }
+}
+
+// Select on handle.
+// Transform
+// A = Add(a0, a1);
+// B = Add(b0, b1);
+// C = Add(c0, c1);
+// Inst = phi A, B, C
+//   into
+// phi0 = phi a0, b0, c0
+// phi1 = phi a1, b1, c1
+// NewInst = Add(phi0, phi1);
+namespace {
+void CollectSelect(llvm::Instruction *Inst,
+                   std::unordered_set<llvm::Instruction *> &selectSet) {
+  unsigned startOpIdx = 0;
+  // Skip Cond for Select.
+  if (isa<SelectInst>(Inst)) {
+    startOpIdx = 1;
+  } else if (!isa<PHINode>(Inst)) {
+    // Only check phi and select here.
+    return;
+  }
+  // Already add.
+  if (selectSet.count(Inst))
+    return;
+
+  selectSet.insert(Inst);
+
+  // Scan operand to add node which is phi/select.
+  unsigned numOperands = Inst->getNumOperands();
+  for (unsigned i = startOpIdx; i < numOperands; i++) {
+    Value *V = Inst->getOperand(i);
+    if (Instruction *I = dyn_cast<Instruction>(V)) {
+      CollectSelect(I, selectSet);
+    }
+  }
+}
+
+void CreateOperandSelect(Instruction *SelInst, Instruction *Prototype,
+                         std::unordered_map<Instruction *, Instruction *>
+                             &selInstToSelOperandInstMap) {
+  IRBuilder<> Builder(SelInst);
+
+  if (SelectInst *Sel = dyn_cast<SelectInst>(SelInst)) {
+    Value *Cond = Sel->getCondition();
+
+    Instruction *newSel = Prototype->clone();
+    for (unsigned i = 0; i < Prototype->getNumOperands(); i++) {
+      Value *op = Prototype->getOperand(i);
+      // Don't replace constant int operand.
+      if (isa<UndefValue>(op)) {
+        Value *selOperand = Builder.CreateSelect(Cond, op, op);
+        newSel->setOperand(i, selOperand);
+      }
+    }
+
+    Builder.Insert(newSel);
+
+    selInstToSelOperandInstMap[SelInst] = newSel;
+    SelInst->replaceAllUsesWith(newSel);
+  } else {
+    Instruction *newSel = Prototype->clone();
+    PHINode *Phi = cast<PHINode>(SelInst);
+    unsigned numIncoming = Phi->getNumIncomingValues();
+
+    for (unsigned i = 0; i < Prototype->getNumOperands(); i++) {
+      Value *op = Prototype->getOperand(i);
+      if (isa<UndefValue>(op)) {
+        // Don't replace constant int operand.
+        PHINode *phiOp = Builder.CreatePHI(op->getType(), numIncoming);
+        for (unsigned j = 0; j < numIncoming; j++) {
+          BasicBlock *BB = Phi->getIncomingBlock(j);
+          phiOp->addIncoming(op, BB);
+        }
+        newSel->setOperand(i, phiOp);
+      }
+    }
+    // Insert newSel after phi insts.
+    Builder.SetInsertPoint(Phi->getParent()->getFirstNonPHI());
+    Builder.Insert(newSel);
+    selInstToSelOperandInstMap[SelInst] = newSel;
+    SelInst->replaceAllUsesWith(newSel);
+  }
+}
+
+bool MergeSelectOnSameValue(Instruction *SelInst, unsigned startOpIdx,
+                            unsigned numOperands) {
+  Value *op0 = nullptr;
+  for (unsigned i = startOpIdx; i < numOperands; i++) {
+    Value *op = SelInst->getOperand(i);
+    if (i == startOpIdx) {
+      op0 = op;
+    } else {
+      if (op0 != op)
+        return false;
+    }
+  }
+  if (op0) {
+    SelInst->replaceAllUsesWith(op0);
+    SelInst->eraseFromParent();
+    return true;
+  }
+  return false;
+}
+
+void UpdateOperandSelect(Instruction *SelInst,
+                         std::unordered_map<Instruction *, Instruction *>
+                             &selInstToSelOperandInstMap,
+                         unsigned nonUniformOpIdx,
+                         std::unordered_set<Instruction *> &nonUniformOps,
+                         std::unordered_set<Instruction *> &invalidSel) {
+  unsigned numOperands = SelInst->getNumOperands();
+
+  unsigned startOpIdx = 0;
+  // Skip Cond for Select.
+  if (SelectInst *Sel = dyn_cast<SelectInst>(SelInst))
+    startOpIdx = 1;
+
+  Instruction *newInst = selInstToSelOperandInstMap[SelInst];
+  // Transform
+  // A = Add(a0, a1);
+  // B = Add(b0, b1);
+  // C = Add(c0, c1);
+  // Inst = phi A, B, C
+  //   into
+  // phi0 = phi a0, b0, c0
+  // phi1 = phi a1, b1, c1
+  // NewInst = Add(phi0, phi1);
+  for (unsigned i = 0; i < newInst->getNumOperands(); i++) {
+    Value *op = newInst->getOperand(i);
+    // Skip not select operand.
+    if (!isa<SelectInst>(op) && !isa<PHINode>(op))
+      continue;
+    Instruction *opI = cast<Instruction>(op);
+    // Each operand of newInst is a select inst.
+    // Now we set phi0 operands based on operands of phi A, B, C.
+    for (unsigned j = startOpIdx; j < numOperands; j++) {
+      Instruction *selOp = dyn_cast<Instruction>(SelInst->getOperand(j));
+      if (!selOp) {
+        // Fail to map selOp to prototype inst at SelInst.
+        invalidSel.insert(SelInst);
+        continue;
+      }
+
+      auto it = selInstToSelOperandInstMap.find(selOp);
+      if (it != selInstToSelOperandInstMap.end()) {
+        // Map the new created inst.
+        selOp = it->second;
+      } else {
+        // Make sure selOp match newInst format.
+        if (selOp->getOpcode() != newInst->getOpcode()) {
+          // Fail to map selOp to prototype inst at SelInst.
+          invalidSel.insert(SelInst);
+          continue;
+        }
+        // Make sure function is the same.
+        if (isa<CallInst>(selOp) && isa<CallInst>(newInst)) {
+          if (cast<CallInst>(selOp)->getCalledFunction() !=
+              cast<CallInst>(newInst)->getCalledFunction()) {
+            // Fail to map selOp to prototype inst at SelInst.
+            invalidSel.insert(SelInst);
+            continue;
+          }
+        }
+      }
+      // Here we set phi0 operand j with operand i of jth operand from (phi A,
+      // B, C).
+      opI->setOperand(j, selOp->getOperand(i));
+    }
+    // Remove select if all operand is the same.
+    if (!MergeSelectOnSameValue(opI, startOpIdx, numOperands) &&
+        i != nonUniformOpIdx) {
+      // Save nonUniform for later check.
+      nonUniformOps.insert(opI);
+    }
+  }
+}
+
+} // namespace
+
+void DxilLowerCreateHandleForLib::AddCreateHandleForPhiNodeAndSelect(
+    OP *hlslOP) {
+  Function *createHandle = hlslOP->GetOpFunc(
+      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(hlslOP->GetCtx()));
+
+  std::unordered_set<PHINode *> objPhiList;
+  std::unordered_set<SelectInst *> objSelectList;
+  std::unordered_set<Instruction *> resSelectSet;
+  for (User *U : createHandle->users()) {
+    for (User *HandleU : U->users()) {
+      Instruction *I = cast<Instruction>(HandleU);
+      if (!isa<CallInst>(I))
+        CollectSelect(I, resSelectSet);
+    }
+  }
+
+  // Generate Handle inst for Res inst.
+  FunctionType *FT = createHandle->getFunctionType();
+  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
+  Type *resClassTy =
+      FT->getParamType(DXIL::OperandIndex::kCreateHandleResClassOpIdx);
+  Type *resIDTy = FT->getParamType(DXIL::OperandIndex::kCreateHandleResIDOpIdx);
+  Type *resAddrTy =
+      FT->getParamType(DXIL::OperandIndex::kCreateHandleResIndexOpIdx);
+  Value *UndefResClass = UndefValue::get(resClassTy);
+  Value *UndefResID = UndefValue::get(resIDTy);
+  Value *UndefResAddr = UndefValue::get(resAddrTy);
+
+  // phi/select node resource is not uniform
+  Value *nonUniformRes = hlslOP->GetI1Const(1);
+
+  std::unique_ptr<CallInst> PrototypeCall(
+      CallInst::Create(createHandle, {opArg, UndefResClass, UndefResID,
+                                      UndefResAddr, nonUniformRes}));
+
+  std::unordered_map<Instruction *, Instruction *> handleMap;
+  for (Instruction *SelInst : resSelectSet) {
+    CreateOperandSelect(SelInst, PrototypeCall.get(), handleMap);
+  }
+
+  // Update operand for Handle phi/select.
+  // If ResClass or ResID is phi/select, save to nonUniformOps.
+  std::unordered_set<Instruction *> nonUniformOps;
+  std::unordered_set<Instruction *> invalidSel;
+  for (Instruction *SelInst : resSelectSet) {
+    UpdateOperandSelect(SelInst, handleMap,
+                        // Index into range is ok to diverse.
+                        DxilInst_CreateHandle::arg_index, nonUniformOps,
+                        invalidSel);
+  }
+
+  if (!invalidSel.empty()) {
+    for (Instruction *I : invalidSel) {
+      // Non uniform res class or res id.
+      dxilutil::EmitResMappingError(I);
+    }
+    return;
+  }
+
+  // ResClass and ResID must be uniform.
+  // Try to merge res class, res id into imm recursive.
+  while (1) {
+    bool bUpdated = false;
+
+    for (auto It = nonUniformOps.begin(); It != nonUniformOps.end();) {
+      Instruction *I = *(It++);
+      unsigned numOperands = I->getNumOperands();
+
+      unsigned startOpIdx = 0;
+      // Skip Cond for Select.
+      if (SelectInst *Sel = dyn_cast<SelectInst>(I))
+        startOpIdx = 1;
+      if (MergeSelectOnSameValue(I, startOpIdx, numOperands)) {
+        nonUniformOps.erase(I);
+        bUpdated = true;
+      }
+    }
+
+    if (!bUpdated) {
+      if (!nonUniformOps.empty()) {
+        for (Instruction *I : nonUniformOps) {
+          // Non uniform res class or res id.
+          dxilutil::EmitResMappingError(I);
+        }
+        return;
+      }
+      break;
+    }
+  }
+
+  // Remove useless select/phi.
+  for (Instruction *Res : resSelectSet) {
+    Res->eraseFromParent();
+  }
+}
+} // namespace
+
+char DxilLowerCreateHandleForLib::ID = 0;
+
+ModulePass *llvm::createDxilLowerCreateHandleForLibPass() {
+  return new DxilLowerCreateHandleForLib();
+}
+
+INITIALIZE_PASS(DxilLowerCreateHandleForLib, "hlsl-dxil-lower-handle-for-lib", "DXIL Lower createHandleForLib", false, false)

+ 122 - 51
lib/HLSL/DxilGenerationPass.cpp

@@ -118,46 +118,28 @@ void InitDxilModuleFromHLModule(HLModule &H, DxilModule &M, DxilEntrySignature *
   DxilFunctionProps *FnProps = H.HasDxilFunctionProps(EntryFn) ? &H.GetDxilFunctionProps(EntryFn) : nullptr;
   M.SetEntryFunction(EntryFn);
   M.SetEntryFunctionName(H.GetEntryFunctionName());
-  
-  std::vector<GlobalVariable* > &LLVMUsed = M.GetLLVMUsed();
 
   // Resources
   for (auto && C : H.GetCBuffers()) {
     auto b = make_unique<DxilCBuffer>();
     InitResourceBase(C.get(), b.get());
     b->SetSize(C->GetSize());
-    if (HasDebugInfo)
-      LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
-
-    b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
     M.AddCBuffer(std::move(b));
   }
   for (auto && C : H.GetUAVs()) {
     auto b = make_unique<DxilResource>();
     InitResource(C.get(), b.get());
-    if (HasDebugInfo)
-      LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
-
-    b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
     M.AddUAV(std::move(b));
   }
   for (auto && C : H.GetSRVs()) {
     auto b = make_unique<DxilResource>();
     InitResource(C.get(), b.get());
-    if (HasDebugInfo)
-      LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
-
-    b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
     M.AddSRV(std::move(b));
   }
   for (auto && C : H.GetSamplers()) {
     auto b = make_unique<DxilSampler>();
     InitResourceBase(C.get(), b.get());
     b->SetSamplerKind(C->GetSamplerKind());
-    if (HasDebugInfo)
-      LLVMUsed.emplace_back(cast<GlobalVariable>(b->GetGlobalSymbol()));
-
-    b->SetGlobalSymbol(UndefValue::get(b->GetGlobalSymbol()->getType()));
     M.AddSampler(std::move(b));
   }
 
@@ -255,11 +237,9 @@ public:
 
     GenerateDxilOperations(M, UpdateCounterSet, NonUniformSet);
 
-    std::unordered_map<Instruction *, Value *> handleMap;
     GenerateDxilCBufferHandles(NonUniformSet);
-    GenerateParamDxilResourceHandles(handleMap);
-    GenerateDxilResourceHandles(UpdateCounterSet, NonUniformSet);
-    AddCreateHandleForPhiNodeAndSelect(m_pHLModule->GetOP());
+    MarkUpdateCounter(UpdateCounterSet);
+    LowerHLCreateHandle();
 
     // For module which not promote mem2reg.
     // Remove local resource alloca/load/store/phi.
@@ -280,9 +260,6 @@ public:
     // Translate precise on allocas into function call to keep the information after mem2reg.
     // The function calls will be removed after propagate precise attribute.
     TranslatePreciseAttribute();
-    // Change struct type to legacy layout for cbuf and struct buf for min precision data types.
-    if (M.GetHLModule().GetHLOptions().bUseMinPrecision)
-      UpdateStructTypeForLegacyLayout();
 
     // High-level metadata should now be turned into low-level metadata.
     const bool SkipInit = true;
@@ -307,6 +284,7 @@ public:
 
 private:
   void RemoveLocalDxilResourceAllocas(Function *F);
+  void MarkUpdateCounter(std::unordered_set<LoadInst *> &UpdateCounterSet);
   void
   TranslateDxilResourceUses(DxilResourceBase &res,
                             std::unordered_set<LoadInst *> &UpdateCounterSet,
@@ -326,7 +304,7 @@ private:
   void GenerateDxilOperations(Module &M,
                               std::unordered_set<LoadInst *> &UpdateCounterSet,
                               std::unordered_set<Value *> &NonUniformSet);
-
+  void LowerHLCreateHandle();
   // Change struct type to legacy layout for cbuf and struct buf.
   void UpdateStructTypeForLegacyLayout();
 
@@ -338,6 +316,63 @@ private:
 };
 }
 
+namespace {
+void TranslateHLCreateHandle(Function *F, hlsl::OP &hlslOP) {
+  Value *opArg = hlslOP.GetU32Const(
+      (unsigned)DXIL::OpCode::CreateHandleFromResourceStructForLib);
+  for (auto U = F->user_begin(); U != F->user_end();) {
+    Value *user = *(U++);
+    if (!isa<Instruction>(user))
+      continue;
+    // must be call inst
+    CallInst *CI = cast<CallInst>(user);
+    Value *res = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
+    Value *newHandle = nullptr;
+    IRBuilder<> Builder(CI);
+    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(res)) {
+      // For cbuffer, res is global variable.
+      Function *createHandle = hlslOP.GetOpFunc(
+          DXIL::OpCode::CreateHandleFromResourceStructForLib, res->getType());
+      newHandle = Builder.CreateCall(createHandle, {opArg, res});
+    } else if (LoadInst *LI = dyn_cast<LoadInst>(res)) {
+      Value *resPtr = LI->getPointerOperand();
+      Function *createHandle =
+          hlslOP.GetOpFunc(DXIL::OpCode::CreateHandleFromResourceStructForLib,
+                           resPtr->getType());
+      newHandle = Builder.CreateCall(createHandle, {opArg, resPtr});
+    } else {
+      //// Just create alloca to save the res might be cheaper?
+      // IRBuilder<>
+      // AllocaBuilder(CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt());
+      // Value *resPtr = AllocaBuilder.CreateAlloca(res->getType());
+      // Builder.CreateStore(res,resPtr);
+      // newHandle = Builder.CreateCall(createHandle, {opArg, resPtr});
+      newHandle =
+          dxilutil::SelectOnOperation(CI, HLOperandIndex::kUnaryOpSrc0Idx);
+    }
+    CI->replaceAllUsesWith(newHandle);
+    CI->eraseFromParent();
+  }
+}
+} // namespace
+
+void DxilGenerationPass::LowerHLCreateHandle() {
+  Module *M = m_pHLModule->GetModule();
+  hlsl::OP &hlslOP = *m_pHLModule->GetOP();
+  // generate dxil operation
+  for (iplist<Function>::iterator F : M->getFunctionList()) {
+    if (F->user_empty())
+      continue;
+    if (!F->isDeclaration()) {
+      hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(F);
+      if (group == HLOpcodeGroup::HLCreateHandle) {
+        // Will lower in later pass.
+        TranslateHLCreateHandle(F, hlslOP);
+      }
+    }
+  }
+}
+
 static Value *MergeImmResClass(Value *resClass) {
   if (ConstantInt *Imm = dyn_cast<ConstantInt>(resClass)) {
     return resClass;
@@ -505,6 +540,47 @@ void DxilGenerationPass::GenerateParamDxilResourceHandles(
   }
 }
 
+static void
+MarkUavUpdateCounter(DxilResource &res,
+                     std::unordered_set<LoadInst *> &UpdateCounterSet) {
+  Value *GV = res.GetGlobalSymbol();
+  for (auto U = GV->user_begin(), E = GV->user_end(); U != E;) {
+    User *user = *(U++);
+    // Skip unused user.
+    if (user->user_empty())
+      continue;
+
+    if (LoadInst *ldInst = dyn_cast<LoadInst>(user)) {
+      if (UpdateCounterSet.count(ldInst)) {
+        DXASSERT_NOMSG(res.GetClass() == DXIL::ResourceClass::UAV);
+        res.SetHasCounter(true);
+      }
+    } else {
+      DXASSERT(dyn_cast<GEPOperator>(user) != nullptr,
+               "else AddOpcodeParamForIntrinsic in CodeGen did not patch uses "
+               "to only have ld/st refer to temp object");
+      GEPOperator *GEP = cast<GEPOperator>(user);
+      for (auto GEPU = GEP->user_begin(), GEPE = GEP->user_end();
+           GEPU != GEPE;) {
+        // Must be load inst.
+        LoadInst *ldInst = cast<LoadInst>(*(GEPU++));
+        if (UpdateCounterSet.count(ldInst)) {
+          DXASSERT_NOMSG(res.GetClass() == DXIL::ResourceClass::UAV);
+          res.SetHasCounter(true);
+        }
+      }
+    }
+  }
+}
+
+void DxilGenerationPass::MarkUpdateCounter(
+    std::unordered_set<LoadInst *> &UpdateCounterSet) {
+  for (size_t i = 0; i < m_pHLModule->GetUAVs().size(); i++) {
+    HLResource &UAV = m_pHLModule->GetUAV(i);
+    MarkUavUpdateCounter(UAV, UpdateCounterSet);
+  }
+}
+
 void DxilGenerationPass::TranslateDxilResourceUses(
     DxilResourceBase &res, std::unordered_set<LoadInst *> &UpdateCounterSet,
     std::unordered_set<Value *> &NonUniformSet) {
@@ -906,24 +982,17 @@ void DxilGenerationPass::GenerateDxilCBufferHandles(
     std::unordered_set<Value *> &NonUniformSet) {
   // For CBuffer, handle are mapped to HLCreateHandle.
   OP *hlslOP = m_pHLModule->GetOP();
-  Function *createHandle = hlslOP->GetOpFunc(
-      OP::OpCode::CreateHandle, llvm::Type::getVoidTy(m_pHLModule->GetCtx()));
-  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandle);
-
-  Value *resClassArg = hlslOP->GetU8Const(
-      static_cast<std::underlying_type<DxilResourceBase::Class>::type>(
-          DXIL::ResourceClass::CBuffer));
-
+  Value *opArg = hlslOP->GetU32Const((unsigned)OP::OpCode::CreateHandleFromResourceStructForLib);
+  LLVMContext &Ctx = hlslOP->GetCtx();
+  Value *zeroIdx = hlslOP->GetU32Const(0);
 
   for (size_t i = 0; i < m_pHLModule->GetCBuffers().size(); i++) {
     DxilCBuffer &CB = m_pHLModule->GetCBuffer(i);
     GlobalVariable *GV = cast<GlobalVariable>(CB.GetGlobalSymbol());
     // Remove GEP created in HLObjectOperationLowerHelper::UniformCbPtr.
     GV->removeDeadConstantUsers();
-    std::string handleName = std::string(GV->getName()) + "_buffer";
+    std::string handleName = std::string(GV->getName());// + "_buffer";
 
-    Value *args[] = {opArg, resClassArg, nullptr, nullptr,
-                     hlslOP->GetI1Const(0)};
     DIVariable *DIV = nullptr;
     DILocation *DL = nullptr;
     if (m_HasDbgInfo) {
@@ -931,18 +1000,13 @@ void DxilGenerationPass::GenerateDxilCBufferHandles(
       DIV = HLModule::FindGlobalVariableDebugInfo(GV, Finder);
       if (DIV)
         // TODO: how to get col?
-        DL = DILocation::get(createHandle->getContext(), DIV->getLine(), 1,
+        DL = DILocation::get(Ctx, DIV->getLine(), 1,
                              DIV->getScope());
     }
 
-    Value *resIDArg = hlslOP->GetU32Const(CB.GetID());
-    args[DXIL::OperandIndex::kCreateHandleResIDOpIdx] = resIDArg;
-
-    // resLowerBound will be added after allocation in DxilCondenseResources.
-    Value *resLowerBound = hlslOP->GetU32Const(0);
-
     if (CB.GetRangeSize() == 1) {
-      args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] = resLowerBound;
+      Function *createHandle = hlslOP->GetOpFunc(
+          OP::OpCode::CreateHandleFromResourceStructForLib, GV->getType());
       for (auto U = GV->user_begin(); U != GV->user_end(); ) {
         // Must HLCreateHandle.
         CallInst *CI = cast<CallInst>(*(U++));
@@ -951,7 +1015,7 @@ void DxilGenerationPass::GenerateDxilCBufferHandles(
             CI->getParent()->getParent()->getEntryBlock().getFirstInsertionPt();
         IRBuilder<> Builder(InsertPt);
 
-        CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
+        CallInst *handle = Builder.CreateCall(createHandle, {opArg, GV}, handleName);
         if (m_HasDbgInfo) {
           // TODO: add debug info.
           //handle->setDebugLoc(DL);
@@ -960,13 +1024,17 @@ void DxilGenerationPass::GenerateDxilCBufferHandles(
         CI->eraseFromParent();
       }
     } else {
-      for (auto U = GV->user_begin(); U != GV->user_end(); ) {
+      PointerType *Ty = GV->getType();
+      Type *EltTy = Ty->getElementType()->getArrayElementType()->getPointerTo(
+          Ty->getAddressSpace());
+      Function *createHandle = hlslOP->GetOpFunc(
+          OP::OpCode::CreateHandleFromResourceStructForLib, EltTy);
+
+      for (auto U = GV->user_begin(); U != GV->user_end();) {
         // Must HLCreateHandle.
         CallInst *CI = cast<CallInst>(*(U++));
         IRBuilder<> Builder(CI);
         Value *CBIndex = CI->getArgOperand(HLOperandIndex::kCreateHandleIndexOpIdx);
-        args[DXIL::OperandIndex::kCreateHandleResIndexOpIdx] =
-            CBIndex;
         if (isa<ConstantInt>(CBIndex)) {
           // Put createHandle to entry block for const index.
           auto InsertPt = CI->getParent()
@@ -975,14 +1043,17 @@ void DxilGenerationPass::GenerateDxilCBufferHandles(
                               .getFirstInsertionPt();
           Builder.SetInsertPoint(InsertPt);
         }
+        // Add GEP for cbv array use.
+        Value *GEP = Builder.CreateGEP(GV, {zeroIdx, CBIndex});
+        /*
         if (!NonUniformSet.count(CBIndex))
           args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
               hlslOP->GetI1Const(0);
         else
           args[DXIL::OperandIndex::kCreateHandleIsUniformOpIdx] =
-              hlslOP->GetI1Const(1);
+              hlslOP->GetI1Const(1);*/
 
-        CallInst *handle = Builder.CreateCall(createHandle, args, handleName);
+        CallInst *handle = Builder.CreateCall(createHandle, {opArg, GEP}, handleName);
         CI->replaceAllUsesWith(handle);
         CI->eraseFromParent();
       }

+ 10 - 11
lib/HLSL/DxilLinker.cpp

@@ -58,9 +58,7 @@ void AddResourceMap(
     std::unordered_map<const llvm::Constant *, DxilResourceBase *> &resMap,
     DxilModule &DM) {
   for (auto &Res : resTab) {
-    const DxilModule::ResourceLinkInfo &linkInfo =
-        DM.GetResourceLinkInfo(resClass, Res->GetID());
-    resMap[linkInfo.ResRangeID] = Res.get();
+    resMap[Res->GetGlobalSymbol()] = Res.get();
   }
 }
 
@@ -488,11 +486,8 @@ void DxilLinkJob::AddResourceToDM(DxilModule &DM) {
     }
     // Update ID.
     basePtr->SetID(ID);
-    Constant *rangeID = ConstantInt::get(GV->getType()->getElementType(), ID);
-    for (User *U : GV->users()) {
-      LoadInst *LI = cast<LoadInst>(U);
-      LI->replaceAllUsesWith(rangeID);
-    }
+
+    basePtr->SetGlobalSymbol(GV);
   }
 }
 
@@ -623,7 +618,8 @@ DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
   for (auto &it : m_functionDefs) {
     DxilFunctionLinkInfo *linkInfo = it.first;
     DxilLib *pLib = it.second;
-
+    DxilModule &tmpDM = pLib->GetDxilModule();
+    DxilTypeSystem &tmpTypeSys = tmpDM.GetTypeSystem();
     for (GlobalVariable *GV : linkInfo->usedGVs) {
       // Skip added globals.
       if (m_newGlobals.count(GV->getName())) {
@@ -650,8 +646,9 @@ DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
       if (GV->hasInitializer())
         Initializer = GV->getInitializer();
 
+      Type *Ty = GV->getType()->getElementType();
       GlobalVariable *NewGV = new GlobalVariable(
-          *pM, GV->getType()->getElementType(), GV->isConstant(),
+          *pM, Ty, GV->isConstant(),
           GV->getLinkage(), Initializer, GV->getName(),
           /*InsertBefore*/ nullptr, GV->getThreadLocalMode(),
           GV->getType()->getAddressSpace(), GV->isExternallyInitialized());
@@ -660,6 +657,8 @@ DxilLinkJob::Link(std::pair<DxilFunctionLinkInfo *, DxilLib *> &entryLinkPair,
 
       vmap[GV] = NewGV;
 
+      typeSys.CopyTypeAnnotation(Ty, tmpTypeSys);
+
       if (DxilResourceBase *res = pLib->GetResource(GV)) {
         bSuccess &= AddResource(res, NewGV);
       }
@@ -748,7 +747,7 @@ void DxilLinkJob::RunPreparePass(Module &M) {
   PM.add(createDeadCodeEliminationPass());
   PM.add(createGlobalDCEPass());
 
-  PM.add(createDxilCondenseResourcesPass());
+  PM.add(createDxilLowerCreateHandleForLibPass());
   PM.add(createDxilFinalizeModulePass());
   PM.add(createComputeViewIdStatePass());
   PM.add(createDxilDeadFunctionEliminationPass());

+ 21 - 0
lib/HLSL/DxilModule.cpp

@@ -1043,6 +1043,27 @@ void DxilModule::RemoveUnusedResources() {
   RemoveResources(m_CBuffers, immCBufID);
 }
 
+namespace {
+template <typename TResource>
+static void RemoveResourceSymbols(std::vector<std::unique_ptr<TResource>> &vec) {
+  for (std::vector<std::unique_ptr<TResource>>::iterator p = vec.begin(); p != vec.end();) {
+    std::vector<std::unique_ptr<TResource>>::iterator c = p++;
+    GlobalVariable *GV = cast<GlobalVariable>((*c)->GetGlobalSymbol());
+    GV->removeDeadConstantUsers();
+    if (GV->user_empty()) {
+      p = vec.erase(c);
+    }
+  }
+}
+}
+
+void DxilModule::RemoveUnusedResourceSymbols() {
+  RemoveResourceSymbols(m_SRVs);
+  RemoveResourceSymbols(m_UAVs);
+  RemoveResourceSymbols(m_CBuffers);
+  RemoveResourceSymbols(m_Samplers);
+}
+
 DxilSignature &DxilModule::GetInputSignature() {
   return m_EntrySignature->InputSignature;
 }

+ 1 - 1
lib/HLSL/DxilOperations.cpp

@@ -299,7 +299,7 @@ const OP::OpCodeProperty OP::m_OpCodeProps[(unsigned)OP::OpCode::NumOpCodes] = {
   {  OC::CallShader,              "CallShader",               OCC::CallShader,               "callShader",                 false, false, false, false, false, false, false, false, false,  true, Attribute::None,     },
 
   // Library create handle from resource struct (like HL intrinsic)                                                         void,     h,     f,     d,    i1,    i8,   i16,   i32,   i64,   udt,  function attribute
-  {  OC::CreateHandleFromResourceStructForLib, "CreateHandleFromResourceStructForLib", OCC::CreateHandleFromResourceStructForLib, "createHandleFromResourceStructForLib",  false, false, false, false, false, false, false, false, false,  true, Attribute::ReadNone, },
+  {  OC::CreateHandleFromResourceStructForLib, "CreateHandleFromResourceStructForLib", OCC::CreateHandleFromResourceStructForLib, "createHandleFromResourceStructForLib",  false, false, false, false, false, false, false, false, false,  true, Attribute::ReadOnly, },
 };
 // OPCODE-OLOADS:END
 

+ 55 - 0
lib/HLSL/DxilUtil.cpp

@@ -23,6 +23,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/IRBuilder.h"
 
 using namespace llvm;
 using namespace hlsl;
@@ -148,5 +149,59 @@ std::unique_ptr<llvm::Module> LoadModuleFromBitcode(llvm::StringRef BC,
   return LoadModuleFromBitcode(pBitcodeBuf.get(), Ctx, DiagStr);
 }
 
+static const StringRef kResourceMapErrorMsg =
+    "local resource not guaranteed to map to unique global resource.";
+void EmitResMappingError(Instruction *Res) {
+  const DebugLoc &DL = Res->getDebugLoc();
+  if (DL.get()) {
+    Res->getContext().emitError("line:" + std::to_string(DL.getLine()) +
+                                " col:" + std::to_string(DL.getCol()) + " " +
+                                Twine(kResourceMapErrorMsg));
+  } else {
+    Res->getContext().emitError(Twine(kResourceMapErrorMsg) +
+                                " With /Zi to show more information.");
+  }
+}
+
+Value *SelectOnOperation(llvm::Instruction *Inst, unsigned operandIdx) {
+  Instruction *prototype = Inst;
+  for (unsigned i = 0; i < prototype->getNumOperands(); i++) {
+    if (i == operandIdx)
+      continue;
+    if (!isa<Constant>(prototype->getOperand(i)))
+      return nullptr;
+  }
+  Value *V = prototype->getOperand(operandIdx);
+  if (SelectInst *SI = dyn_cast<SelectInst>(V)) {
+    IRBuilder<> Builder(SI);
+    Instruction *trueClone = Inst->clone();
+    trueClone->setOperand(operandIdx, SI->getTrueValue());
+    Builder.Insert(trueClone);
+    Instruction *falseClone = Inst->clone();
+    falseClone->setOperand(operandIdx, SI->getFalseValue());
+    Builder.Insert(falseClone);
+    Value *newSel =
+        Builder.CreateSelect(SI->getCondition(), trueClone, falseClone);
+    return newSel;
+  }
+
+  if (PHINode *Phi = dyn_cast<PHINode>(V)) {
+    Type *Ty = Inst->getType();
+    unsigned numOperands = Phi->getNumOperands();
+    IRBuilder<> Builder(Phi);
+    PHINode *newPhi = Builder.CreatePHI(Ty, numOperands);
+    for (unsigned i = 0; i < numOperands; i++) {
+      BasicBlock *b = Phi->getIncomingBlock(i);
+      Value *V = Phi->getIncomingValue(i);
+      Instruction *iClone = Inst->clone();
+      IRBuilder<> iBuilder(b->getTerminator()->getPrevNode());
+      iClone->setOperand(operandIdx, V);
+      iBuilder.Insert(iClone);
+      newPhi->addIncoming(iClone, b);
+    }
+    return newPhi;
+  }
+  return nullptr;
+}
 }
 }

+ 1 - 42
lib/HLSL/HLOperationLower.cpp

@@ -6789,43 +6789,6 @@ static void TranslateHLExtension(Function *F,
   }
 }
 
-namespace {
-void TranslateHLCreateHandle(Function *F, HLOperationLowerHelper &helper,
-                             hlsl::HLOpcodeGroup group,
-                             HLObjectOperationLowerHelper *pObjHelper) {
-  hlsl::OP &hlslOP = helper.hlslOP;
-  Value *opArg = hlslOP.GetU32Const(
-      (unsigned)DXIL::OpCode::CreateHandleFromResourceStructForLib);
-  for (auto U = F->user_begin(); U != F->user_end();) {
-    Value *user = *(U++);
-    if (!isa<Instruction>(user))
-      continue;
-    // must be call inst
-    CallInst *CI = cast<CallInst>(user);
-    Value *res = CI->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
-    Value *newHandle = nullptr;
-    if (LoadInst *LI = dyn_cast<LoadInst>(res)) {
-      Value *resPtr = LI->getPointerOperand();
-      Function *createHandle =
-          hlslOP.GetOpFunc(DXIL::OpCode::CreateHandleFromResourceStructForLib,
-                           resPtr->getType());
-      IRBuilder<> Builder(CI);
-      newHandle = Builder.CreateCall(createHandle, {opArg, resPtr});
-    } else {
-      // A handle to res.
-      CallInst *resCall = cast<CallInst>(res);
-      Function *F = resCall->getCalledFunction();
-      HLOpcodeGroup group = hlsl::GetHLOpcodeGroupByName(F);
-      DXASSERT(group == HLOpcodeGroup::HLCast, "must be a handleToRes");
-      newHandle = resCall->getArgOperand(HLOperandIndex::kUnaryOpSrc0Idx);
-      DXASSERT(newHandle->getType() == CI->getType(), "must be a handleToRes");
-    }
-    CI->replaceAllUsesWith(newHandle);
-    CI->eraseFromParent();
-  }
-}
-} // namespace
-
 namespace hlsl {
 
 void TranslateBuiltinOperations(
@@ -6843,14 +6806,10 @@ void TranslateBuiltinOperations(
   for (iplist<Function>::iterator F : M->getFunctionList()) {
     if (F->user_empty())
       continue;
-    hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(F);
     if (!F->isDeclaration()) {
-      if (group == HLOpcodeGroup::HLCreateHandle) {
-        // Will lower in later pass.
-        TranslateHLCreateHandle(F, helper, group, &objHelper);
-      }
       continue;
     }
+    hlsl::HLOpcodeGroup group = hlsl::GetHLOpcodeGroup(F);
     if (group == HLOpcodeGroup::NotHL) {
       // Nothing to do.
       continue;

+ 2 - 2
lib/Transforms/IPO/PassManagerBuilder.cpp

@@ -303,7 +303,7 @@ void PassManagerBuilder::populateModulePassManager(
     addHLSLPasses(HLSLHighLevel, OptLevel, HLSLExtensionsCodeGen, MPM);
     if (!HLSLHighLevel) {
       MPM.add(createMultiDimArrayToOneDimArrayPass());
-      MPM.add(createDxilCondenseResourcesPass());
+      MPM.add(createDxilLowerCreateHandleForLibPass());
       MPM.add(createDxilLegalizeSampleOffsetPass());
       MPM.add(createDxilFinalizeModulePass());
       MPM.add(createComputeViewIdStatePass());
@@ -575,7 +575,7 @@ void PassManagerBuilder::populateModulePassManager(
   // HLSL Change Begins.
   if (!HLSLHighLevel) {
     MPM.add(createMultiDimArrayToOneDimArrayPass());
-    MPM.add(createDxilCondenseResourcesPass());
+    MPM.add(createDxilLowerCreateHandleForLibPass());
     MPM.add(createDeadCodeEliminationPass());
     if (DisableUnrollLoops)
       MPM.add(createDxilLegalizeSampleOffsetPass());

+ 2 - 1
utils/hct/hctdb.py

@@ -1238,7 +1238,7 @@ class db_dxil(object):
             db_dxil_param(3, "udt", "Parameter", "User-defined parameters to pass to the callable shader,This parameter structure must match the parameter structure used in the callable shader pointed to in the shader table")])
         next_op_idx += 1
 
-        self.add_dxil_op("CreateHandleFromResourceStructForLib", next_op_idx, "CreateHandleFromResourceStructForLib", "create resource handle from resource struct for library", "u", "rn", [
+        self.add_dxil_op("CreateHandleFromResourceStructForLib", next_op_idx, "CreateHandleFromResourceStructForLib", "create resource handle from resource struct for library", "u", "ro", [
             db_dxil_param(0, "res", "", "result"),
             db_dxil_param(2, "udt", "Resource", "resource to create the handle")])
         next_op_idx += 1
@@ -1439,6 +1439,7 @@ class db_dxil(object):
         add_pass('hlsl-passes-pause', 'PausePasses', 'Prepare to pause passes', [])
         add_pass('hlsl-passes-resume', 'ResumePasses', 'Prepare to resume passes', [])
         add_pass('hlsl-dxil-condense', 'DxilCondenseResources', 'DXIL Condense Resources', [])
+        add_pass('hlsl-dxil-lower-handle-for-lib', 'DxilLowerCreateHandleForLib', 'DXIL Lower createHandleForLib', [])
         add_pass('hlsl-dxil-eliminate-output-dynamic', 'DxilEliminateOutputDynamicIndexing', 'DXIL eliminate ouptut dynamic indexing', [])
         add_pass('hlsl-dxil-add-pixel-hit-instrmentation', 'DxilAddPixelHitInstrumentation', 'DXIL Count completed PS invocations and costs', [
             {'n':'force-early-z','t':'int','c':1},