[llvm] wip: [DirectX] Refactor resources into binding and type passes (PR #119738)

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 12 10:43:43 PST 2024


https://github.com/bogner updated https://github.com/llvm/llvm-project/pull/119738

>From 48386184ca65b92c9db7ec90ebef8e57d221b54a Mon Sep 17 00:00:00 2001
From: Justin Bogner <mail at justinbogner.com>
Date: Fri, 6 Dec 2024 14:58:50 -0800
Subject: [PATCH] wip: [DirectX] Refactor resources into binding and type
 passes

This is a big refactor of resources into two separate passes (#118400),
which also happens to fix #116849. Unfortunately it's quite large and
probably not practical to review.

I plan on splitting this into three changes:
1. Rework resource type info to work by accessing the target ext type
2. Introduce the resource type analysis pass
3. Add and use the createSymbol API
---
 llvm/include/llvm/Analysis/DXILResource.h     | 555 ++++++----
 llvm/include/llvm/InitializePasses.h          |   3 +-
 llvm/include/llvm/LinkAllPasses.h             |   3 +-
 llvm/lib/Analysis/Analysis.cpp                |   3 +-
 llvm/lib/Analysis/DXILResource.cpp            | 961 +++++++++---------
 llvm/lib/Passes/PassRegistry.def              |   6 +-
 .../lib/Target/DirectX/DXContainerGlobals.cpp |  28 +-
 .../Target/DirectX/DXILDataScalarization.cpp  |   7 -
 .../Target/DirectX/DXILFinalizeLinkage.cpp    |   5 -
 llvm/lib/Target/DirectX/DXILFinalizeLinkage.h |   1 -
 llvm/lib/Target/DirectX/DXILFlattenArrays.cpp |   7 -
 .../Target/DirectX/DXILIntrinsicExpansion.cpp |   6 -
 llvm/lib/Target/DirectX/DXILOpLowering.cpp    |  55 +-
 llvm/lib/Target/DirectX/DXILPrepare.cpp       |   2 +-
 llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp |  81 +-
 .../Target/DirectX/DXILTranslateMetadata.cpp  |  51 +-
 .../DXILResource/buffer-frombinding.ll        |  16 +-
 llvm/test/CodeGen/DirectX/llc-pipeline.ll     |   4 +-
 llvm/unittests/Analysis/DXILResourceTest.cpp  | 405 +++++---
 19 files changed, 1282 insertions(+), 917 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 6b577c02f05450..b59798a3d64a47 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -11,6 +11,7 @@
 
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/Alignment.h"
@@ -18,33 +19,187 @@
 
 namespace llvm {
 class CallInst;
+class DataLayout;
 class LLVMContext;
 class MDTuple;
+class TargetExtType;
 class Value;
 
+class DXILResourceTypeMap;
+
 namespace dxil {
 
-class ResourceInfo {
+/// The dx.RawBuffer target extension type
+///
+/// `target("dx.RawBuffer", Type, IsWriteable, IsROV)`
+class RawBufferExtType : public TargetExtType {
 public:
-  struct ResourceBinding {
-    uint32_t RecordID;
-    uint32_t Space;
-    uint32_t LowerBound;
-    uint32_t Size;
+  RawBufferExtType() = delete;
+  RawBufferExtType(const RawBufferExtType &) = delete;
+  RawBufferExtType &operator=(const RawBufferExtType &) = delete;
+
+  bool isStructured() const {
+    // TODO: We need to be more prescriptive here, but since there's some debate
+    // over whether byte address buffer should have a void type or an i8 type,
+    // accept either for now.
+    Type *Ty = getTypeParameter(0);
+    return !Ty->isVoidTy() && !Ty->isIntegerTy(8);
+  }
 
-    bool operator==(const ResourceBinding &RHS) const {
-      return std::tie(RecordID, Space, LowerBound, Size) ==
-             std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
-    }
-    bool operator!=(const ResourceBinding &RHS) const {
-      return !(*this == RHS);
-    }
-    bool operator<(const ResourceBinding &RHS) const {
-      return std::tie(RecordID, Space, LowerBound, Size) <
-             std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
-    }
-  };
+  Type *getResourceType() const {
+    return isStructured() ? getTypeParameter(0) : nullptr;
+  }
+  bool isWriteable() const { return getIntParameter(0); }
+  bool isROV() const { return getIntParameter(1); }
 
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.RawBuffer";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.TypedBuffer target extension type
+///
+/// `target("dx.TypedBuffer", Type, IsWriteable, IsROV, IsSigned)`
+class TypedBufferExtType : public TargetExtType {
+public:
+  TypedBufferExtType() = delete;
+  TypedBufferExtType(const TypedBufferExtType &) = delete;
+  TypedBufferExtType &operator=(const TypedBufferExtType &) = delete;
+
+  Type *getResourceType() const { return getTypeParameter(0); }
+  bool isWriteable() const { return getIntParameter(0); }
+  bool isROV() const { return getIntParameter(1); }
+  bool isSigned() const { return getIntParameter(2); }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.TypedBuffer";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.Texture target extension type
+///
+/// `target("dx.Texture", Type, IsWriteable, IsROV, IsSigned, Dimension)`
+class TextureExtType : public TargetExtType {
+public:
+  TextureExtType() = delete;
+  TextureExtType(const TextureExtType &) = delete;
+  TextureExtType &operator=(const TextureExtType &) = delete;
+
+  Type *getResourceType() const { return getTypeParameter(0); }
+  bool isWriteable() const { return getIntParameter(0); }
+  bool isROV() const { return getIntParameter(1); }
+  bool isSigned() const { return getIntParameter(2); }
+  dxil::ResourceKind getDimension() const {
+    return static_cast<dxil::ResourceKind>(getIntParameter(3));
+  }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.Texture";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.MSTexture target extension type
+///
+/// `target("dx.MSTexture", Type, IsWriteable, Samples, IsSigned, Dimension)`
+class MSTextureExtType : public TargetExtType {
+public:
+  MSTextureExtType() = delete;
+  MSTextureExtType(const MSTextureExtType &) = delete;
+  MSTextureExtType &operator=(const MSTextureExtType &) = delete;
+
+  Type *getResourceType() const { return getTypeParameter(0); }
+  bool isWriteable() const { return getIntParameter(0); }
+  uint32_t getSampleCount() const { return getIntParameter(1); }
+  bool isSigned() const { return getIntParameter(2); }
+  dxil::ResourceKind getDimension() const {
+    return static_cast<dxil::ResourceKind>(getIntParameter(3));
+  }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.MSTexture";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.FeedbackTexture target extension type
+///
+/// `target("dx.FeedbackTexture", FeedbackType, Dimension)`
+class FeedbackTextureExtType : public TargetExtType {
+public:
+  FeedbackTextureExtType() = delete;
+  FeedbackTextureExtType(const FeedbackTextureExtType &) = delete;
+  FeedbackTextureExtType &operator=(const FeedbackTextureExtType &) = delete;
+
+  dxil::SamplerFeedbackType getFeedbackType() const {
+    return static_cast<dxil::SamplerFeedbackType>(getIntParameter(0));
+  }
+  dxil::ResourceKind getDimension() const {
+    return static_cast<dxil::ResourceKind>(getIntParameter(1));
+  }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.FeedbackTexture";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.CBuffer target extension type
+///
+/// `target("dx.CBuffer", <Type>, ...)`
+class CBufferExtType : public TargetExtType {
+public:
+  CBufferExtType() = delete;
+  CBufferExtType(const CBufferExtType &) = delete;
+  CBufferExtType &operator=(const CBufferExtType &) = delete;
+
+  Type *getResourceType() const { return getTypeParameter(0); }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.CBuffer";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+/// The dx.Sampler target extension type
+///
+/// `target("dx.Sampler", SamplerType)`
+class SamplerExtType : public TargetExtType {
+public:
+  SamplerExtType() = delete;
+  SamplerExtType(const SamplerExtType &) = delete;
+  SamplerExtType &operator=(const SamplerExtType &) = delete;
+
+  dxil::SamplerType getSamplerType() const {
+    return static_cast<dxil::SamplerType>(getIntParameter(0));
+  }
+
+  static bool classof(const TargetExtType *T) {
+    return T->getName() == "dx.Sampler";
+  }
+  static bool classof(const Type *T) {
+    return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
+  }
+};
+
+//===----------------------------------------------------------------------===//
+
+class ResourceTypeInfo {
+public:
   struct UAVInfo {
     bool GloballyCoherent;
     bool HasCounter;
@@ -93,55 +248,31 @@ class ResourceInfo {
     }
   };
 
-  struct MSInfo {
-    uint32_t Count;
-
-    bool operator==(const MSInfo &RHS) const { return Count == RHS.Count; }
-    bool operator!=(const MSInfo &RHS) const { return !(*this == RHS); }
-    bool operator<(const MSInfo &RHS) const { return Count < RHS.Count; }
-  };
-
-  struct FeedbackInfo {
-    dxil::SamplerFeedbackType Type;
-
-    bool operator==(const FeedbackInfo &RHS) const { return Type == RHS.Type; }
-    bool operator!=(const FeedbackInfo &RHS) const { return !(*this == RHS); }
-    bool operator<(const FeedbackInfo &RHS) const { return Type < RHS.Type; }
-  };
-
 private:
-  // Universal properties.
-  Value *Symbol;
-  StringRef Name;
+  TargetExtType *HandleTy;
+
+  // GloballyCoherent and HasCounter aren't really part of the type and need to
+  // be determined by analysis, so they're just provided directly by the
+  // DXILResourceTypeMap when we construct these.
+  bool GloballyCoherent;
+  bool HasCounter;
 
   dxil::ResourceClass RC;
   dxil::ResourceKind Kind;
 
-  ResourceBinding Binding = {};
-
-  // Resource class dependent properties.
-  // CBuffer, Sampler, and RawBuffer end here.
-  union {
-    UAVInfo UAVFlags;            // UAV
-    uint32_t CBufferSize;        // CBuffer
-    dxil::SamplerType SamplerTy; // Sampler
-  };
-
-  // Resource kind dependent properties.
-  union {
-    StructInfo Struct;     // StructuredBuffer
-    TypedInfo Typed;       // All SRV/UAV except Raw/StructuredBuffer
-    FeedbackInfo Feedback; // FeedbackTexture
-  };
-
-  MSInfo MultiSample;
-
 public:
-  ResourceInfo(dxil::ResourceClass RC, dxil::ResourceKind Kind, Value *Symbol,
-               StringRef Name)
-      : Symbol(Symbol), Name(Name), RC(RC), Kind(Kind) {}
-
-  // Conditions to check before accessing union members.
+  ResourceTypeInfo(TargetExtType *HandleTy, const dxil::ResourceClass RC,
+                   const dxil::ResourceKind Kind, bool GloballyCoherent = false,
+                   bool HasCounter = false);
+  ResourceTypeInfo(TargetExtType *HandleTy, bool GloballyCoherent = false,
+                   bool HasCounter = false)
+      : ResourceTypeInfo(HandleTy, {}, dxil::ResourceKind::Invalid,
+                         GloballyCoherent, HasCounter) {}
+
+  TargetExtType *getHandleTy() const { return HandleTy; }
+  StructType *createElementStruct();
+
+  // Conditions to check before accessing specific views.
   bool isUAV() const;
   bool isCBuffer() const;
   bool isSampler() const;
@@ -150,148 +281,185 @@ class ResourceInfo {
   bool isFeedback() const;
   bool isMultiSample() const;
 
-  void bind(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
-            uint32_t Size) {
-    Binding.RecordID = RecordID;
-    Binding.Space = Space;
-    Binding.LowerBound = LowerBound;
-    Binding.Size = Size;
-  }
+  // Views into the type.
+  UAVInfo getUAV() const;
+  uint32_t getCBufferSize(const DataLayout &DL) const;
+  dxil::SamplerType getSamplerType() const;
+  StructInfo getStruct(const DataLayout &DL) const;
+  TypedInfo getTyped() const;
+  dxil::SamplerFeedbackType getFeedbackType() const;
+  uint32_t getMultiSampleCount() const;
+
+  dxil::ResourceClass getResourceClass() const { return RC; }
+  dxil::ResourceKind getResourceKind() const { return Kind; }
+
+  bool operator==(const ResourceTypeInfo &RHS) const;
+  bool operator!=(const ResourceTypeInfo &RHS) const { return !(*this == RHS); }
+  bool operator<(const ResourceTypeInfo &RHS) const;
+
+  void print(raw_ostream &OS, const DataLayout &DL) const;
+};
+
+//===----------------------------------------------------------------------===//
+
+class ResourceBindingInfo {
+public:
+  struct ResourceBinding {
+    uint32_t RecordID;
+    uint32_t Space;
+    uint32_t LowerBound;
+    uint32_t Size;
+
+    bool operator==(const ResourceBinding &RHS) const {
+      return std::tie(RecordID, Space, LowerBound, Size) ==
+             std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
+    }
+    bool operator!=(const ResourceBinding &RHS) const {
+      return !(*this == RHS);
+    }
+    bool operator<(const ResourceBinding &RHS) const {
+      return std::tie(RecordID, Space, LowerBound, Size) <
+             std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
+    }
+  };
+
+private:
+  ResourceBinding Binding;
+  TargetExtType *HandleTy;
+  GlobalVariable *Symbol = nullptr;
+
+public:
+  ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
+                      uint32_t Size, TargetExtType *HandleTy,
+                      GlobalVariable *Symbol = nullptr)
+      : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
+        Symbol(Symbol) {}
+
+  void setBindingID(unsigned ID) { Binding.RecordID = ID; }
+
   const ResourceBinding &getBinding() const { return Binding; }
-  void setUAV(bool GloballyCoherent, bool HasCounter, bool IsROV) {
-    assert(isUAV() && "Not a UAV");
-    UAVFlags.GloballyCoherent = GloballyCoherent;
-    UAVFlags.HasCounter = HasCounter;
-    UAVFlags.IsROV = IsROV;
-  }
-  const UAVInfo &getUAV() const {
-    assert(isUAV() && "Not a UAV");
-    return UAVFlags;
-  }
-  void setCBuffer(uint32_t Size) {
-    assert(isCBuffer() && "Not a CBuffer");
-    CBufferSize = Size;
+  TargetExtType *getHandleTy() const { return HandleTy; }
+  const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
+
+  bool hasSymbol() const { return Symbol; }
+  GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
+  MDTuple *getAsMetadata(Module &M, DXILResourceTypeMap &DRTM) const;
+  MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo RTI) const;
+
+  std::pair<uint32_t, uint32_t>
+  getAnnotateProps(Module &M, DXILResourceTypeMap &DRTM) const;
+  std::pair<uint32_t, uint32_t>
+  getAnnotateProps(Module &M, dxil::ResourceTypeInfo RTI) const;
+
+  bool operator==(const ResourceBindingInfo &RHS) const {
+    return std::tie(Binding, HandleTy, Symbol) ==
+           std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
   }
-  void setSampler(dxil::SamplerType Ty) { SamplerTy = Ty; }
-  void setStruct(uint32_t Stride, MaybeAlign Alignment) {
-    assert(isStruct() && "Not a Struct");
-    Struct.Stride = Stride;
-    Struct.AlignLog2 = Alignment ? Log2(*Alignment) : 0;
+  bool operator!=(const ResourceBindingInfo &RHS) const {
+    return !(*this == RHS);
   }
-  void setTyped(dxil::ElementType ElementTy, uint32_t ElementCount) {
-    assert(isTyped() && "Not Typed");
-    Typed.ElementTy = ElementTy;
-    Typed.ElementCount = ElementCount;
+  bool operator<(const ResourceBindingInfo &RHS) const {
+    return Binding < RHS.Binding;
   }
-  const TypedInfo &getTyped() const {
-    assert(isTyped() && "Not typed");
-    return Typed;
+
+  void print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
+             const DataLayout &DL) const;
+  void print(raw_ostream &OS, dxil::ResourceTypeInfo RTI,
+             const DataLayout &DL) const;
+};
+
+} // namespace dxil
+
+//===----------------------------------------------------------------------===//
+
+class DXILResourceTypeMap {
+  struct Info {
+    dxil::ResourceClass RC;
+    dxil::ResourceKind Kind;
+    bool GloballyCoherent;
+    bool HasCounter;
+  };
+  DenseMap<TargetExtType *, Info> Infos;
+
+public:
+  bool invalidate(Module &M, const PreservedAnalyses &PA,
+                  ModuleAnalysisManager::Invalidator &Inv);
+
+  dxil::ResourceTypeInfo operator[](TargetExtType *Ty) {
+    Info I = Infos[Ty];
+    return dxil::ResourceTypeInfo(Ty, I.RC, I.Kind, I.GloballyCoherent,
+                                  I.HasCounter);
   }
-  void setFeedback(dxil::SamplerFeedbackType Type) {
-    assert(isFeedback() && "Not Feedback");
-    Feedback.Type = Type;
+
+  void setGloballyCoherent(TargetExtType *Ty, bool GloballyCoherent) {
+    Infos[Ty].GloballyCoherent = GloballyCoherent;
   }
-  void setMultiSample(uint32_t Count) {
-    assert(isMultiSample() && "Not MultiSampled");
-    MultiSample.Count = Count;
+
+  void setHasCounter(TargetExtType *Ty, bool HasCounter) {
+    Infos[Ty].HasCounter = HasCounter;
   }
-  const MSInfo &getMultiSample() const {
-    assert(isMultiSample() && "Not MultiSampled");
-    return MultiSample;
+};
+
+class DXILResourceTypeAnalysis
+    : public AnalysisInfoMixin<DXILResourceTypeAnalysis> {
+  friend AnalysisInfoMixin<DXILResourceTypeAnalysis>;
+
+  static AnalysisKey Key;
+
+public:
+  using Result = DXILResourceTypeMap;
+
+  DXILResourceTypeMap run(Module &M, ModuleAnalysisManager &AM) {
+    return Result();
   }
+};
 
-  StringRef getName() const { return Name; }
-  dxil::ResourceClass getResourceClass() const { return RC; }
-  dxil::ResourceKind getResourceKind() const { return Kind; }
+class DXILResourceTypeWrapperPass : public ImmutablePass {
+  DXILResourceTypeMap DRTM;
 
-  bool operator==(const ResourceInfo &RHS) const;
-  bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); }
-  bool operator<(const ResourceInfo &RHS) const;
-
-  static ResourceInfo SRV(Value *Symbol, StringRef Name,
-                          dxil::ElementType ElementTy, uint32_t ElementCount,
-                          dxil::ResourceKind Kind);
-  static ResourceInfo RawBuffer(Value *Symbol, StringRef Name);
-  static ResourceInfo StructuredBuffer(Value *Symbol, StringRef Name,
-                                       uint32_t Stride, MaybeAlign Alignment);
-  static ResourceInfo Texture2DMS(Value *Symbol, StringRef Name,
-                                  dxil::ElementType ElementTy,
-                                  uint32_t ElementCount, uint32_t SampleCount);
-  static ResourceInfo Texture2DMSArray(Value *Symbol, StringRef Name,
-                                       dxil::ElementType ElementTy,
-                                       uint32_t ElementCount,
-                                       uint32_t SampleCount);
-
-  static ResourceInfo UAV(Value *Symbol, StringRef Name,
-                          dxil::ElementType ElementTy, uint32_t ElementCount,
-                          bool GloballyCoherent, bool IsROV,
-                          dxil::ResourceKind Kind);
-  static ResourceInfo RWRawBuffer(Value *Symbol, StringRef Name,
-                                  bool GloballyCoherent, bool IsROV);
-  static ResourceInfo RWStructuredBuffer(Value *Symbol, StringRef Name,
-                                         uint32_t Stride, MaybeAlign Alignment,
-                                         bool GloballyCoherent, bool IsROV,
-                                         bool HasCounter);
-  static ResourceInfo RWTexture2DMS(Value *Symbol, StringRef Name,
-                                    dxil::ElementType ElementTy,
-                                    uint32_t ElementCount, uint32_t SampleCount,
-                                    bool GloballyCoherent);
-  static ResourceInfo RWTexture2DMSArray(Value *Symbol, StringRef Name,
-                                         dxil::ElementType ElementTy,
-                                         uint32_t ElementCount,
-                                         uint32_t SampleCount,
-                                         bool GloballyCoherent);
-  static ResourceInfo FeedbackTexture2D(Value *Symbol, StringRef Name,
-                                        dxil::SamplerFeedbackType FeedbackTy);
-  static ResourceInfo
-  FeedbackTexture2DArray(Value *Symbol, StringRef Name,
-                         dxil::SamplerFeedbackType FeedbackTy);
-
-  static ResourceInfo CBuffer(Value *Symbol, StringRef Name, uint32_t Size);
-
-  static ResourceInfo Sampler(Value *Symbol, StringRef Name,
-                              dxil::SamplerType SamplerTy);
-
-  MDTuple *getAsMetadata(LLVMContext &Ctx) const;
-
-  std::pair<uint32_t, uint32_t> getAnnotateProps() const;
-
-  void print(raw_ostream &OS) const;
+  virtual void anchor();
+
+public:
+  static char ID;
+  DXILResourceTypeWrapperPass();
+
+  DXILResourceTypeMap &getResourceTypeMap() { return DRTM; }
+  const DXILResourceTypeMap &getResourceTypeMap() const { return DRTM; }
 };
 
-} // namespace dxil
+ModulePass *createDXILResourceTypeWrapperPassPass();
 
-class DXILResourceMap {
-  SmallVector<dxil::ResourceInfo> Resources;
+//===----------------------------------------------------------------------===//
+
+class DXILBindingMap {
+  SmallVector<dxil::ResourceBindingInfo> Infos;
   DenseMap<CallInst *, unsigned> CallMap;
   unsigned FirstUAV = 0;
   unsigned FirstCBuffer = 0;
   unsigned FirstSampler = 0;
 
-public:
-  using iterator = SmallVector<dxil::ResourceInfo>::iterator;
-  using const_iterator = SmallVector<dxil::ResourceInfo>::const_iterator;
+  /// Populate the map given the resource binding calls in the given module.
+  void populate(Module &M, DXILResourceTypeMap &DRTM);
 
-  DXILResourceMap(
-      SmallVectorImpl<std::pair<CallInst *, dxil::ResourceInfo>> &&CIToRI);
+public:
+  using iterator = SmallVector<dxil::ResourceBindingInfo>::iterator;
+  using const_iterator = SmallVector<dxil::ResourceBindingInfo>::const_iterator;
 
-  iterator begin() { return Resources.begin(); }
-  const_iterator begin() const { return Resources.begin(); }
-  iterator end() { return Resources.end(); }
-  const_iterator end() const { return Resources.end(); }
+  iterator begin() { return Infos.begin(); }
+  const_iterator begin() const { return Infos.begin(); }
+  iterator end() { return Infos.end(); }
+  const_iterator end() const { return Infos.end(); }
 
-  bool empty() const { return Resources.empty(); }
+  bool empty() const { return Infos.empty(); }
 
   iterator find(const CallInst *Key) {
     auto Pos = CallMap.find(Key);
-    return Pos == CallMap.end() ? Resources.end()
-                                : (Resources.begin() + Pos->second);
+    return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
   }
 
   const_iterator find(const CallInst *Key) const {
     auto Pos = CallMap.find(Key);
-    return Pos == CallMap.end() ? Resources.end()
-                                : (Resources.begin() + Pos->second);
+    return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
   }
 
   iterator srv_begin() { return begin(); }
@@ -334,44 +502,51 @@ class DXILResourceMap {
     return make_range(sampler_begin(), sampler_end());
   }
 
-  void print(raw_ostream &OS) const;
+  void print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
+             const DataLayout &DL) const;
+
+  friend class DXILResourceBindingAnalysis;
+  friend class DXILResourceBindingWrapperPass;
 };
 
-class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {
-  friend AnalysisInfoMixin<DXILResourceAnalysis>;
+class DXILResourceBindingAnalysis
+    : public AnalysisInfoMixin<DXILResourceBindingAnalysis> {
+  friend AnalysisInfoMixin<DXILResourceBindingAnalysis>;
 
   static AnalysisKey Key;
 
 public:
-  using Result = DXILResourceMap;
+  using Result = DXILBindingMap;
 
   /// Gather resource info for the module \c M.
-  DXILResourceMap run(Module &M, ModuleAnalysisManager &AM);
+  DXILBindingMap run(Module &M, ModuleAnalysisManager &AM);
 };
 
-/// Printer pass for the \c DXILResourceAnalysis results.
-class DXILResourcePrinterPass : public PassInfoMixin<DXILResourcePrinterPass> {
+/// Printer pass for the \c DXILResourceBindingAnalysis results.
+class DXILResourceBindingPrinterPass
+    : public PassInfoMixin<DXILResourceBindingPrinterPass> {
   raw_ostream &OS;
 
 public:
-  explicit DXILResourcePrinterPass(raw_ostream &OS) : OS(OS) {}
+  explicit DXILResourceBindingPrinterPass(raw_ostream &OS) : OS(OS) {}
 
   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
 
   static bool isRequired() { return true; }
 };
 
-class DXILResourceWrapperPass : public ModulePass {
-  std::unique_ptr<DXILResourceMap> ResourceMap;
+class DXILResourceBindingWrapperPass : public ModulePass {
+  std::unique_ptr<DXILBindingMap> Map;
+  DXILResourceTypeMap *DRTM;
 
 public:
   static char ID; // Class identification, replacement for typeinfo
 
-  DXILResourceWrapperPass();
-  ~DXILResourceWrapperPass() override;
+  DXILResourceBindingWrapperPass();
+  ~DXILResourceBindingWrapperPass() override;
 
-  const DXILResourceMap &getResourceMap() const { return *ResourceMap; }
-  DXILResourceMap &getResourceMap() { return *ResourceMap; }
+  const DXILBindingMap &getBindingMap() const { return *Map; }
+  DXILBindingMap &getBindingMap() { return *Map; }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override;
   bool runOnModule(Module &M) override;
@@ -381,7 +556,7 @@ class DXILResourceWrapperPass : public ModulePass {
   void dump() const;
 };
 
-ModulePass *createDXILResourceWrapperPassPass();
+ModulePass *createDXILResourceBindingWrapperPassPass();
 
 } // namespace llvm
 
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 7d829cf5b9b015..1cb9013bc48cc5 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -84,7 +84,8 @@ void initializeDAHPass(PassRegistry &);
 void initializeDCELegacyPassPass(PassRegistry &);
 void initializeDXILMetadataAnalysisWrapperPassPass(PassRegistry &);
 void initializeDXILMetadataAnalysisWrapperPrinterPass(PassRegistry &);
-void initializeDXILResourceWrapperPassPass(PassRegistry &);
+void initializeDXILResourceBindingWrapperPassPass(PassRegistry &);
+void initializeDXILResourceTypeWrapperPassPass(PassRegistry &);
 void initializeDeadMachineInstructionElimPass(PassRegistry &);
 void initializeDebugifyMachineModulePass(PassRegistry &);
 void initializeDependenceAnalysisWrapperPassPass(PassRegistry &);
diff --git a/llvm/include/llvm/LinkAllPasses.h b/llvm/include/llvm/LinkAllPasses.h
index 54245ca0b70222..ac1970334de0cd 100644
--- a/llvm/include/llvm/LinkAllPasses.h
+++ b/llvm/include/llvm/LinkAllPasses.h
@@ -70,7 +70,8 @@ struct ForcePassLinking {
     (void)llvm::createCallGraphViewerPass();
     (void)llvm::createCFGSimplificationPass();
     (void)llvm::createStructurizeCFGPass();
-    (void)llvm::createDXILResourceWrapperPassPass();
+    (void)llvm::createDXILResourceBindingWrapperPassPass();
+    (void)llvm::createDXILResourceTypeWrapperPassPass();
     (void)llvm::createDeadArgEliminationPass();
     (void)llvm::createDeadCodeEliminationPass();
     (void)llvm::createDependenceAnalysisWrapperPass();
diff --git a/llvm/lib/Analysis/Analysis.cpp b/llvm/lib/Analysis/Analysis.cpp
index 58723469f21ca8..bc2b8a57f83a7a 100644
--- a/llvm/lib/Analysis/Analysis.cpp
+++ b/llvm/lib/Analysis/Analysis.cpp
@@ -25,7 +25,8 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
   initializeCallGraphDOTPrinterPass(Registry);
   initializeCallGraphViewerPass(Registry);
   initializeCycleInfoWrapperPassPass(Registry);
-  initializeDXILResourceWrapperPassPass(Registry);
+  initializeDXILResourceBindingWrapperPassPass(Registry);
+  initializeDXILResourceTypeWrapperPassPass(Registry);
   initializeDependenceAnalysisWrapperPassPass(Registry);
   initializeDominanceFrontierWrapperPassPass(Registry);
   initializeDomViewerWrapperPassPass(Registry);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 2802480481690d..9f992ee1a8277f 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/Analysis/DXILResource.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/DiagnosticInfo.h"
@@ -17,6 +18,7 @@
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/InitializePasses.h"
+#include "llvm/Support/FormatVariadic.h"
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -148,17 +150,159 @@ static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) {
   llvm_unreachable("Unhandled SamplerFeedbackType");
 }
 
-bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; }
+static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) {
+  // TODO: Handle unorm, snorm, and packed.
+  Ty = Ty->getScalarType();
+
+  if (Ty->isIntegerTy()) {
+    switch (Ty->getIntegerBitWidth()) {
+    case 16:
+      return IsSigned ? ElementType::I16 : ElementType::U16;
+    case 32:
+      return IsSigned ? ElementType::I32 : ElementType::U32;
+    case 64:
+      return IsSigned ? ElementType::I64 : ElementType::U64;
+    case 1:
+    default:
+      return ElementType::Invalid;
+    }
+  } else if (Ty->isFloatTy()) {
+    return ElementType::F32;
+  } else if (Ty->isDoubleTy()) {
+    return ElementType::F64;
+  } else if (Ty->isHalfTy()) {
+    return ElementType::F16;
+  }
+
+  return ElementType::Invalid;
+}
+
+ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
+                                   const dxil::ResourceClass RC_,
+                                   const dxil::ResourceKind Kind_,
+                                   bool GloballyCoherent, bool HasCounter)
+    : HandleTy(HandleTy), GloballyCoherent(GloballyCoherent),
+      HasCounter(HasCounter) {
+  // If we're provided a resource class and kind, trust them.
+  if (Kind_ != dxil::ResourceKind::Invalid) {
+    RC = RC_;
+    Kind = Kind_;
+    return;
+  }
+
+  if (auto *Ty = dyn_cast<RawBufferExtType>(HandleTy)) {
+    RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
+    Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer
+                              : ResourceKind::RawBuffer;
+  } else if (auto *Ty = dyn_cast<TypedBufferExtType>(HandleTy)) {
+    RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
+    Kind = ResourceKind::TypedBuffer;
+  } else if (auto *Ty = dyn_cast<TextureExtType>(HandleTy)) {
+    RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
+    Kind = Ty->getDimension();
+  } else if (auto *Ty = dyn_cast<MSTextureExtType>(HandleTy)) {
+    RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV;
+    Kind = Ty->getDimension();
+  } else if (auto *Ty = dyn_cast<FeedbackTextureExtType>(HandleTy)) {
+    RC = ResourceClass::UAV;
+    Kind = Ty->getDimension();
+  } else if (isa<CBufferExtType>(HandleTy)) {
+    RC = ResourceClass::CBuffer;
+    Kind = ResourceKind::CBuffer;
+  } else if (isa<SamplerExtType>(HandleTy)) {
+    RC = ResourceClass::Sampler;
+    Kind = ResourceKind::Sampler;
+  } else
+    llvm_unreachable("Unknown handle type");
+}
+
+static void formatTypeName(SmallString<64> &Dest, StringRef Name,
+                           bool isWriteable, bool isROV) {
+  Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";
+  Dest += Name;
+}
+
+StructType *ResourceTypeInfo::createElementStruct() {
+  SmallString<64> TypeName;
+
+  switch (Kind) {
+  case ResourceKind::Texture1D:
+  case ResourceKind::Texture2D:
+  case ResourceKind::Texture3D:
+  case ResourceKind::TextureCube:
+  case ResourceKind::Texture1DArray:
+  case ResourceKind::Texture2DArray:
+  case ResourceKind::TextureCubeArray: {
+    auto *RTy = cast<TextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::Texture2DMS:
+  case ResourceKind::Texture2DMSArray: {
+    auto *RTy = cast<MSTextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   /*IsROV=*/false);
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::TypedBuffer: {
+    auto *RTy = cast<TypedBufferExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::RawBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(HandleTy->getContext(), TypeName);
+  }
+  case ResourceKind::StructuredBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::FeedbackTexture2D:
+  case ResourceKind::FeedbackTexture2DArray: {
+    auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
+    TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
+                       llvm::to_underlying(RTy->getFeedbackType()));
+    return StructType::create(HandleTy->getContext(), TypeName);
+  }
+  case ResourceKind::CBuffer:
+    return StructType::create(HandleTy->getContext(), "cbuffer");
+  case ResourceKind::Sampler: {
+    auto *RTy = cast<SamplerExtType>(HandleTy);
+    TypeName = formatv("SamplerState<{0}>",
+                       llvm::to_underlying(RTy->getSamplerType()));
+    return StructType::create(HandleTy->getContext(), TypeName);
+  }
+  case ResourceKind::TBuffer:
+  case ResourceKind::RTAccelerationStructure:
+    llvm_unreachable("Unhandled resource kind");
+  case ResourceKind::Invalid:
+  case ResourceKind::NumEntries:
+    llvm_unreachable("Invalid resource kind");
+  }
+  llvm_unreachable("Unhandled ResourceKind enum");
+}
 
-bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; }
+bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
 
-bool ResourceInfo::isSampler() const { return RC == ResourceClass::Sampler; }
+bool ResourceTypeInfo::isCBuffer() const {
+  return RC == ResourceClass::CBuffer;
+}
+
+bool ResourceTypeInfo::isSampler() const {
+  return RC == ResourceClass::Sampler;
+}
 
-bool ResourceInfo::isStruct() const {
+bool ResourceTypeInfo::isStruct() const {
   return Kind == ResourceKind::StructuredBuffer;
 }
 
-bool ResourceInfo::isTyped() const {
+bool ResourceTypeInfo::isTyped() const {
   switch (Kind) {
   case ResourceKind::Texture1D:
   case ResourceKind::Texture2D:
@@ -187,194 +331,216 @@ bool ResourceInfo::isTyped() const {
   llvm_unreachable("Unhandled ResourceKind enum");
 }
 
-bool ResourceInfo::isFeedback() const {
+bool ResourceTypeInfo::isFeedback() const {
   return Kind == ResourceKind::FeedbackTexture2D ||
          Kind == ResourceKind::FeedbackTexture2DArray;
 }
 
-bool ResourceInfo::isMultiSample() const {
+bool ResourceTypeInfo::isMultiSample() const {
   return Kind == ResourceKind::Texture2DMS ||
          Kind == ResourceKind::Texture2DMSArray;
 }
 
-ResourceInfo ResourceInfo::SRV(Value *Symbol, StringRef Name,
-                               ElementType ElementTy, uint32_t ElementCount,
-                               ResourceKind Kind) {
-  ResourceInfo RI(ResourceClass::SRV, Kind, Symbol, Name);
-  assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
-         "Invalid ResourceKind for SRV constructor.");
-  RI.setTyped(ElementTy, ElementCount);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::RawBuffer(Value *Symbol, StringRef Name) {
-  ResourceInfo RI(ResourceClass::SRV, ResourceKind::RawBuffer, Symbol, Name);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::StructuredBuffer(Value *Symbol, StringRef Name,
-                                            uint32_t Stride,
-                                            MaybeAlign Alignment) {
-  ResourceInfo RI(ResourceClass::SRV, ResourceKind::StructuredBuffer, Symbol,
-                  Name);
-  RI.setStruct(Stride, Alignment);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::Texture2DMS(Value *Symbol, StringRef Name,
-                                       ElementType ElementTy,
-                                       uint32_t ElementCount,
-                                       uint32_t SampleCount) {
-  ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMS, Symbol, Name);
-  RI.setTyped(ElementTy, ElementCount);
-  RI.setMultiSample(SampleCount);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::Texture2DMSArray(Value *Symbol, StringRef Name,
-                                            ElementType ElementTy,
-                                            uint32_t ElementCount,
-                                            uint32_t SampleCount) {
-  ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMSArray, Symbol,
-                  Name);
-  RI.setTyped(ElementTy, ElementCount);
-  RI.setMultiSample(SampleCount);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::UAV(Value *Symbol, StringRef Name,
-                               ElementType ElementTy, uint32_t ElementCount,
-                               bool GloballyCoherent, bool IsROV,
-                               ResourceKind Kind) {
-  ResourceInfo RI(ResourceClass::UAV, Kind, Symbol, Name);
-  assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) &&
-         "Invalid ResourceKind for UAV constructor.");
-  RI.setTyped(ElementTy, ElementCount);
-  RI.setUAV(GloballyCoherent, /*HasCounter=*/false, IsROV);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::RWRawBuffer(Value *Symbol, StringRef Name,
-                                       bool GloballyCoherent, bool IsROV) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::RawBuffer, Symbol, Name);
-  RI.setUAV(GloballyCoherent, /*HasCounter=*/false, IsROV);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::RWStructuredBuffer(Value *Symbol, StringRef Name,
-                                              uint32_t Stride,
-                                              MaybeAlign Alignment,
-                                              bool GloballyCoherent, bool IsROV,
-                                              bool HasCounter) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::StructuredBuffer, Symbol,
-                  Name);
-  RI.setStruct(Stride, Alignment);
-  RI.setUAV(GloballyCoherent, HasCounter, IsROV);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::RWTexture2DMS(Value *Symbol, StringRef Name,
-                                         ElementType ElementTy,
-                                         uint32_t ElementCount,
-                                         uint32_t SampleCount,
-                                         bool GloballyCoherent) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMS, Symbol, Name);
-  RI.setTyped(ElementTy, ElementCount);
-  RI.setUAV(GloballyCoherent, /*HasCounter=*/false, /*IsROV=*/false);
-  RI.setMultiSample(SampleCount);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::RWTexture2DMSArray(Value *Symbol, StringRef Name,
-                                              ElementType ElementTy,
-                                              uint32_t ElementCount,
-                                              uint32_t SampleCount,
-                                              bool GloballyCoherent) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMSArray, Symbol,
-                  Name);
-  RI.setTyped(ElementTy, ElementCount);
-  RI.setUAV(GloballyCoherent, /*HasCounter=*/false, /*IsROV=*/false);
-  RI.setMultiSample(SampleCount);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::FeedbackTexture2D(Value *Symbol, StringRef Name,
-                                             SamplerFeedbackType FeedbackTy) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2D, Symbol,
-                  Name);
-  RI.setUAV(/*GloballyCoherent=*/false, /*HasCounter=*/false, /*IsROV=*/false);
-  RI.setFeedback(FeedbackTy);
-  return RI;
-}
-
-ResourceInfo
-ResourceInfo::FeedbackTexture2DArray(Value *Symbol, StringRef Name,
-                                     SamplerFeedbackType FeedbackTy) {
-  ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2DArray,
-                  Symbol, Name);
-  RI.setUAV(/*GloballyCoherent=*/false, /*HasCounter=*/false, /*IsROV=*/false);
-  RI.setFeedback(FeedbackTy);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::CBuffer(Value *Symbol, StringRef Name,
-                                   uint32_t Size) {
-  ResourceInfo RI(ResourceClass::CBuffer, ResourceKind::CBuffer, Symbol, Name);
-  RI.setCBuffer(Size);
-  return RI;
-}
-
-ResourceInfo ResourceInfo::Sampler(Value *Symbol, StringRef Name,
-                                   SamplerType SamplerTy) {
-  ResourceInfo RI(ResourceClass::Sampler, ResourceKind::Sampler, Symbol, Name);
-  RI.setSampler(SamplerTy);
-  return RI;
-}
-
-bool ResourceInfo::operator==(const ResourceInfo &RHS) const {
-  if (std::tie(Symbol, Name, Binding, RC, Kind) !=
-      std::tie(RHS.Symbol, RHS.Name, RHS.Binding, RHS.RC, RHS.Kind))
-    return false;
-  if (isCBuffer() && RHS.isCBuffer() && CBufferSize != RHS.CBufferSize)
-    return false;
-  if (isSampler() && RHS.isSampler() && SamplerTy != RHS.SamplerTy)
-    return false;
-  if (isUAV() && RHS.isUAV() && UAVFlags != RHS.UAVFlags)
-    return false;
-  if (isStruct() && RHS.isStruct() && Struct != RHS.Struct)
-    return false;
-  if (isFeedback() && RHS.isFeedback() && Feedback != RHS.Feedback)
-    return false;
-  if (isTyped() && RHS.isTyped() && Typed != RHS.Typed)
-    return false;
-  if (isMultiSample() && RHS.isMultiSample() && MultiSample != RHS.MultiSample)
+static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) {
+  switch (Kind) {
+  case ResourceKind::Texture1D:
+  case ResourceKind::Texture2D:
+  case ResourceKind::Texture3D:
+  case ResourceKind::TextureCube:
+  case ResourceKind::Texture1DArray:
+  case ResourceKind::Texture2DArray:
+  case ResourceKind::TextureCubeArray:
+    return cast<TextureExtType>(Ty)->isROV();
+  case ResourceKind::TypedBuffer:
+    return cast<TypedBufferExtType>(Ty)->isROV();
+  case ResourceKind::RawBuffer:
+  case ResourceKind::StructuredBuffer:
+    return cast<RawBufferExtType>(Ty)->isROV();
+  case ResourceKind::Texture2DMS:
+  case ResourceKind::Texture2DMSArray:
+  case ResourceKind::FeedbackTexture2D:
+  case ResourceKind::FeedbackTexture2DArray:
     return false;
-  return true;
+  case ResourceKind::CBuffer:
+  case ResourceKind::Sampler:
+  case ResourceKind::TBuffer:
+  case ResourceKind::RTAccelerationStructure:
+  case ResourceKind::Invalid:
+  case ResourceKind::NumEntries:
+    llvm_unreachable("Resource cannot be ROV");
+  }
+  llvm_unreachable("Unhandled ResourceKind enum");
+}
+
+ResourceTypeInfo::UAVInfo ResourceTypeInfo::getUAV() const {
+  assert(isUAV() && "Not a UAV");
+  return {GloballyCoherent, HasCounter, isROV(Kind, HandleTy)};
+}
+
+uint32_t ResourceTypeInfo::getCBufferSize(const DataLayout &DL) const {
+  assert(isCBuffer() && "Not a CBuffer");
+  Type *Ty = cast<CBufferExtType>(HandleTy)->getResourceType();
+  return DL.getTypeSizeInBits(Ty) / 8;
+}
+
+dxil::SamplerType ResourceTypeInfo::getSamplerType() const {
+  assert(isSampler() && "Not a Sampler");
+  return cast<SamplerExtType>(HandleTy)->getSamplerType();
+}
+
+ResourceTypeInfo::StructInfo
+ResourceTypeInfo::getStruct(const DataLayout &DL) const {
+  assert(isStruct() && "Not a Struct");
+
+  Type *ElTy = cast<RawBufferExtType>(HandleTy)->getResourceType();
+
+  uint32_t Stride = DL.getTypeAllocSize(ElTy);
+  MaybeAlign Alignment;
+  if (auto *STy = dyn_cast<StructType>(ElTy))
+    Alignment = DL.getStructLayout(STy)->getAlignment();
+  uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0;
+  return {Stride, AlignLog2};
+}
+
+static std::pair<Type *, bool> getTypedElementType(dxil::ResourceKind Kind,
+                                                   TargetExtType *Ty) {
+  switch (Kind) {
+  case ResourceKind::Texture1D:
+  case ResourceKind::Texture2D:
+  case ResourceKind::Texture3D:
+  case ResourceKind::TextureCube:
+  case ResourceKind::Texture1DArray:
+  case ResourceKind::Texture2DArray:
+  case ResourceKind::TextureCubeArray: {
+    auto *RTy = cast<TextureExtType>(Ty);
+    return {RTy->getResourceType(), RTy->isSigned()};
+  }
+  case ResourceKind::Texture2DMS:
+  case ResourceKind::Texture2DMSArray: {
+    auto *RTy = cast<MSTextureExtType>(Ty);
+    return {RTy->getResourceType(), RTy->isSigned()};
+  }
+  case ResourceKind::TypedBuffer: {
+    auto *RTy = cast<TypedBufferExtType>(Ty);
+    return {RTy->getResourceType(), RTy->isSigned()};
+  }
+  case ResourceKind::RawBuffer:
+  case ResourceKind::StructuredBuffer:
+  case ResourceKind::FeedbackTexture2D:
+  case ResourceKind::FeedbackTexture2DArray:
+  case ResourceKind::CBuffer:
+  case ResourceKind::Sampler:
+  case ResourceKind::TBuffer:
+  case ResourceKind::RTAccelerationStructure:
+  case ResourceKind::Invalid:
+  case ResourceKind::NumEntries:
+    llvm_unreachable("Resource is not typed");
+  }
+  llvm_unreachable("Unhandled ResourceKind enum");
+}
+
+ResourceTypeInfo::TypedInfo ResourceTypeInfo::getTyped() const {
+  assert(isTyped() && "Not typed");
+
+  auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy);
+  dxil::ElementType ET = toDXILElementType(ElTy, IsSigned);
+  uint32_t Count = 1;
+  if (auto *VTy = dyn_cast<FixedVectorType>(ElTy))
+    Count = VTy->getNumElements();
+  return {ET, Count};
 }
 
-bool ResourceInfo::operator<(const ResourceInfo &RHS) const {
-  // Skip the symbol to avoid non-determinism, and the name to keep a consistent
-  // ordering even when we strip reflection data.
-  if (std::tie(Binding, RC, Kind) < std::tie(RHS.Binding, RHS.RC, RHS.Kind))
+dxil::SamplerFeedbackType ResourceTypeInfo::getFeedbackType() const {
+  assert(isFeedback() && "Not Feedback");
+  return cast<FeedbackTextureExtType>(HandleTy)->getFeedbackType();
+}
+uint32_t ResourceTypeInfo::getMultiSampleCount() const {
+  assert(isMultiSample() && "Not MultiSampled");
+  return cast<MSTextureExtType>(HandleTy)->getSampleCount();
+}
+
+bool ResourceTypeInfo::operator==(const ResourceTypeInfo &RHS) const {
+  return std::tie(HandleTy, GloballyCoherent, HasCounter) ==
+         std::tie(RHS.HandleTy, RHS.GloballyCoherent, RHS.HasCounter);
+}
+
+bool ResourceTypeInfo::operator<(const ResourceTypeInfo &RHS) const {
+  // An empty datalayout is sufficient for sorting purposes.
+  DataLayout DummyDL;
+  if (std::tie(RC, Kind) < std::tie(RHS.RC, RHS.Kind))
     return true;
-  if (isCBuffer() && RHS.isCBuffer() && CBufferSize < RHS.CBufferSize)
+  if (isCBuffer() && RHS.isCBuffer() &&
+      getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL))
     return true;
-  if (isSampler() && RHS.isSampler() && SamplerTy < RHS.SamplerTy)
+  if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType())
     return true;
-  if (isUAV() && RHS.isUAV() && UAVFlags < RHS.UAVFlags)
+  if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV())
     return true;
-  if (isStruct() && RHS.isStruct() && Struct < RHS.Struct)
+  if (isStruct() && RHS.isStruct() &&
+      getStruct(DummyDL) < RHS.getStruct(DummyDL))
     return true;
-  if (isFeedback() && RHS.isFeedback() && Feedback < RHS.Feedback)
+  if (isFeedback() && RHS.isFeedback() &&
+      getFeedbackType() < RHS.getFeedbackType())
     return true;
-  if (isTyped() && RHS.isTyped() && Typed < RHS.Typed)
+  if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped())
     return true;
-  if (isMultiSample() && RHS.isMultiSample() && MultiSample < RHS.MultiSample)
+  if (isMultiSample() && RHS.isMultiSample() &&
+      getMultiSampleCount() < RHS.getMultiSampleCount())
     return true;
   return false;
 }
 
-MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
+void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
+  OS << "  Class: " << getResourceClassName(RC) << "\n"
+     << "  Kind: " << getResourceKindName(Kind) << "\n";
+
+  if (isCBuffer()) {
+    OS << "  CBuffer size: " << getCBufferSize(DL) << "\n";
+  } else if (isSampler()) {
+    OS << "  Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n";
+  } else {
+    if (isUAV()) {
+      UAVInfo UAVFlags = getUAV();
+      OS << "  Globally Coherent: " << UAVFlags.GloballyCoherent << "\n"
+         << "  HasCounter: " << UAVFlags.HasCounter << "\n"
+         << "  IsROV: " << UAVFlags.IsROV << "\n";
+    }
+    if (isMultiSample())
+      OS << "  Sample Count: " << getMultiSampleCount() << "\n";
+
+    if (isStruct()) {
+      StructInfo Struct = getStruct(DL);
+      OS << "  Buffer Stride: " << Struct.Stride << "\n";
+      OS << "  Alignment: " << Struct.AlignLog2 << "\n";
+    } else if (isTyped()) {
+      TypedInfo Typed = getTyped();
+      OS << "  Element Type: " << getElementTypeName(Typed.ElementTy) << "\n"
+         << "  Element Count: " << Typed.ElementCount << "\n";
+    } else if (isFeedback())
+      OS << "  Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType())
+         << "\n";
+  }
+}
+
+GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
+                                                  StringRef Name) {
+  assert(!Symbol && "Symbol has already been created");
+  Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
+                              GlobalValue::ExternalLinkage,
+                              /*Initializer=*/nullptr, Name);
+  return Symbol;
+}
+
+MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
+                                            DXILResourceTypeMap &DRTM) const {
+  return getAsMetadata(M, DRTM[getHandleTy()]);
+}
+
+MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
+                                            dxil::ResourceTypeInfo RTI) const {
+  LLVMContext &Ctx = M.getContext();
+  const DataLayout &DL = M.getDataLayout();
+
   SmallVector<Metadata *, 11> MDVals;
 
   Type *I32Ty = Type::getInt32Ty(Ctx);
@@ -389,22 +555,24 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
   };
 
   MDVals.push_back(getIntMD(Binding.RecordID));
+  assert(Symbol && "Cannot yet create useful resource metadata without symbol");
   MDVals.push_back(ValueAsMetadata::get(Symbol));
-  MDVals.push_back(MDString::get(Ctx, Name));
+  MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
   MDVals.push_back(getIntMD(Binding.Space));
   MDVals.push_back(getIntMD(Binding.LowerBound));
   MDVals.push_back(getIntMD(Binding.Size));
 
-  if (isCBuffer()) {
-    MDVals.push_back(getIntMD(CBufferSize));
+  if (RTI.isCBuffer()) {
+    MDVals.push_back(getIntMD(RTI.getCBufferSize(DL)));
     MDVals.push_back(nullptr);
-  } else if (isSampler()) {
-    MDVals.push_back(getIntMD(llvm::to_underlying(SamplerTy)));
+  } else if (RTI.isSampler()) {
+    MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getSamplerType())));
     MDVals.push_back(nullptr);
   } else {
-    MDVals.push_back(getIntMD(llvm::to_underlying(Kind)));
+    MDVals.push_back(getIntMD(llvm::to_underlying(RTI.getResourceKind())));
 
-    if (isUAV()) {
+    if (RTI.isUAV()) {
+      ResourceTypeInfo::UAVInfo UAVFlags = RTI.getUAV();
       MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent));
       MDVals.push_back(getBoolMD(UAVFlags.HasCounter));
       MDVals.push_back(getBoolMD(UAVFlags.IsROV));
@@ -412,23 +580,24 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
       // All SRVs include sample count in the metadata, but it's only meaningful
       // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+,
       // but this just isn't reflected in the metadata at all.
-      uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
+      uint32_t SampleCount =
+          RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
       MDVals.push_back(getIntMD(SampleCount));
     }
 
     // Further properties are attached to a metadata list of tag-value pairs.
     SmallVector<Metadata *> Tags;
-    if (isStruct()) {
+    if (RTI.isStruct()) {
       Tags.push_back(
           getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride)));
-      Tags.push_back(getIntMD(Struct.Stride));
-    } else if (isTyped()) {
+      Tags.push_back(getIntMD(RTI.getStruct(DL).Stride));
+    } else if (RTI.isTyped()) {
       Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType)));
-      Tags.push_back(getIntMD(llvm::to_underlying(Typed.ElementTy)));
-    } else if (isFeedback()) {
+      Tags.push_back(getIntMD(llvm::to_underlying(RTI.getTyped().ElementTy)));
+    } else if (RTI.isFeedback()) {
       Tags.push_back(
           getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind)));
-      Tags.push_back(getIntMD(llvm::to_underlying(Feedback.Type)));
+      Tags.push_back(getIntMD(llvm::to_underlying(RTI.getFeedbackType())));
     }
     MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags));
   }
@@ -436,17 +605,29 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
   return MDNode::get(Ctx, MDVals);
 }
 
-std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const {
-  uint32_t ResourceKind = llvm::to_underlying(Kind);
-  uint32_t AlignLog2 = isStruct() ? Struct.AlignLog2 : 0;
-  bool IsUAV = isUAV();
+std::pair<uint32_t, uint32_t>
+ResourceBindingInfo::getAnnotateProps(Module &M,
+                                      DXILResourceTypeMap &DRTM) const {
+  return getAnnotateProps(M, DRTM[getHandleTy()]);
+}
+
+std::pair<uint32_t, uint32_t>
+ResourceBindingInfo::getAnnotateProps(Module &M,
+                                      dxil::ResourceTypeInfo RTI) const {
+  const DataLayout &DL = M.getDataLayout();
+
+  uint32_t ResourceKind = llvm::to_underlying(RTI.getResourceKind());
+  uint32_t AlignLog2 = RTI.isStruct() ? RTI.getStruct(DL).AlignLog2 : 0;
+  bool IsUAV = RTI.isUAV();
+  ResourceTypeInfo::UAVInfo UAVFlags =
+      IsUAV ? RTI.getUAV() : ResourceTypeInfo::UAVInfo{};
   bool IsROV = IsUAV && UAVFlags.IsROV;
   bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent;
   uint8_t SamplerCmpOrHasCounter = 0;
   if (IsUAV)
     SamplerCmpOrHasCounter = UAVFlags.HasCounter;
-  else if (isSampler())
-    SamplerCmpOrHasCounter = SamplerTy == SamplerType::Comparison;
+  else if (RTI.isSampler())
+    SamplerCmpOrHasCounter = RTI.getSamplerType() == SamplerType::Comparison;
 
   // TODO: Document this format. Currently the only reference is the
   // implementation of dxc's DxilResourceProperties struct.
@@ -459,16 +640,17 @@ std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const {
   Word0 |= (SamplerCmpOrHasCounter & 1) << 15;
 
   uint32_t Word1 = 0;
-  if (isStruct())
-    Word1 = Struct.Stride;
-  else if (isCBuffer())
-    Word1 = CBufferSize;
-  else if (isFeedback())
-    Word1 = llvm::to_underlying(Feedback.Type);
-  else if (isTyped()) {
+  if (RTI.isStruct())
+    Word1 = RTI.getStruct(DL).Stride;
+  else if (RTI.isCBuffer())
+    Word1 = RTI.getCBufferSize(DL);
+  else if (RTI.isFeedback())
+    Word1 = llvm::to_underlying(RTI.getFeedbackType());
+  else if (RTI.isTyped()) {
+    ResourceTypeInfo::TypedInfo Typed = RTI.getTyped();
     uint32_t CompType = llvm::to_underlying(Typed.ElementTy);
     uint32_t CompCount = Typed.ElementCount;
-    uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0;
+    uint32_t SampleCount = RTI.isMultiSample() ? RTI.getMultiSampleCount() : 0;
 
     Word1 |= (CompType & 0xFF) << 0;
     Word1 |= (CompCount & 0xFF) << 8;
@@ -478,276 +660,119 @@ std::pair<uint32_t, uint32_t> ResourceInfo::getAnnotateProps() const {
   return {Word0, Word1};
 }
 
-void ResourceInfo::print(raw_ostream &OS) const {
-  OS << "  Symbol: ";
-  Symbol->printAsOperand(OS);
-  OS << "\n";
+void ResourceBindingInfo::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
+                                const DataLayout &DL) const {
+  print(OS, DRTM[getHandleTy()], DL);
+}
+
+void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo RTI,
+                                const DataLayout &DL) const {
+  if (Symbol) {
+    OS << "  Symbol: ";
+    Symbol->printAsOperand(OS);
+    OS << "\n";
+  }
 
-  OS << "  Name: \"" << Name << "\"\n"
-     << "  Binding:\n"
+  OS << "  Binding:\n"
      << "    Record ID: " << Binding.RecordID << "\n"
      << "    Space: " << Binding.Space << "\n"
      << "    Lower Bound: " << Binding.LowerBound << "\n"
-     << "    Size: " << Binding.Size << "\n"
-     << "  Class: " << getResourceClassName(RC) << "\n"
-     << "  Kind: " << getResourceKindName(Kind) << "\n";
+     << "    Size: " << Binding.Size << "\n";
 
-  if (isCBuffer()) {
-    OS << "  CBuffer size: " << CBufferSize << "\n";
-  } else if (isSampler()) {
-    OS << "  Sampler Type: " << getSamplerTypeName(SamplerTy) << "\n";
-  } else {
-    if (isUAV()) {
-      OS << "  Globally Coherent: " << UAVFlags.GloballyCoherent << "\n"
-         << "  HasCounter: " << UAVFlags.HasCounter << "\n"
-         << "  IsROV: " << UAVFlags.IsROV << "\n";
-    }
-    if (isMultiSample())
-      OS << "  Sample Count: " << MultiSample.Count << "\n";
-
-    if (isStruct()) {
-      OS << "  Buffer Stride: " << Struct.Stride << "\n";
-      OS << "  Alignment: " << Struct.AlignLog2 << "\n";
-    } else if (isTyped()) {
-      OS << "  Element Type: " << getElementTypeName(Typed.ElementTy) << "\n"
-         << "  Element Count: " << Typed.ElementCount << "\n";
-    } else if (isFeedback())
-      OS << "  Feedback Type: " << getSamplerFeedbackTypeName(Feedback.Type)
-         << "\n";
-  }
+  RTI.print(OS, DL);
 }
 
 //===----------------------------------------------------------------------===//
-// ResourceMapper
-
-static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) {
-  // TODO: Handle unorm, snorm, and packed.
-  Ty = Ty->getScalarType();
-
-  if (Ty->isIntegerTy()) {
-    switch (Ty->getIntegerBitWidth()) {
-    case 16:
-      return IsSigned ? ElementType::I16 : ElementType::U16;
-    case 32:
-      return IsSigned ? ElementType::I32 : ElementType::U32;
-    case 64:
-      return IsSigned ? ElementType::I64 : ElementType::U64;
-    case 1:
-    default:
-      return ElementType::Invalid;
-    }
-  } else if (Ty->isFloatTy()) {
-    return ElementType::F32;
-  } else if (Ty->isDoubleTy()) {
-    return ElementType::F64;
-  } else if (Ty->isHalfTy()) {
-    return ElementType::F16;
-  }
 
-  return ElementType::Invalid;
+bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA,
+                                     ModuleAnalysisManager::Invalidator &Inv) {
+  // Passes that introduce resource types must explicitly invalidate this pass.
+  auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
+  return !PAC.preservedWhenStateless();
 }
 
-namespace {
-
-class ResourceMapper {
-  Module &M;
-  LLVMContext &Context;
-  SmallVector<std::pair<CallInst *, dxil::ResourceInfo>> Resources;
-
-public:
-  ResourceMapper(Module &M) : M(M), Context(M.getContext()) {}
-
-  void diagnoseHandle(CallInst *CI, const Twine &Msg,
-                      DiagnosticSeverity Severity = DS_Error) {
-    std::string S;
-    raw_string_ostream SS(S);
-    CI->printAsOperand(SS);
-    DiagnosticInfoUnsupported Diag(*CI->getFunction(), Msg + ": " + SS.str(),
-                                   CI->getDebugLoc(), Severity);
-    Context.diagnose(Diag);
-  }
-
-  ResourceInfo *mapBufferType(CallInst *CI, TargetExtType *HandleTy,
-                              bool IsTyped) {
-    if (HandleTy->getNumTypeParameters() != 1 ||
-        HandleTy->getNumIntParameters() != (IsTyped ? 3 : 2)) {
-      diagnoseHandle(CI, Twine("Invalid buffer target type"));
-      return nullptr;
-    }
-
-    Type *ElTy = HandleTy->getTypeParameter(0);
-    unsigned IsWriteable = HandleTy->getIntParameter(0);
-    unsigned IsROV = HandleTy->getIntParameter(1);
-    bool IsSigned = IsTyped && HandleTy->getIntParameter(2);
-
-    ResourceClass RC = IsWriteable ? ResourceClass::UAV : ResourceClass::SRV;
-    ResourceKind Kind;
-    if (IsTyped)
-      Kind = ResourceKind::TypedBuffer;
-    else if (ElTy->isIntegerTy(8))
-      Kind = ResourceKind::RawBuffer;
-    else
-      Kind = ResourceKind::StructuredBuffer;
-
-    // TODO: We need to lower to a typed pointer, can we smuggle the type
-    // through?
-    Value *Symbol = UndefValue::get(PointerType::getUnqual(Context));
-    // TODO: We don't actually keep track of the name right now...
-    StringRef Name = "";
-
-    // Note that we return a pointer into the vector's storage. This is okay as
-    // long as we don't add more elements until we're done with the pointer.
-    auto &Pair =
-        Resources.emplace_back(CI, ResourceInfo{RC, Kind, Symbol, Name});
-    ResourceInfo *RI = &Pair.second;
-
-    if (RI->isUAV())
-      // TODO: We need analysis for GloballyCoherent and HasCounter
-      RI->setUAV(false, false, IsROV);
-
-    if (RI->isTyped()) {
-      dxil::ElementType ET = toDXILElementType(ElTy, IsSigned);
-      uint32_t Count = 1;
-      if (auto *VTy = dyn_cast<FixedVectorType>(ElTy))
-        Count = VTy->getNumElements();
-      RI->setTyped(ET, Count);
-    } else if (RI->isStruct()) {
-      const DataLayout &DL = M.getDataLayout();
-
-      // This mimics what DXC does. Notably, we only ever set the alignment if
-      // the type is actually a struct type.
-      uint32_t Stride = DL.getTypeAllocSize(ElTy);
-      MaybeAlign Alignment;
-      if (auto *STy = dyn_cast<StructType>(ElTy))
-        Alignment = DL.getStructLayout(STy)->getAlignment();
-      RI->setStruct(Stride, Alignment);
-    }
-
-    return RI;
-  }
-
-  ResourceInfo *mapHandleIntrin(CallInst *CI) {
-    FunctionType *FTy = CI->getFunctionType();
-    Type *RetTy = FTy->getReturnType();
-    auto *HandleTy = dyn_cast<TargetExtType>(RetTy);
-    if (!HandleTy) {
-      diagnoseHandle(CI, "dx.handle.fromBinding requires target type");
-      return nullptr;
-    }
-
-    StringRef TypeName = HandleTy->getName();
-    if (TypeName == "dx.TypedBuffer") {
-      return mapBufferType(CI, HandleTy, /*IsTyped=*/true);
-    } else if (TypeName == "dx.RawBuffer") {
-      return mapBufferType(CI, HandleTy, /*IsTyped=*/false);
-    } else if (TypeName == "dx.CBuffer") {
-      // TODO: implement
-      diagnoseHandle(CI, "dx.CBuffer handles are not implemented yet");
-      return nullptr;
-    } else if (TypeName == "dx.Sampler") {
-      // TODO: implement
-      diagnoseHandle(CI, "dx.Sampler handles are not implemented yet");
-      return nullptr;
-    } else if (TypeName == "dx.Texture") {
-      // TODO: implement
-      diagnoseHandle(CI, "dx.Texture handles are not implemented yet");
-      return nullptr;
-    }
-
-    diagnoseHandle(CI, "Invalid target(dx) type");
-    return nullptr;
-  }
-
-  ResourceInfo *mapHandleFromBinding(CallInst *CI) {
-    assert(CI->getIntrinsicID() == Intrinsic::dx_handle_fromBinding &&
-           "Must be dx.handle.fromBinding intrinsic");
-
-    ResourceInfo *RI = mapHandleIntrin(CI);
-    if (!RI)
-      return nullptr;
-
-    uint32_t Space = cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
-    uint32_t LowerBound =
-        cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
-    uint32_t Size = cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
+//===----------------------------------------------------------------------===//
 
-    // We use a binding ID of zero for now - these will be filled in later.
-    RI->bind(0U, Space, LowerBound, Size);
+void DXILBindingMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
+  SmallVector<std::tuple<CallInst *, ResourceBindingInfo, ResourceTypeInfo>>
+      CIToInfos;
 
-    return RI;
-  }
+  for (Function &F : M.functions()) {
+    if (!F.isDeclaration())
+      continue;
+    LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
+    Intrinsic::ID ID = F.getIntrinsicID();
+    switch (ID) {
+    default:
+      continue;
+    case Intrinsic::dx_handle_fromBinding: {
+      auto *HandleTy = cast<TargetExtType>(F.getReturnType());
+      ResourceTypeInfo RTI = DRTM[HandleTy];
 
-  DXILResourceMap mapResources() {
-    for (Function &F : M.functions()) {
-      if (!F.isDeclaration())
-        continue;
-      LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n");
-      Intrinsic::ID ID = F.getIntrinsicID();
-      switch (ID) {
-      default:
-        // TODO: handle `dx.op` functions.
-        continue;
-      case Intrinsic::dx_handle_fromBinding:
-        for (User *U : F.users()) {
+      for (User *U : F.users())
+        if (CallInst *CI = dyn_cast<CallInst>(U)) {
           LLVM_DEBUG(dbgs() << "  Visiting: " << *U << "\n");
-          if (CallInst *CI = dyn_cast<CallInst>(U))
-            mapHandleFromBinding(CI);
+          uint32_t Space =
+              cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
+          uint32_t LowerBound =
+              cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
+          uint32_t Size =
+              cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
+          ResourceBindingInfo RBI = ResourceBindingInfo{
+              /*RecordID=*/0, Space, LowerBound, Size, HandleTy};
+
+          CIToInfos.emplace_back(CI, RBI, RTI);
         }
-        break;
-      }
-    }
 
-    return DXILResourceMap(std::move(Resources));
+      break;
+    }
+    }
   }
-};
 
-} // namespace
+  llvm::stable_sort(CIToInfos, [](auto &LHS, auto &RHS) {
+    const auto &[LCI, LRBI, LRTI] = LHS;
+    const auto &[RCI, RRBI, RRTI] = RHS;
+    // Sort by resource class first for grouping purposes, and then by the
+    // binding and type so we can remove duplicates.
+    ResourceClass LRC = LRTI.getResourceClass();
+    ResourceClass RRC = RRTI.getResourceClass();
 
-DXILResourceMap::DXILResourceMap(
-    SmallVectorImpl<std::pair<CallInst *, dxil::ResourceInfo>> &&CIToRI) {
-  if (CIToRI.empty())
-    return;
-
-  llvm::stable_sort(CIToRI, [](auto &LHS, auto &RHS) {
-    // Sort by resource class first for grouping purposes, and then by the rest
-    // of the fields so that we can remove duplicates.
-    ResourceClass LRC = LHS.second.getResourceClass();
-    ResourceClass RRC = RHS.second.getResourceClass();
-    return std::tie(LRC, LHS.second) < std::tie(RRC, RHS.second);
+    return std::tie(LRC, LRBI, LRTI) < std::tie(RRC, RRBI, RRTI);
   });
-  for (auto [CI, RI] : CIToRI) {
-    if (Resources.empty() || RI != Resources.back())
-      Resources.push_back(RI);
-    CallMap[CI] = Resources.size() - 1;
+  for (auto [CI, RBI, RTI] : CIToInfos) {
+    if (Infos.empty() || RBI != Infos.back())
+      Infos.push_back(RBI);
+    CallMap[CI] = Infos.size() - 1;
   }
 
-  unsigned Size = Resources.size();
+  unsigned Size = Infos.size();
   // In DXC, Record ID is unique per resource type. Match that.
   FirstUAV = FirstCBuffer = FirstSampler = Size;
   uint32_t NextID = 0;
   for (unsigned I = 0, E = Size; I != E; ++I) {
-    ResourceInfo &RI = Resources[I];
-    if (RI.isUAV() && FirstUAV == Size) {
+    ResourceBindingInfo &RBI = Infos[I];
+    ResourceTypeInfo RTI = DRTM[RBI.getHandleTy()];
+    if (RTI.isUAV() && FirstUAV == Size) {
       FirstUAV = I;
       NextID = 0;
-    } else if (RI.isCBuffer() && FirstCBuffer == Size) {
+    } else if (RTI.isCBuffer() && FirstCBuffer == Size) {
       FirstCBuffer = I;
       NextID = 0;
-    } else if (RI.isSampler() && FirstSampler == Size) {
+    } else if (RTI.isSampler() && FirstSampler == Size) {
       FirstSampler = I;
       NextID = 0;
     }
 
     // Adjust the resource binding to use the next ID.
-    const ResourceInfo::ResourceBinding &Binding = RI.getBinding();
-    RI.bind(NextID++, Binding.Space, Binding.LowerBound, Binding.Size);
+    RBI.setBindingID(NextID++);
   }
 }
 
-void DXILResourceMap::print(raw_ostream &OS) const {
-  for (unsigned I = 0, E = Resources.size(); I != E; ++I) {
+void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
+                           const DataLayout &DL) const {
+  for (unsigned I = 0, E = Infos.size(); I != E; ++I) {
     OS << "Binding " << I << ":\n";
-    Resources[I].print(OS);
+    Infos[I].print(OS, DRTM, DL);
     OS << "\n";
   }
 
@@ -759,61 +784,83 @@ void DXILResourceMap::print(raw_ostream &OS) const {
 }
 
 //===----------------------------------------------------------------------===//
-// DXILResourceAnalysis and DXILResourcePrinterPass
 
-// Provide an explicit template instantiation for the static ID.
-AnalysisKey DXILResourceAnalysis::Key;
+AnalysisKey DXILResourceTypeAnalysis::Key;
+AnalysisKey DXILResourceBindingAnalysis::Key;
 
-DXILResourceMap DXILResourceAnalysis::run(Module &M,
-                                          ModuleAnalysisManager &AM) {
-  DXILResourceMap Data = ResourceMapper(M).mapResources();
+DXILBindingMap DXILResourceBindingAnalysis::run(Module &M,
+                                                ModuleAnalysisManager &AM) {
+  DXILBindingMap Data;
+  DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
+  Data.populate(M, DRTM);
   return Data;
 }
 
-PreservedAnalyses DXILResourcePrinterPass::run(Module &M,
-                                               ModuleAnalysisManager &AM) {
-  DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(M);
-  DRM.print(OS);
+PreservedAnalyses
+DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) {
+  DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
+  DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
+
+  DBM.print(OS, DRTM, M.getDataLayout());
   return PreservedAnalyses::all();
 }
 
-//===----------------------------------------------------------------------===//
-// DXILResourceWrapperPass
+void DXILResourceTypeWrapperPass::anchor() {}
 
-DXILResourceWrapperPass::DXILResourceWrapperPass() : ModulePass(ID) {
-  initializeDXILResourceWrapperPassPass(*PassRegistry::getPassRegistry());
+DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) {
+  initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
 }
 
-DXILResourceWrapperPass::~DXILResourceWrapperPass() = default;
+INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type",
+                "DXIL Resource Type Analysis", false, true)
+char DXILResourceTypeWrapperPass::ID = 0;
 
-void DXILResourceWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+ModulePass *llvm::createDXILResourceTypeWrapperPassPass() {
+  return new DXILResourceTypeWrapperPass();
+}
+
+DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass()
+    : ModulePass(ID) {
+  initializeDXILResourceBindingWrapperPassPass(
+      *PassRegistry::getPassRegistry());
+}
+
+DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass() = default;
+
+void DXILResourceBindingWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<DXILResourceTypeWrapperPass>();
   AU.setPreservesAll();
 }
 
-bool DXILResourceWrapperPass::runOnModule(Module &M) {
-  ResourceMap.reset(new DXILResourceMap(ResourceMapper(M).mapResources()));
+bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
+  Map.reset(new DXILBindingMap());
+
+  DRTM = &getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
+  Map->populate(M, *DRTM);
+
   return false;
 }
 
-void DXILResourceWrapperPass::releaseMemory() { ResourceMap.reset(); }
+void DXILResourceBindingWrapperPass::releaseMemory() { Map.reset(); }
 
-void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *) const {
-  if (!ResourceMap) {
+void DXILResourceBindingWrapperPass::print(raw_ostream &OS,
+                                           const Module *M) const {
+  if (!Map) {
     OS << "No resource map has been built!\n";
     return;
   }
-  ResourceMap->print(OS);
+  Map->print(OS, *DRTM, M->getDataLayout());
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 LLVM_DUMP_METHOD
-void DXILResourceWrapperPass::dump() const { print(dbgs(), nullptr); }
+void DXILResourceBindingWrapperPass::dump() const { print(dbgs(), nullptr); }
 #endif
 
-INITIALIZE_PASS(DXILResourceWrapperPass, DEBUG_TYPE, "DXIL Resource analysis",
-                false, true)
-char DXILResourceWrapperPass::ID = 0;
+INITIALIZE_PASS(DXILResourceBindingWrapperPass, "dxil-resource-binding",
+                "DXIL Resource Binding Analysis", false, true)
+char DXILResourceBindingWrapperPass::ID = 0;
 
-ModulePass *llvm::createDXILResourceWrapperPassPass() {
-  return new DXILResourceWrapperPass();
+ModulePass *llvm::createDXILResourceBindingWrapperPassPass() {
+  return new DXILResourceBindingWrapperPass();
 }
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 825f2f7f9a494a..ad7e6429a17417 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -22,7 +22,8 @@ MODULE_ANALYSIS("callgraph", CallGraphAnalysis())
 MODULE_ANALYSIS("collector-metadata", CollectorMetadataAnalysis())
 MODULE_ANALYSIS("ctx-prof-analysis", CtxProfAnalysis())
 MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
-MODULE_ANALYSIS("dxil-resource", DXILResourceAnalysis())
+MODULE_ANALYSIS("dxil-resource-binding", DXILResourceBindingAnalysis())
+MODULE_ANALYSIS("dxil-resource-type", DXILResourceTypeAnalysis())
 MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
 MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
 MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
@@ -127,7 +128,8 @@ MODULE_PASS("print-must-be-executed-contexts",
 MODULE_PASS("print-profile-summary", ProfileSummaryPrinterPass(errs()))
 MODULE_PASS("print-stack-safety", StackSafetyGlobalPrinterPass(errs()))
 MODULE_PASS("print<dxil-metadata>", DXILMetadataAnalysisPrinterPass(errs()))
-MODULE_PASS("print<dxil-resource>", DXILResourcePrinterPass(errs()))
+MODULE_PASS("print<dxil-resource-binding>",
+            DXILResourceBindingPrinterPass(errs()))
 MODULE_PASS("print<inline-advisor>", InlineAdvisorAnalysisPrinterPass(errs()))
 MODULE_PASS("print<module-debuginfo>", ModuleDebugInfoPrinterPass(errs()))
 MODULE_PASS("print<reg-usage>", PhysicalRegisterUsageInfoPrinterPass(errs()))
diff --git a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
index aaf994b23cf3c9..4c55a13b17f29b 100644
--- a/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
+++ b/llvm/lib/Target/DirectX/DXContainerGlobals.cpp
@@ -61,7 +61,8 @@ class DXContainerGlobals : public llvm::ModulePass {
     AU.setPreservesAll();
     AU.addRequired<ShaderFlagsAnalysisWrapper>();
     AU.addRequired<DXILMetadataAnalysisWrapperPass>();
-    AU.addRequired<DXILResourceWrapperPass>();
+    AU.addRequired<DXILResourceTypeWrapperPass>();
+    AU.addRequired<DXILResourceBindingWrapperPass>();
   }
 };
 
@@ -144,19 +145,23 @@ void DXContainerGlobals::addSignature(Module &M,
 }
 
 void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
-  const DXILResourceMap &ResMap =
-      getAnalysis<DXILResourceWrapperPass>().getResourceMap();
-
-  for (const dxil::ResourceInfo &ResInfo : ResMap) {
-    const dxil::ResourceInfo::ResourceBinding &Binding = ResInfo.getBinding();
+  const DXILBindingMap &DBM =
+      getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
+  DXILResourceTypeMap &DRTM =
+      getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
+
+  for (const dxil::ResourceBindingInfo &RBI : DBM) {
+    const dxil::ResourceBindingInfo::ResourceBinding &Binding =
+        RBI.getBinding();
     dxbc::PSV::v2::ResourceBindInfo BindInfo;
     BindInfo.LowerBound = Binding.LowerBound;
     BindInfo.UpperBound = Binding.LowerBound + Binding.Size - 1;
     BindInfo.Space = Binding.Space;
 
+    dxil::ResourceTypeInfo TypeInfo = DRTM[RBI.getHandleTy()];
     dxbc::PSV::ResourceType ResType = dxbc::PSV::ResourceType::Invalid;
-    bool IsUAV = ResInfo.getResourceClass() == dxil::ResourceClass::UAV;
-    switch (ResInfo.getResourceKind()) {
+    bool IsUAV = TypeInfo.getResourceClass() == dxil::ResourceClass::UAV;
+    switch (TypeInfo.getResourceKind()) {
     case dxil::ResourceKind::Sampler:
       ResType = dxbc::PSV::ResourceType::Sampler;
       break;
@@ -166,7 +171,7 @@ void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
     case dxil::ResourceKind::StructuredBuffer:
       ResType = IsUAV ? dxbc::PSV::ResourceType::UAVStructured
                       : dxbc::PSV::ResourceType::SRVStructured;
-      if (IsUAV && ResInfo.getUAV().HasCounter)
+      if (IsUAV && TypeInfo.getUAV().HasCounter)
         ResType = dxbc::PSV::ResourceType::UAVStructuredWithCounter;
       break;
     case dxil::ResourceKind::RTAccelerationStructure:
@@ -184,7 +189,7 @@ void DXContainerGlobals::addResourcesForPSV(Module &M, PSVRuntimeInfo &PSV) {
     BindInfo.Type = ResType;
 
     BindInfo.Kind =
-        static_cast<dxbc::PSV::ResourceKind>(ResInfo.getResourceKind());
+        static_cast<dxbc::PSV::ResourceKind>(TypeInfo.getResourceKind());
     // TODO: Add support for dxbc::PSV::ResourceFlag::UsedByAtomic64, tracking
     // with https://github.com/llvm/llvm-project/issues/104392
     BindInfo.Flags.Flags = 0u;
@@ -240,7 +245,8 @@ INITIALIZE_PASS_BEGIN(DXContainerGlobals, "dxil-globals",
                       "DXContainer Global Emitter", false, true)
 INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper)
 INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
-INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
 INITIALIZE_PASS_END(DXContainerGlobals, "dxil-globals",
                     "DXContainer Global Emitter", false, true)
 
diff --git a/llvm/lib/Target/DirectX/DXILDataScalarization.cpp b/llvm/lib/Target/DirectX/DXILDataScalarization.cpp
index 0e6cf59e257508..1783e4a5463135 100644
--- a/llvm/lib/Target/DirectX/DXILDataScalarization.cpp
+++ b/llvm/lib/Target/DirectX/DXILDataScalarization.cpp
@@ -10,7 +10,6 @@
 #include "DirectX.h"
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstVisitor.h"
@@ -33,7 +32,6 @@ class DXILDataScalarizationLegacy : public ModulePass {
   bool runOnModule(Module &M) override;
   DXILDataScalarizationLegacy() : ModulePass(ID) {}
 
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
   static char ID; // Pass identification.
 };
 
@@ -276,7 +274,6 @@ PreservedAnalyses DXILDataScalarization::run(Module &M,
   if (!MadeChanges)
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
-  PA.preserve<DXILResourceAnalysis>();
   return PA;
 }
 
@@ -284,10 +281,6 @@ bool DXILDataScalarizationLegacy::runOnModule(Module &M) {
   return findAndReplaceVectors(M);
 }
 
-void DXILDataScalarizationLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addPreserved<DXILResourceWrapperPass>();
-}
-
 char DXILDataScalarizationLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILDataScalarizationLegacy, DEBUG_TYPE,
diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
index 79ebbe0925e5c3..91ac758150fb4c 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.cpp
@@ -8,7 +8,6 @@
 
 #include "DXILFinalizeLinkage.h"
 #include "DirectX.h"
-#include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/Metadata.h"
@@ -51,10 +50,6 @@ bool DXILFinalizeLinkageLegacy::runOnModule(Module &M) {
   return finalizeLinkage(M);
 }
 
-void DXILFinalizeLinkageLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addPreserved<DXILResourceWrapperPass>();
-}
-
 char DXILFinalizeLinkageLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILFinalizeLinkageLegacy, DEBUG_TYPE,
diff --git a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.h b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.h
index 62d3a8a27cfced..aab1bc3f7a28e2 100644
--- a/llvm/lib/Target/DirectX/DXILFinalizeLinkage.h
+++ b/llvm/lib/Target/DirectX/DXILFinalizeLinkage.h
@@ -32,7 +32,6 @@ class DXILFinalizeLinkageLegacy : public ModulePass {
   DXILFinalizeLinkageLegacy() : ModulePass(ID) {}
   bool runOnModule(Module &M) override;
 
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
   static char ID; // Pass identification.
 };
 } // namespace llvm
diff --git a/llvm/lib/Target/DirectX/DXILFlattenArrays.cpp b/llvm/lib/Target/DirectX/DXILFlattenArrays.cpp
index e4a3bc76eeacd2..6077af997212ea 100644
--- a/llvm/lib/Target/DirectX/DXILFlattenArrays.cpp
+++ b/llvm/lib/Target/DirectX/DXILFlattenArrays.cpp
@@ -14,7 +14,6 @@
 #include "DirectX.h"
 #include "llvm/ADT/PostOrderIterator.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/IRBuilder.h"
@@ -38,7 +37,6 @@ class DXILFlattenArraysLegacy : public ModulePass {
   bool runOnModule(Module &M) override;
   DXILFlattenArraysLegacy() : ModulePass(ID) {}
 
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
   static char ID; // Pass identification.
 };
 
@@ -419,7 +417,6 @@ PreservedAnalyses DXILFlattenArrays::run(Module &M, ModuleAnalysisManager &) {
   if (!MadeChanges)
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
-  PA.preserve<DXILResourceAnalysis>();
   return PA;
 }
 
@@ -427,10 +424,6 @@ bool DXILFlattenArraysLegacy::runOnModule(Module &M) {
   return flattenArrays(M);
 }
 
-void DXILFlattenArraysLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addPreserved<DXILResourceWrapperPass>();
-}
-
 char DXILFlattenArraysLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILFlattenArraysLegacy, DEBUG_TYPE,
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index d2bfca1fada559..3c6ea4470fbdcc 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -14,7 +14,6 @@
 #include "DirectX.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/Analysis/DXILResource.h"
 #include "llvm/CodeGen/Passes.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstrTypes.h"
@@ -39,7 +38,6 @@ class DXILIntrinsicExpansionLegacy : public ModulePass {
   bool runOnModule(Module &M) override;
   DXILIntrinsicExpansionLegacy() : ModulePass(ID) {}
 
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
   static char ID; // Pass identification.
 };
 
@@ -617,10 +615,6 @@ bool DXILIntrinsicExpansionLegacy::runOnModule(Module &M) {
   return expansionIntrinsics(M);
 }
 
-void DXILIntrinsicExpansionLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
-  AU.addPreserved<DXILResourceWrapperPass>();
-}
-
 char DXILIntrinsicExpansionLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILIntrinsicExpansionLegacy, DEBUG_TYPE,
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index d9e70da6ed653a..c66b24442d4bd0 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -77,11 +77,13 @@ namespace {
 class OpLowerer {
   Module &M;
   DXILOpBuilder OpBuilder;
-  DXILResourceMap &DRM;
+  DXILBindingMap &DBM;
+  DXILResourceTypeMap &DRTM;
   SmallVector<CallInst *> CleanupCasts;
 
 public:
-  OpLowerer(Module &M, DXILResourceMap &DRM) : M(M), OpBuilder(M), DRM(DRM) {}
+  OpLowerer(Module &M, DXILBindingMap &DBM, DXILResourceTypeMap &DRTM)
+      : M(M), OpBuilder(M), DBM(DBM), DRTM(DRTM) {}
 
   /// Replace every call to \c F using \c ReplaceCall, and then erase \c F. If
   /// there is an error replacing a call, we emit a diagnostic and return true.
@@ -257,10 +259,12 @@ class OpLowerer {
     return replaceFunction(F, [&](CallInst *CI) -> Error {
       IRB.SetInsertPoint(CI);
 
-      auto *It = DRM.find(CI);
-      assert(It != DRM.end() && "Resource not in map?");
-      dxil::ResourceInfo &RI = *It;
+      auto *It = DBM.find(CI);
+      assert(It != DBM.end() && "Resource not in map?");
+      dxil::ResourceBindingInfo &RI = *It;
+
       const auto &Binding = RI.getBinding();
+      dxil::ResourceClass RC = DRTM[RI.getHandleTy()].getResourceClass();
 
       Value *IndexOp = CI->getArgOperand(3);
       if (Binding.LowerBound != 0)
@@ -268,7 +272,7 @@ class OpLowerer {
                                 ConstantInt::get(Int32Ty, Binding.LowerBound));
 
       std::array<Value *, 4> Args{
-          ConstantInt::get(Int8Ty, llvm::to_underlying(RI.getResourceClass())),
+          ConstantInt::get(Int8Ty, llvm::to_underlying(RC)),
           ConstantInt::get(Int32Ty, Binding.RecordID), IndexOp,
           CI->getArgOperand(4)};
       Expected<CallInst *> OpCall =
@@ -293,18 +297,20 @@ class OpLowerer {
     return replaceFunction(F, [&](CallInst *CI) -> Error {
       IRB.SetInsertPoint(CI);
 
-      auto *It = DRM.find(CI);
-      assert(It != DRM.end() && "Resource not in map?");
-      dxil::ResourceInfo &RI = *It;
+      auto *It = DBM.find(CI);
+      assert(It != DBM.end() && "Resource not in map?");
+      dxil::ResourceBindingInfo &RI = *It;
 
       const auto &Binding = RI.getBinding();
+      dxil::ResourceClass RC = DRTM[RI.getHandleTy()].getResourceClass();
 
       Value *IndexOp = CI->getArgOperand(3);
       if (Binding.LowerBound != 0)
         IndexOp = IRB.CreateAdd(IndexOp,
                                 ConstantInt::get(Int32Ty, Binding.LowerBound));
 
-      std::pair<uint32_t, uint32_t> Props = RI.getAnnotateProps();
+      std::pair<uint32_t, uint32_t> Props =
+          RI.getAnnotateProps(*F.getParent(), DRTM);
 
       // For `CreateHandleFromBinding` we need the upper bound rather than the
       // size, so we need to be careful about the difference for "unbounded".
@@ -312,8 +318,8 @@ class OpLowerer {
       uint32_t UpperBound = Binding.Size == Unbounded
                                 ? Unbounded
                                 : Binding.LowerBound + Binding.Size - 1;
-      Constant *ResBind = OpBuilder.getResBind(
-          Binding.LowerBound, UpperBound, Binding.Space, RI.getResourceClass());
+      Constant *ResBind = OpBuilder.getResBind(Binding.LowerBound, UpperBound,
+                                               Binding.Space, RC);
       std::array<Value *, 3> BindArgs{ResBind, IndexOp, CI->getArgOperand(4)};
       Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
           OpCode::CreateHandleFromBinding, BindArgs, CI->getName());
@@ -340,7 +346,7 @@ class OpLowerer {
   }
 
   /// Lower `dx.handle.fromBinding` intrinsics depending on the shader model and
-  /// taking into account binding information from DXILResourceAnalysis.
+  /// taking into account binding information from DXILResourceBindingAnalysis.
   bool lowerHandleFromBinding(Function &F) {
     Triple TT(Triple(M.getTargetTriple()));
     if (TT.getDXILVersion() < VersionTuple(1, 6))
@@ -737,13 +743,14 @@ class OpLowerer {
 } // namespace
 
 PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) {
-  DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
+  DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
+  DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
 
-  bool MadeChanges = OpLowerer(M, DRM).lowerIntrinsics();
+  bool MadeChanges = OpLowerer(M, DBM, DRTM).lowerIntrinsics();
   if (!MadeChanges)
     return PreservedAnalyses::all();
   PreservedAnalyses PA;
-  PA.preserve<DXILResourceAnalysis>();
+  PA.preserve<DXILResourceBindingAnalysis>();
   return PA;
 }
 
@@ -751,18 +758,21 @@ namespace {
 class DXILOpLoweringLegacy : public ModulePass {
 public:
   bool runOnModule(Module &M) override {
-    DXILResourceMap &DRM =
-        getAnalysis<DXILResourceWrapperPass>().getResourceMap();
+    DXILBindingMap &DBM =
+        getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
+    DXILResourceTypeMap &DRTM =
+        getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
 
-    return OpLowerer(M, DRM).lowerIntrinsics();
+    return OpLowerer(M, DBM, DRTM).lowerIntrinsics();
   }
   StringRef getPassName() const override { return "DXIL Op Lowering"; }
   DXILOpLoweringLegacy() : ModulePass(ID) {}
 
   static char ID; // Pass identification.
   void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
-    AU.addRequired<DXILResourceWrapperPass>();
-    AU.addPreserved<DXILResourceWrapperPass>();
+    AU.addRequired<DXILResourceTypeWrapperPass>();
+    AU.addRequired<DXILResourceBindingWrapperPass>();
+    AU.addPreserved<DXILResourceBindingWrapperPass>();
   }
 };
 char DXILOpLoweringLegacy::ID = 0;
@@ -770,7 +780,8 @@ char DXILOpLoweringLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",
                       false, false)
-INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
 INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,
                     false)
 
diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp
index 6092cfb3948f0c..375e6ce7129245 100644
--- a/llvm/lib/Target/DirectX/DXILPrepare.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp
@@ -251,7 +251,7 @@ class DXILPrepareModule : public ModulePass {
     AU.addPreserved<ShaderFlagsAnalysisWrapper>();
     AU.addPreserved<DXILResourceMDWrapper>();
     AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
-    AU.addPreserved<DXILResourceWrapperPass>();
+    AU.addPreserved<DXILResourceBindingWrapperPass>();
   }
   static char ID; // Pass identification.
 };
diff --git a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
index 0478dc2df988de..ff690f2abe4901 100644
--- a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
@@ -48,7 +48,7 @@ static StringRef getRCPrefix(dxil::ResourceClass RC) {
   llvm_unreachable("covered switch");
 }
 
-static StringRef getFormatName(const dxil::ResourceInfo &RI) {
+static StringRef getFormatName(const dxil::ResourceTypeInfo &RI) {
   if (RI.isTyped()) {
     switch (RI.getTyped().ElementTy) {
     case dxil::ElementType::I1:
@@ -139,9 +139,9 @@ static StringRef getTextureDimName(dxil::ResourceKind RK) {
 
 namespace {
 struct FormatResourceDimension
-    : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
-  explicit FormatResourceDimension(const dxil::ResourceInfo &RI)
-      : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}
+    : public llvm::FormatAdapter<const dxil::ResourceTypeInfo &> {
+  explicit FormatResourceDimension(const dxil::ResourceTypeInfo &RI)
+      : llvm::FormatAdapter<const dxil::ResourceTypeInfo &>(RI) {}
 
   void format(llvm::raw_ostream &OS, StringRef Style) override {
     dxil::ResourceKind RK = Item.getResourceKind();
@@ -149,7 +149,7 @@ struct FormatResourceDimension
     default: {
       OS << getTextureDimName(RK);
       if (Item.isMultiSample())
-        OS << Item.getMultiSample().Count;
+        OS << Item.getMultiSampleCount();
       break;
     }
     case dxil::ResourceKind::RawBuffer:
@@ -172,33 +172,40 @@ struct FormatResourceDimension
 };
 
 struct FormatBindingID
-    : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
-  explicit FormatBindingID(const dxil::ResourceInfo &RI)
-      : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}
+    : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
+  dxil::ResourceClass RC;
+
+  explicit FormatBindingID(const dxil::ResourceBindingInfo &RBI,
+                           const dxil::ResourceTypeInfo &RTI)
+      : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI),
+        RC(RTI.getResourceClass()) {}
 
   void format(llvm::raw_ostream &OS, StringRef Style) override {
-    OS << getRCPrefix(Item.getResourceClass()).upper()
-       << Item.getBinding().RecordID;
+    OS << getRCPrefix(RC).upper() << Item.getBinding().RecordID;
   }
 };
 
 struct FormatBindingLocation
-    : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
-  explicit FormatBindingLocation(const dxil::ResourceInfo &RI)
-      : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}
+    : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
+  dxil::ResourceClass RC;
+
+  explicit FormatBindingLocation(const dxil::ResourceBindingInfo &RBI,
+                                 const dxil::ResourceTypeInfo &RTI)
+      : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RBI),
+        RC(RTI.getResourceClass()) {}
 
   void format(llvm::raw_ostream &OS, StringRef Style) override {
     const auto &Binding = Item.getBinding();
-    OS << getRCPrefix(Item.getResourceClass()) << Binding.LowerBound;
+    OS << getRCPrefix(RC) << Binding.LowerBound;
     if (Binding.Space)
       OS << ",space" << Binding.Space;
   }
 };
 
 struct FormatBindingSize
-    : public llvm::FormatAdapter<const dxil::ResourceInfo &> {
-  explicit FormatBindingSize(const dxil::ResourceInfo &RI)
-      : llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}
+    : public llvm::FormatAdapter<const dxil::ResourceBindingInfo &> {
+  explicit FormatBindingSize(const dxil::ResourceBindingInfo &RI)
+      : llvm::FormatAdapter<const dxil::ResourceBindingInfo &>(RI) {}
 
   void format(llvm::raw_ostream &OS, StringRef Style) override {
     uint32_t Size = Item.getBinding().Size;
@@ -211,7 +218,8 @@ struct FormatBindingSize
 
 } // namespace
 
-static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM,
+static void prettyPrintResources(raw_ostream &OS, const DXILBindingMap &DBM,
+                                 DXILResourceTypeMap &DRTM,
                                  const dxil::Resources &MDResources) {
   // Column widths are arbitrary but match the widths DXC uses.
   OS << ";\n; Resource Bindings:\n;\n";
@@ -222,20 +230,22 @@ static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM,
       "", "", "", "", "");
 
   // TODO: Do we want to sort these by binding or something like that?
-  for (const dxil::ResourceInfo &RI : DRM) {
-    dxil::ResourceClass RC = RI.getResourceClass();
+  for (const dxil::ResourceBindingInfo &RBI : DBM) {
+    const dxil::ResourceTypeInfo &RTI = DRTM[RBI.getHandleTy()];
+
+    dxil::ResourceClass RC = RTI.getResourceClass();
     assert((RC != dxil::ResourceClass::CBuffer || !MDResources.hasCBuffers()) &&
            "Old and new cbuffer representations can't coexist");
     assert((RC != dxil::ResourceClass::UAV || !MDResources.hasUAVs()) &&
            "Old and new UAV representations can't coexist");
 
-    StringRef Name(RI.getName());
+    StringRef Name(RBI.getName());
     StringRef Type(getRCName(RC));
-    StringRef Format(getFormatName(RI));
-    FormatResourceDimension Dim(RI);
-    FormatBindingID ID(RI);
-    FormatBindingLocation Bind(RI);
-    FormatBindingSize Count(RI);
+    StringRef Format(getFormatName(RTI));
+    FormatResourceDimension Dim(RTI);
+    FormatBindingID ID(RBI, RTI);
+    FormatBindingLocation Bind(RBI, RTI);
+    FormatBindingSize Count(RBI);
     OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name,
                   Type, Format, Dim, ID, Bind, Count);
   }
@@ -250,9 +260,10 @@ static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM,
 
 PreservedAnalyses DXILPrettyPrinterPass::run(Module &M,
                                              ModuleAnalysisManager &MAM) {
-  const DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
+  const DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
+  DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
   const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M);
-  prettyPrintResources(OS, DRM, MDResources);
+  prettyPrintResources(OS, DBM, DRTM, MDResources);
   return PreservedAnalyses::all();
 }
 
@@ -277,7 +288,8 @@ class DXILPrettyPrinterLegacy : public llvm::ModulePass {
   bool runOnModule(Module &M) override;
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesAll();
-    AU.addRequired<DXILResourceWrapperPass>();
+    AU.addRequired<DXILResourceTypeWrapperPass>();
+    AU.addRequired<DXILResourceBindingWrapperPass>();
     AU.addRequired<DXILResourceMDWrapper>();
   }
 };
@@ -286,16 +298,19 @@ class DXILPrettyPrinterLegacy : public llvm::ModulePass {
 char DXILPrettyPrinterLegacy::ID = 0;
 INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
                       "DXIL Metadata Pretty Printer", true, true)
-INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper)
 INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
                     "DXIL Metadata Pretty Printer", true, true)
 
 bool DXILPrettyPrinterLegacy::runOnModule(Module &M) {
-  const DXILResourceMap &DRM =
-      getAnalysis<DXILResourceWrapperPass>().getResourceMap();
+  const DXILBindingMap &DBM =
+      getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
+  DXILResourceTypeMap &DRTM =
+      getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
   dxil::Resources &Res = getAnalysis<DXILResourceMDWrapper>().getDXILResource();
-  prettyPrintResources(OS, DRM, Res);
+  prettyPrintResources(OS, DBM, DRTM, Res);
   return false;
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 4ba10d123e8d27..9443ccd9c82a53 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -72,25 +72,30 @@ enum class EntryPropsTag {
 
 } // namespace
 
-static NamedMDNode *emitResourceMetadata(Module &M, const DXILResourceMap &DRM,
+static NamedMDNode *emitResourceMetadata(Module &M, DXILBindingMap &DBM,
+                                         DXILResourceTypeMap &DRTM,
                                          const dxil::Resources &MDResources) {
   LLVMContext &Context = M.getContext();
 
+  for (ResourceBindingInfo &RI : DBM)
+    if (!RI.hasSymbol())
+      RI.createSymbol(M, DRTM[RI.getHandleTy()].createElementStruct());
+
   SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
-  for (const ResourceInfo &RI : DRM.srvs())
-    SRVs.push_back(RI.getAsMetadata(Context));
-  for (const ResourceInfo &RI : DRM.uavs())
-    UAVs.push_back(RI.getAsMetadata(Context));
-  for (const ResourceInfo &RI : DRM.cbuffers())
-    CBufs.push_back(RI.getAsMetadata(Context));
-  for (const ResourceInfo &RI : DRM.samplers())
-    Smps.push_back(RI.getAsMetadata(Context));
+  for (const ResourceBindingInfo &RI : DBM.srvs())
+    SRVs.push_back(RI.getAsMetadata(M, DRTM));
+  for (const ResourceBindingInfo &RI : DBM.uavs())
+    UAVs.push_back(RI.getAsMetadata(M, DRTM));
+  for (const ResourceBindingInfo &RI : DBM.cbuffers())
+    CBufs.push_back(RI.getAsMetadata(M, DRTM));
+  for (const ResourceBindingInfo &RI : DBM.samplers())
+    Smps.push_back(RI.getAsMetadata(M, DRTM));
 
   Metadata *SRVMD = SRVs.empty() ? nullptr : MDNode::get(Context, SRVs);
   Metadata *UAVMD = UAVs.empty() ? nullptr : MDNode::get(Context, UAVs);
   Metadata *CBufMD = CBufs.empty() ? nullptr : MDNode::get(Context, CBufs);
   Metadata *SmpMD = Smps.empty() ? nullptr : MDNode::get(Context, Smps);
-  bool HasResources = !DRM.empty();
+  bool HasResources = !DBM.empty();
 
   if (MDResources.hasUAVs()) {
     assert(!UAVMD && "Old and new UAV representations can't coexist");
@@ -295,7 +300,8 @@ static MDTuple *emitTopLevelLibraryNode(Module &M, MDNode *RMD,
   return constructEntryMetadata(nullptr, nullptr, RMD, Properties, Ctx);
 }
 
-static void translateMetadata(Module &M, const DXILResourceMap &DRM,
+static void translateMetadata(Module &M, DXILBindingMap &DBM,
+                              DXILResourceTypeMap &DRTM,
                               const Resources &MDResources,
                               const ModuleShaderFlags &ShaderFlags,
                               const ModuleMetadataInfo &MMDI) {
@@ -306,7 +312,8 @@ static void translateMetadata(Module &M, const DXILResourceMap &DRM,
   emitValidatorVersionMD(M, MMDI);
   emitShaderModelVersionMD(M, MMDI);
   emitDXILVersionTupleMD(M, MMDI);
-  NamedMDNode *NamedResourceMD = emitResourceMetadata(M, DRM, MDResources);
+  NamedMDNode *NamedResourceMD =
+      emitResourceMetadata(M, DBM, DRTM, MDResources);
   auto *ResourceMD =
       (NamedResourceMD != nullptr) ? NamedResourceMD->getOperand(0) : nullptr;
   // FIXME: Add support to construct Signatures
@@ -358,12 +365,13 @@ static void translateMetadata(Module &M, const DXILResourceMap &DRM,
 
 PreservedAnalyses DXILTranslateMetadata::run(Module &M,
                                              ModuleAnalysisManager &MAM) {
-  const DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
+  DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
+  DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
   const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M);
   const ModuleShaderFlags &ShaderFlags = MAM.getResult<ShaderFlagsAnalysis>(M);
   const dxil::ModuleMetadataInfo MMDI = MAM.getResult<DXILMetadataAnalysis>(M);
 
-  translateMetadata(M, DRM, MDResources, ShaderFlags, MMDI);
+  translateMetadata(M, DBM, DRTM, MDResources, ShaderFlags, MMDI);
 
   return PreservedAnalyses::all();
 }
@@ -377,18 +385,21 @@ class DXILTranslateMetadataLegacy : public ModulePass {
   StringRef getPassName() const override { return "DXIL Translate Metadata"; }
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
-    AU.addRequired<DXILResourceWrapperPass>();
+    AU.addRequired<DXILResourceTypeWrapperPass>();
+    AU.addRequired<DXILResourceBindingWrapperPass>();
     AU.addRequired<DXILResourceMDWrapper>();
     AU.addRequired<ShaderFlagsAnalysisWrapper>();
     AU.addRequired<DXILMetadataAnalysisWrapperPass>();
-    AU.addPreserved<DXILResourceWrapperPass>();
+    AU.addPreserved<DXILResourceBindingWrapperPass>();
     AU.addPreserved<DXILResourceMDWrapper>();
     AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
   }
 
   bool runOnModule(Module &M) override {
-    const DXILResourceMap &DRM =
-        getAnalysis<DXILResourceWrapperPass>().getResourceMap();
+    DXILBindingMap &DBM =
+        getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
+    DXILResourceTypeMap &DRTM =
+        getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
     const dxil::Resources &MDResources =
         getAnalysis<DXILResourceMDWrapper>().getDXILResource();
     const ModuleShaderFlags &ShaderFlags =
@@ -396,7 +407,7 @@ class DXILTranslateMetadataLegacy : public ModulePass {
     dxil::ModuleMetadataInfo MMDI =
         getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
 
-    translateMetadata(M, DRM, MDResources, ShaderFlags, MMDI);
+    translateMetadata(M, DBM, DRTM, MDResources, ShaderFlags, MMDI);
     return true;
   }
 };
@@ -411,7 +422,7 @@ ModulePass *llvm::createDXILTranslateMetadataLegacyPass() {
 
 INITIALIZE_PASS_BEGIN(DXILTranslateMetadataLegacy, "dxil-translate-metadata",
                       "DXIL Translate Metadata", false, false)
-INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper)
 INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper)
 INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
index b26a185423597d..313c8376483b91 100644
--- a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
+++ b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
@@ -1,15 +1,13 @@
-; RUN: opt -S -disable-output -passes="print<dxil-resource>" < %s 2>&1 | FileCheck %s
+; RUN: opt -S -disable-output -passes="print<dxil-resource-binding>" < %s 2>&1 | FileCheck %s
 
 @G = external constant <4 x float>, align 4
 
 define void @test_typedbuffer() {
   ; ByteAddressBuffer Buf : register(t8, space1)
-  %srv0 = call target("dx.RawBuffer", i8, 0, 0)
+  %srv0 = call target("dx.RawBuffer", void, 0, 0)
       @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_0_0t(
           i32 1, i32 8, i32 1, i32 0, i1 false)
   ; CHECK: Binding [[SRV0:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 0
   ; CHECK:     Space: 1
@@ -24,8 +22,6 @@ define void @test_typedbuffer() {
       @llvm.dx.handle.fromBinding.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(
           i32 4, i32 2, i32 1, i32 0, i1 false)
   ; CHECK: Binding [[SRV1:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 1
   ; CHECK:     Space: 4
@@ -41,8 +37,6 @@ define void @test_typedbuffer() {
       @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_0_0t(
           i32 5, i32 3, i32 24, i32 0, i1 false)
   ; CHECK: Binding [[SRV2:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 2
   ; CHECK:     Space: 5
@@ -58,8 +52,6 @@ define void @test_typedbuffer() {
       @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_1_0t(
           i32 2, i32 7, i32 1, i32 0, i1 false)
   ; CHECK: Binding [[UAV0:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 0
   ; CHECK:     Space: 2
@@ -78,8 +70,6 @@ define void @test_typedbuffer() {
               @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
                   i32 3, i32 5, i32 1, i32 0, i1 false)
   ; CHECK: Binding [[UAV1:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 1
   ; CHECK:     Space: 3
@@ -103,8 +93,6 @@ define void @test_typedbuffer() {
               @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
                   i32 4, i32 0, i32 10, i32 5, i1 false)
   ; CHECK: Binding [[UAV2:[0-9]+]]:
-  ; CHECK:   Symbol: ptr undef
-  ; CHECK:   Name: ""
   ; CHECK:   Binding:
   ; CHECK:     Record ID: 2
   ; CHECK:     Space: 4
diff --git a/llvm/test/CodeGen/DirectX/llc-pipeline.ll b/llvm/test/CodeGen/DirectX/llc-pipeline.ll
index 40fa30778a1532..147898efc716fd 100644
--- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll
+++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll
@@ -6,6 +6,7 @@
 ; CHECK-LABEL: Pass Arguments:
 ; CHECK-NEXT: Target Library Information
 ; CHECK-NEXT: Target Transform Information
+; CHECK-NEXT: DXIL Resource Type Analysis
 ; CHECK-NEXT: ModulePass Manager
 ; CHECK-NEXT:   DXIL Finalize Linkage
 ; CHECK-NEXT:   DXIL Intrinsic Expansion
@@ -14,7 +15,7 @@
 ; CHECK-NEXT:   FunctionPass Manager
 ; CHECK-NEXT:     Dominator Tree Construction
 ; CHECK-NEXT:     Scalarize vector operations
-; CHECK-NEXT:   DXIL Resource analysis
+; CHECK-NEXT:   DXIL Resource Binding Analysis
 ; CHECK-NEXT:   DXIL Op Lowering
 ; CHECK-NEXT:   DXIL resource Information
 ; CHECK-NEXT:   DXIL Shader Flag Analysis
@@ -23,4 +24,3 @@
 ; CHECK-NEXT:   DXIL Prepare Module
 ; CHECK-NEXT:   DXIL Metadata Pretty Printer
 ; CHECK-NEXT:   Print Module IR
- 
diff --git a/llvm/unittests/Analysis/DXILResourceTest.cpp b/llvm/unittests/Analysis/DXILResourceTest.cpp
index e24018457dabec..4c005f817af59d 100644
--- a/llvm/unittests/Analysis/DXILResourceTest.cpp
+++ b/llvm/unittests/Analysis/DXILResourceTest.cpp
@@ -8,6 +8,9 @@
 
 #include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Module.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -99,8 +102,16 @@ testing::AssertionResult MDTupleEq(const char *LHSExpr, const char *RHSExpr,
 } // namespace
 
 TEST(DXILResource, AnnotationsAndMetadata) {
+  // TODO: How am I supposed to get this?
+  DataLayout DL("e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-"
+                "f64:64-n8:16:32:64-v96:32");
+
   LLVMContext Context;
+  Module M("AnnotationsAndMetadata", Context);
+  M.setDataLayout(DL);
+
   Type *Int1Ty = Type::getInt1Ty(Context);
+  Type *Int8Ty = Type::getInt8Ty(Context);
   Type *Int32Ty = Type::getInt32Ty(Context);
   Type *FloatTy = Type::getFloatTy(Context);
   Type *DoubleTy = Type::getDoubleTy(Context);
@@ -110,205 +121,327 @@ TEST(DXILResource, AnnotationsAndMetadata) {
 
   MDBuilder TestMD(Context, Int32Ty, Int1Ty);
 
-  // ByteAddressBuffer Buffer0;
-  Value *Symbol = UndefValue::get(
-      StructType::create(Context, {Int32Ty}, "struct.ByteAddressBuffer"));
-  ResourceInfo Resource = ResourceInfo::RawBuffer(Symbol, "Buffer0");
-  Resource.bind(0, 0, 0, 1);
-  std::pair<uint32_t, uint32_t> Props = Resource.getAnnotateProps();
+  // ByteAddressBuffer Buffer;
+  ResourceTypeInfo RTI(llvm::TargetExtType::get(
+      Context, "dx.RawBuffer", Int8Ty, {/*IsWriteable=*/0, /*IsROV=*/0}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::SRV);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::RawBuffer);
+
+  ResourceBindingInfo RBI(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GlobalVariable *GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer");
+  std::pair<uint32_t, uint32_t> Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000bU);
   EXPECT_EQ(Props.second, 0U);
-  MDTuple *MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 11, 0, nullptr));
+  MDTuple *MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "Buffer", 0, 0, 1, 11, 0, nullptr));
 
   // RWByteAddressBuffer BufferOut : register(u3, space2);
-  Symbol = UndefValue::get(
-      StructType::create(Context, {Int32Ty}, "struct.RWByteAddressBuffer"));
-  Resource =
-      ResourceInfo::RWRawBuffer(Symbol, "BufferOut",
-                                /*GloballyCoherent=*/false, /*IsROV=*/false);
-  Resource.bind(1, 2, 3, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.RawBuffer", Int8Ty, {/*IsWriteable=*/1, /*IsROV=*/0}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  EXPECT_EQ(RTI.getUAV().GloballyCoherent, false);
+  EXPECT_EQ(RTI.getUAV().HasCounter, false);
+  EXPECT_EQ(RTI.getUAV().IsROV, false);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::RawBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/1, /*Space=*/2, /*LowerBound=*/3, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "BufferOut");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000100bU);
   EXPECT_EQ(Props.second, 0U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(1, Symbol, "BufferOut", 2, 3, 1, 11, false, false,
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(1, GV, "BufferOut", 2, 3, 1, 11, false, false,
                              false, nullptr));
 
   // struct BufType0 { int i; float f; double d; };
   // StructuredBuffer<BufType0> Buffer0 : register(t0);
   StructType *BufType0 =
       StructType::create(Context, {Int32Ty, FloatTy, DoubleTy}, "BufType0");
-  Symbol = UndefValue::get(StructType::create(
-      Context, {BufType0}, "class.StructuredBuffer<BufType>"));
-  Resource = ResourceInfo::StructuredBuffer(Symbol, "Buffer0",
-                                            /*Stride=*/16, Align(8));
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.RawBuffer", BufType0, {/*IsWriteable=*/0, /*IsROV=*/0}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::SRV);
+  ASSERT_EQ(RTI.isStruct(), true);
+  EXPECT_EQ(RTI.getStruct(DL).Stride, 16u);
+  EXPECT_EQ(RTI.getStruct(DL).AlignLog2, Log2(Align(8)));
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::StructuredBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer0");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000030cU);
   EXPECT_EQ(Props.second, 0x00000010U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(
-      MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD,
+              TestMD.get(0, GV, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
 
   // StructuredBuffer<float3> Buffer1 : register(t1);
-  Symbol = UndefValue::get(StructType::create(
-      Context, {Floatx3Ty}, "class.StructuredBuffer<vector<float, 3> >"));
-  Resource = ResourceInfo::StructuredBuffer(Symbol, "Buffer1",
-                                            /*Stride=*/12, {});
-  Resource.bind(1, 0, 1, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.RawBuffer", Floatx3Ty, {/*IsWriteable=*/0, /*IsROV=*/0}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::SRV);
+  ASSERT_EQ(RTI.isStruct(), true);
+  EXPECT_EQ(RTI.getStruct(DL).Stride, 12u);
+  EXPECT_EQ(RTI.getStruct(DL).AlignLog2, 0u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::StructuredBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/1, /*Space=*/0, /*LowerBound=*/1, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer1");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000cU);
   EXPECT_EQ(Props.second, 0x0000000cU);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(
-      MD, TestMD.get(1, Symbol, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD,
+              TestMD.get(1, GV, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
 
   // Texture2D<float4> ColorMapTexture : register(t2);
-  Symbol = UndefValue::get(StructType::create(
-      Context, {Floatx4Ty}, "class.Texture2D<vector<float, 4> >"));
-  Resource =
-      ResourceInfo::SRV(Symbol, "ColorMapTexture", dxil::ElementType::F32,
-                        /*ElementCount=*/4, dxil::ResourceKind::Texture2D);
-  Resource.bind(2, 0, 2, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(
+      llvm::TargetExtType::get(Context, "dx.Texture", Floatx4Ty,
+                               {/*IsWriteable=*/0, /*IsROV=*/0, /*IsSigned=*/0,
+                                llvm::to_underlying(ResourceKind::Texture2D)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::SRV);
+  ASSERT_EQ(RTI.isTyped(), true);
+  EXPECT_EQ(RTI.getTyped().ElementTy, ElementType::F32);
+  EXPECT_EQ(RTI.getTyped().ElementCount, 4u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Texture2D);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/2, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ColorMapTexture");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000002U);
   EXPECT_EQ(Props.second, 0x00000409U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(2, Symbol, "ColorMapTexture", 0, 2, 1, 2, 0,
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(2, GV, "ColorMapTexture", 0, 2, 1, 2, 0,
                              TestMD.get(0, 9)));
 
   // Texture2DMS<float, 8> DepthBuffer : register(t0);
-  Symbol = UndefValue::get(
-      StructType::create(Context, {FloatTy}, "class.Texture2DMS<float, 8>"));
-  Resource =
-      ResourceInfo::Texture2DMS(Symbol, "DepthBuffer", dxil::ElementType::F32,
-                                /*ElementCount=*/1, /*SampleCount=*/8);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.MSTexture", FloatTy,
+      {/*IsWriteable=*/0, /*SampleCount=*/8,
+       /*IsSigned=*/0, llvm::to_underlying(ResourceKind::Texture2DMS)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::SRV);
+  ASSERT_EQ(RTI.isTyped(), true);
+  EXPECT_EQ(RTI.getTyped().ElementTy, ElementType::F32);
+  EXPECT_EQ(RTI.getTyped().ElementCount, 1u);
+  ASSERT_EQ(RTI.isMultiSample(), true);
+  EXPECT_EQ(RTI.getMultiSampleCount(), 8u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Texture2DMS);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "DepthBuffer");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000003U);
   EXPECT_EQ(Props.second, 0x00080109U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "DepthBuffer", 0, 0, 1, 3, 8,
-                             TestMD.get(0, 9)));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(
+      MD, TestMD.get(0, GV, "DepthBuffer", 0, 0, 1, 3, 8, TestMD.get(0, 9)));
 
   // FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip;
-  Symbol = UndefValue::get(
-      StructType::create(Context, {Int32Ty}, "class.FeedbackTexture2D<0>"));
-  Resource = ResourceInfo::FeedbackTexture2D(Symbol, "feedbackMinMip",
-                                             SamplerFeedbackType::MinMip);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.FeedbackTexture", {},
+      {llvm::to_underlying(SamplerFeedbackType::MinMip),
+       llvm::to_underlying(ResourceKind::FeedbackTexture2D)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  ASSERT_EQ(RTI.isFeedback(), true);
+  EXPECT_EQ(RTI.getFeedbackType(), SamplerFeedbackType::MinMip);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::FeedbackTexture2D);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMinMip");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001011U);
   EXPECT_EQ(Props.second, 0U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMinMip", 0, 0, 1, 17, false,
-                             false, false, TestMD.get(2, 0)));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMinMip", 0, 0, 1, 17, false, false,
+                             false, TestMD.get(2, 0)));
 
   // FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIP_REGION_USED> feedbackMipRegion;
-  Symbol = UndefValue::get(StructType::create(
-      Context, {Int32Ty}, "class.FeedbackTexture2DArray<1>"));
-  Resource = ResourceInfo::FeedbackTexture2DArray(
-      Symbol, "feedbackMipRegion", SamplerFeedbackType::MipRegionUsed);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.FeedbackTexture", {},
+      {llvm::to_underlying(SamplerFeedbackType::MipRegionUsed),
+       llvm::to_underlying(ResourceKind::FeedbackTexture2DArray)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  ASSERT_EQ(RTI.isFeedback(), true);
+  EXPECT_EQ(RTI.getFeedbackType(), SamplerFeedbackType::MipRegionUsed);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::FeedbackTexture2DArray);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMipRegion");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001012U);
   EXPECT_EQ(Props.second, 0x00000001U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMipRegion", 0, 0, 1, 18, false,
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMipRegion", 0, 0, 1, 18, false,
                              false, false, TestMD.get(2, 1)));
 
   // globallycoherent RWTexture2D<int2> OutputTexture : register(u0, space2);
-  Symbol = UndefValue::get(StructType::create(
-      Context, {Int32x2Ty}, "class.RWTexture2D<vector<int, 2> >"));
-  Resource = ResourceInfo::UAV(Symbol, "OutputTexture", dxil::ElementType::I32,
-                               /*ElementCount=*/2, /*GloballyCoherent=*/1,
-                               /*IsROV=*/0, dxil::ResourceKind::Texture2D);
-  Resource.bind(0, 2, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(
+      llvm::TargetExtType::get(Context, "dx.Texture", Int32x2Ty,
+                               {/*IsWriteable=*/1,
+                                /*IsROV=*/0, /*IsSigned=*/1,
+                                llvm::to_underlying(ResourceKind::Texture2D)}),
+      /*GloballyCoherent=*/true, /*HasCounter=*/false);
+
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  EXPECT_EQ(RTI.getUAV().GloballyCoherent, true);
+  EXPECT_EQ(RTI.getUAV().HasCounter, false);
+  EXPECT_EQ(RTI.getUAV().IsROV, false);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Texture2D);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/2, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "OutputTexture");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00005002U);
   EXPECT_EQ(Props.second, 0x00000204U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "OutputTexture", 2, 0, 1, 2, true,
-                             false, false, TestMD.get(0, 4)));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "OutputTexture", 2, 0, 1, 2, true, false,
+                             false, TestMD.get(0, 4)));
 
   // RasterizerOrderedBuffer<float4> ROB;
-  Symbol = UndefValue::get(
-      StructType::create(Context, {Floatx4Ty},
-                         "class.RasterizerOrderedBuffer<vector<float, 4> >"));
-  Resource = ResourceInfo::UAV(Symbol, "ROB", dxil::ElementType::F32,
-                               /*ElementCount=*/4, /*GloballyCoherent=*/0,
-                               /*IsROV=*/1, dxil::ResourceKind::TypedBuffer);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.TypedBuffer", Floatx4Ty,
+      {/*IsWriteable=*/1, /*IsROV=*/1, /*IsSigned=*/0}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  EXPECT_EQ(RTI.getUAV().GloballyCoherent, false);
+  EXPECT_EQ(RTI.getUAV().HasCounter, false);
+  EXPECT_EQ(RTI.getUAV().IsROV, true);
+  ASSERT_EQ(RTI.isTyped(), true);
+  EXPECT_EQ(RTI.getTyped().ElementTy, ElementType::F32);
+  EXPECT_EQ(RTI.getTyped().ElementCount, 4u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::TypedBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ROB");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000300aU);
   EXPECT_EQ(Props.second, 0x00000409U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "ROB", 0, 0, 1, 10, false, false, true,
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "ROB", 0, 0, 1, 10, false, false, true,
                              TestMD.get(0, 9)));
 
   // RWStructuredBuffer<ParticleMotion> g_OutputBuffer : register(u2);
   StructType *BufType1 = StructType::create(
       Context, {Floatx3Ty, FloatTy, Int32Ty}, "ParticleMotion");
-  Symbol = UndefValue::get(StructType::create(
-      Context, {BufType1}, "class.StructuredBuffer<ParticleMotion>"));
-  Resource =
-      ResourceInfo::RWStructuredBuffer(Symbol, "g_OutputBuffer", /*Stride=*/20,
-                                       Align(4), /*GloballyCoherent=*/false,
-                                       /*IsROV=*/false, /*HasCounter=*/true);
-  Resource.bind(0, 0, 2, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(
+      llvm::TargetExtType::get(Context, "dx.RawBuffer", BufType1,
+                               {/*IsWriteable=*/1, /*IsROV=*/0}),
+      /*GloballyCoherent=*/false, /*HasCounter=*/true);
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  EXPECT_EQ(RTI.getUAV().GloballyCoherent, false);
+  EXPECT_EQ(RTI.getUAV().HasCounter, true);
+  EXPECT_EQ(RTI.getUAV().IsROV, false);
+  ASSERT_EQ(RTI.isStruct(), true);
+  EXPECT_EQ(RTI.getStruct(DL).Stride, 20u);
+  EXPECT_EQ(RTI.getStruct(DL).AlignLog2, Log2(Align(4)));
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::StructuredBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_OutputBuffer");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000920cU);
   EXPECT_EQ(Props.second, 0x00000014U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_OutputBuffer", 0, 2, 1, 12, false,
-                             true, false, TestMD.get(1, 20)));
-
-  // RWTexture2DMSArray<uint,8> g_rw_t2dmsa;
-  Symbol = UndefValue::get(StructType::create(
-      Context, {Int32Ty}, "class.RWTexture2DMSArray<unsigned int, 8>"));
-  Resource = ResourceInfo::RWTexture2DMSArray(
-      Symbol, "g_rw_t2dmsa", dxil::ElementType::U32, /*ElementCount=*/1,
-      /*SampleCount=*/8, /*GloballyCoherent=*/false);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_OutputBuffer", 0, 2, 1, 12, false, true,
+                             false, TestMD.get(1, 20)));
+
+  // RWTexture2DMSArray<uint, 8> g_rw_t2dmsa;
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.MSTexture", Int32Ty,
+      {/*IsWriteable=*/1, /*SampleCount=*/8, /*IsSigned=*/0,
+       llvm::to_underlying(ResourceKind::Texture2DMSArray)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::UAV);
+  EXPECT_EQ(RTI.getUAV().GloballyCoherent, false);
+  EXPECT_EQ(RTI.getUAV().HasCounter, false);
+  EXPECT_EQ(RTI.getUAV().IsROV, false);
+  ASSERT_EQ(RTI.isTyped(), true);
+  EXPECT_EQ(RTI.getTyped().ElementTy, ElementType::U32);
+  EXPECT_EQ(RTI.getTyped().ElementCount, 1u);
+  ASSERT_EQ(RTI.isMultiSample(), true);
+  EXPECT_EQ(RTI.getMultiSampleCount(), 8u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Texture2DMSArray);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_rw_t2dmsa");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001008U);
   EXPECT_EQ(Props.second, 0x00080105U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_rw_t2dmsa", 0, 0, 1, 8, false, false,
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_rw_t2dmsa", 0, 0, 1, 8, false, false,
                              false, TestMD.get(0, 5)));
 
   // cbuffer cb0 { float4 g_X; float4 g_Y; }
-  Symbol = UndefValue::get(
-      StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0"));
-  Resource = ResourceInfo::CBuffer(Symbol, "cb0", /*Size=*/32);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  StructType *CBufType0 =
+      StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0");
+  RTI = ResourceTypeInfo(
+      llvm::TargetExtType::get(Context, "dx.CBuffer", CBufType0, {}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::CBuffer);
+  EXPECT_EQ(RTI.getCBufferSize(DL), 32u);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::CBuffer);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000dU);
   EXPECT_EQ(Props.second, 0x00000020U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "cb0", 0, 0, 1, 32, nullptr));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "", 0, 0, 1, 32, nullptr));
 
   // SamplerState ColorMapSampler : register(s0);
-  Symbol = UndefValue::get(
-      StructType::create(Context, {Int32Ty}, "struct.SamplerState"));
-  Resource = ResourceInfo::Sampler(Symbol, "ColorMapSampler",
-                                   dxil::SamplerType::Default);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.Sampler", {},
+      {llvm::to_underlying(dxil::SamplerType::Default)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::Sampler);
+  EXPECT_EQ(RTI.getSamplerType(), dxil::SamplerType::Default);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Sampler);
+
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ColorMapSampler");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000eU);
   EXPECT_EQ(Props.second, 0U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD,
-              TestMD.get(0, Symbol, "ColorMapSampler", 0, 0, 1, 0, nullptr));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "ColorMapSampler", 0, 0, 1, 0, nullptr));
+
+  RTI = ResourceTypeInfo(llvm::TargetExtType::get(
+      Context, "dx.Sampler", {},
+      {llvm::to_underlying(dxil::SamplerType::Comparison)}));
+  EXPECT_EQ(RTI.getResourceClass(), ResourceClass::Sampler);
+  EXPECT_EQ(RTI.getSamplerType(), dxil::SamplerType::Comparison);
+  EXPECT_EQ(RTI.getResourceKind(), ResourceKind::Sampler);
 
-  // SamplerComparisonState ShadowSampler {...};
-  Resource = ResourceInfo::Sampler(Symbol, "CmpSampler",
-                                   dxil::SamplerType::Comparison);
-  Resource.bind(0, 0, 0, 1);
-  Props = Resource.getAnnotateProps();
+  RBI = ResourceBindingInfo(
+      /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
+      RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "CmpSampler");
+  Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000800eU);
   EXPECT_EQ(Props.second, 0U);
-  MD = Resource.getAsMetadata(Context);
-  EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "CmpSampler", 0, 0, 1, 1, nullptr));
+  MD = RBI.getAsMetadata(M, RTI);
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "CmpSampler", 0, 0, 1, 1, nullptr));
 }



More information about the llvm-commits mailing list