Skip to content

[DXIL][Analysis] Uniquify duplicate resources in DXILResourceAnalysis #105602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

bogner
Copy link
Contributor

@bogner bogner commented Aug 22, 2024

If a resources is used multiple times, we should only have one resource record
for it. This comes up most prominantly with arrays of resources like so:

RWBuffer<float4> BufferArray[10] : register(u0, space4);
RWBuffer<float4> B1 = BufferArray[0];
RWBuffer<float4> B2 = BufferArray[SomeIndex];
RWBuffer<float4> B3 = BufferArray[3];

In this case, there's only one resource, but we'll generate 3 different
dx.handle.fromBinding calls to access different slices.

Note that this adds some API that won't be used until #104447 later in the
stack. Trying to avoid that results in unnecessary churn.

Fixes #105143

Created using spr 1.3.5-bogner
@llvmbot llvmbot added backend:DirectX llvm:analysis Includes value tracking, cost tables and constant folding labels Aug 22, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 22, 2024

@llvm/pr-subscribers-backend-directx

@llvm/pr-subscribers-llvm-analysis

Author: Justin Bogner (bogner)

Changes

If a resources is used multiple times, we should only have one resource record
for it. This comes up most prominantly with arrays of resources like so:

RWBuffer&lt;float4&gt; Arr[10] : register(u0, space4);
RWBuffer&lt;float4&gt; B1 = BufferArray[0];
RWBuffer&lt;float4&gt; B2 = BufferArray[SomeIndex];
RWBuffer&lt;float4&gt; B3 = BufferArray[3];

In this case, there's only one resource, but we'll generate 3 different
dx.handle.fromBinding calls to access different slices.

Note that this adds some API that won't be used until #104447 later in the
stack. Trying to avoid that results in unnecessary churn.


Patch is 22.97 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/105602.diff

3 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DXILResource.h (+99-2)
  • (modified) llvm/lib/Analysis/DXILResource.cpp (+105-67)
  • (modified) llvm/test/Analysis/DXILResource/buffer-frombinding.ll (+86-78)
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 14cf03c9a3acee..58db0a93f2f351 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -25,6 +25,7 @@ class Value;
 namespace dxil {
 
 class ResourceInfo {
+public:
   struct ResourceBinding {
     uint32_t RecordID;
     uint32_t Space;
@@ -38,6 +39,10 @@ class ResourceInfo {
     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);
+    }
   };
 
   struct UAVInfo {
@@ -50,6 +55,10 @@ class ResourceInfo {
              std::tie(RHS.GloballyCoherent, RHS.HasCounter, RHS.IsROV);
     }
     bool operator!=(const UAVInfo &RHS) const { return !(*this == RHS); }
+    bool operator<(const UAVInfo &RHS) const {
+      return std::tie(GloballyCoherent, HasCounter, IsROV) <
+             std::tie(RHS.GloballyCoherent, RHS.HasCounter, RHS.IsROV);
+    }
   };
 
   struct StructInfo {
@@ -64,6 +73,9 @@ class ResourceInfo {
       return std::tie(Stride, AlignLog2) == std::tie(RHS.Stride, RHS.AlignLog2);
     }
     bool operator!=(const StructInfo &RHS) const { return !(*this == RHS); }
+    bool operator<(const StructInfo &RHS) const {
+      return std::tie(Stride, AlignLog2) < std::tie(RHS.Stride, RHS.AlignLog2);
+    }
   };
 
   struct TypedInfo {
@@ -75,6 +87,10 @@ class ResourceInfo {
              std::tie(RHS.ElementTy, RHS.ElementCount);
     }
     bool operator!=(const TypedInfo &RHS) const { return !(*this == RHS); }
+    bool operator<(const TypedInfo &RHS) const {
+      return std::tie(ElementTy, ElementCount) <
+             std::tie(RHS.ElementTy, RHS.ElementCount);
+    }
   };
 
   struct MSInfo {
@@ -82,6 +98,7 @@ class ResourceInfo {
 
     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 {
@@ -89,8 +106,10 @@ class ResourceInfo {
 
     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;
@@ -138,6 +157,7 @@ class ResourceInfo {
     Binding.LowerBound = LowerBound;
     Binding.Size = Size;
   }
+  const ResourceBinding &getBinding() const { return Binding; }
   void setUAV(bool GloballyCoherent, bool HasCounter, bool IsROV) {
     assert(isUAV() && "Not a UAV");
     UAVFlags.GloballyCoherent = GloballyCoherent;
@@ -168,7 +188,11 @@ class ResourceInfo {
     MultiSample.Count = Count;
   }
 
+  dxil::ResourceClass getResourceClass() const { return RC; }
+
   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,
@@ -216,7 +240,6 @@ class ResourceInfo {
 
   MDTuple *getAsMetadata(LLVMContext &Ctx) const;
 
-  ResourceBinding getBinding() const { return Binding; }
   std::pair<uint32_t, uint32_t> getAnnotateProps() const;
 
   void print(raw_ostream &OS) const;
@@ -224,7 +247,81 @@ class ResourceInfo {
 
 } // namespace dxil
 
-using DXILResourceMap = MapVector<CallInst *, dxil::ResourceInfo>;
+class DXILResourceMap {
+  SmallVector<dxil::ResourceInfo> Resources;
+  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;
+
+  DXILResourceMap(
+      SmallVectorImpl<std::pair<CallInst *, dxil::ResourceInfo>> &&CIToRI);
+
+  iterator begin() { return Resources.begin(); }
+  const_iterator begin() const { return Resources.begin(); }
+  iterator end() { return Resources.end(); }
+  const_iterator end() const { return Resources.end(); }
+
+  bool empty() const { return Resources.empty(); }
+
+  iterator find(const CallInst *Key) {
+    auto Pos = CallMap.find(Key);
+    return Pos == CallMap.end() ? Resources.end()
+                                : (Resources.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);
+  }
+
+  iterator srv_begin() { return begin(); }
+  const_iterator srv_begin() const { return begin(); }
+  iterator srv_end() { return begin() + FirstUAV; }
+  const_iterator srv_end() const { return begin() + FirstUAV; }
+  iterator_range<iterator> srvs() { return make_range(srv_begin(), srv_end()); }
+  iterator_range<const_iterator> srvs() const {
+    return make_range(srv_begin(), srv_end());
+  }
+
+  iterator uav_begin() { return begin() + FirstUAV; }
+  const_iterator uav_begin() const { return begin() + FirstUAV; }
+  iterator uav_end() { return begin() + FirstCBuffer; }
+  const_iterator uav_end() const { return begin() + FirstCBuffer; }
+  iterator_range<iterator> uavs() { return make_range(uav_begin(), uav_end()); }
+  iterator_range<const_iterator> uavs() const {
+    return make_range(uav_begin(), uav_end());
+  }
+
+  iterator cbuffer_begin() { return begin() + FirstCBuffer; }
+  const_iterator cbuffer_begin() const { return begin() + FirstCBuffer; }
+  iterator cbuffer_end() { return begin() + FirstSampler; }
+  const_iterator cbuffer_end() const { return begin() + FirstSampler; }
+  iterator_range<iterator> cbuffers() {
+    return make_range(cbuffer_begin(), cbuffer_end());
+  }
+  iterator_range<const_iterator> cbuffers() const {
+    return make_range(cbuffer_begin(), cbuffer_end());
+  }
+
+  iterator sampler_begin() { return begin() + FirstSampler; }
+  const_iterator sampler_begin() const { return begin() + FirstSampler; }
+  iterator sampler_end() { return end(); }
+  const_iterator sampler_end() const { return end(); }
+  iterator_range<iterator> samplers() {
+    return make_range(sampler_begin(), sampler_end());
+  }
+  iterator_range<const_iterator> samplers() const {
+    return make_range(sampler_begin(), sampler_end());
+  }
+
+  void print(raw_ostream &OS) const;
+};
 
 class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {
   friend AnalysisInfoMixin<DXILResourceAnalysis>;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 1b5b051c9db29e..110a59331f15be 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -335,27 +335,45 @@ 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())
-    return CBufferSize == RHS.CBufferSize;
-  if (isSampler())
-    return SamplerTy == RHS.SamplerTy;
-  if (isUAV() && UAVFlags != RHS.UAVFlags)
+  if (isCBuffer() && RHS.isCBuffer() && CBufferSize != RHS.CBufferSize)
     return false;
-
-  if (isStruct())
-    return Struct == RHS.Struct;
-  if (isFeedback())
-    return Feedback == RHS.Feedback;
-  if (isTyped() && Typed != RHS.Typed)
+  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)
     return false;
-
-  if (isMultiSample())
-    return MultiSample == RHS.MultiSample;
-
-  assert((Kind == ResourceKind::RawBuffer) && "Unhandled resource kind");
   return true;
 }
 
+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))
+    return true;
+  if (isCBuffer() && RHS.isCBuffer() && CBufferSize < RHS.CBufferSize)
+    return true;
+  if (isSampler() && RHS.isSampler() && SamplerTy < RHS.SamplerTy)
+    return true;
+  if (isUAV() && RHS.isUAV() && UAVFlags < RHS.UAVFlags)
+    return true;
+  if (isStruct() && RHS.isStruct() && Struct < RHS.Struct)
+    return true;
+  if (isFeedback() && RHS.isFeedback() && Feedback < RHS.Feedback)
+    return true;
+  if (isTyped() && RHS.isTyped() && Typed < RHS.Typed)
+    return true;
+  if (isMultiSample() && RHS.isMultiSample() && MultiSample < RHS.MultiSample)
+    return true;
+  return false;
+}
+
 MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const {
   SmallVector<Metadata *, 11> MDVals;
 
@@ -534,18 +552,10 @@ namespace {
 class ResourceMapper {
   Module &M;
   LLVMContext &Context;
-  DXILResourceMap &Resources;
-
-  // In DXC, Record ID is unique per resource type. Match that.
-  uint32_t NextUAV = 0;
-  uint32_t NextSRV = 0;
-  uint32_t NextCBuf = 0;
-  uint32_t NextSmp = 0;
+  SmallVector<std::pair<CallInst *, dxil::ResourceInfo>> Resources;
 
 public:
-  ResourceMapper(Module &M,
-                 MapVector<CallInst *, dxil::ResourceInfo> &Resources)
-      : M(M), Context(M.getContext()), Resources(Resources) {}
+  ResourceMapper(Module &M) : M(M), Context(M.getContext()) {}
 
   void diagnoseHandle(CallInst *CI, const Twine &Msg,
                       DiagnosticSeverity Severity = DS_Error) {
@@ -585,13 +595,11 @@ class ResourceMapper {
     // TODO: We don't actually keep track of the name right now...
     StringRef Name = "";
 
-    auto [It, Success] = Resources.try_emplace(CI, RC, Kind, Symbol, Name);
-    assert(Success && "Mapping the same CallInst again?");
-    (void)Success;
-    // We grab a pointer into the map's storage, which isn't generally safe.
-    // Since we're just using this to fill in the info the map won't mutate and
-    // the pointer stays valid for as long as we need it to.
-    ResourceInfo *RI = &(It->second);
+    // 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
@@ -658,27 +666,18 @@ class ResourceMapper {
     if (!RI)
       return nullptr;
 
-    uint32_t NextID;
-    if (RI->isCBuffer())
-      NextID = NextCBuf++;
-    else if (RI->isSampler())
-      NextID = NextSmp++;
-    else if (RI->isUAV())
-      NextID = NextUAV++;
-    else
-      NextID = NextSRV++;
-
     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();
 
-    RI->bind(NextID, Space, LowerBound, Size);
+    // We use a binding ID of zero for now - these will be filled in later.
+    RI->bind(0U, Space, LowerBound, Size);
 
     return RI;
   }
 
-  void mapResources() {
+  DXILResourceMap mapResources() {
     for (Function &F : M.functions()) {
       if (!F.isDeclaration())
         continue;
@@ -697,11 +696,67 @@ class ResourceMapper {
         break;
       }
     }
+
+    return DXILResourceMap(std::move(Resources));
   }
 };
 
 } // namespace
 
+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);
+  });
+  for (auto [CI, RI] : CIToRI) {
+    if (Resources.empty() || RI != Resources.back())
+      Resources.push_back(RI);
+    CallMap[CI] = Resources.size() - 1;
+  }
+
+  unsigned Size = Resources.size();
+  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) {
+      FirstUAV = I;
+      NextID = 0;
+    } else if (RI.isCBuffer() && FirstCBuffer == Size) {
+      FirstCBuffer = I;
+      NextID = 0;
+    } if (RI.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);
+  }
+}
+
+void DXILResourceMap::print(raw_ostream &OS) const {
+  for (unsigned I = 0, E = Resources.size(); I != E; ++I) {
+    OS << "Binding " << I << ":\n";
+    Resources[I].print(OS);
+    OS << "\n";
+  }
+
+  for (const auto &[CI, Index] : CallMap) {
+    OS << "Call bound to " << Index << ":";
+    CI->print(OS);
+    OS << "\n";
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // DXILResourceAnalysis and DXILResourcePrinterPass
 
@@ -710,24 +765,14 @@ AnalysisKey DXILResourceAnalysis::Key;
 
 DXILResourceMap DXILResourceAnalysis::run(Module &M,
                                           ModuleAnalysisManager &AM) {
-  DXILResourceMap Data;
-  ResourceMapper(M, Data).mapResources();
+  DXILResourceMap Data = ResourceMapper(M).mapResources();
   return Data;
 }
 
 PreservedAnalyses DXILResourcePrinterPass::run(Module &M,
                                                ModuleAnalysisManager &AM) {
-  DXILResourceMap &Data =
-      AM.getResult<DXILResourceAnalysis>(M);
-
-  for (const auto &[Handle, Info] : Data) {
-    OS << "Binding for ";
-    Handle->print(OS);
-    OS << "\n";
-    Info.print(OS);
-    OS << "\n";
-  }
-
+  DXILResourceMap &DRM = AM.getResult<DXILResourceAnalysis>(M);
+  DRM.print(OS);
   return PreservedAnalyses::all();
 }
 
@@ -745,8 +790,7 @@ void DXILResourceWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
 }
 
 bool DXILResourceWrapperPass::runOnModule(Module &M) {
-  ResourceMap.reset(new DXILResourceMap());
-  ResourceMapper(M, *ResourceMap).mapResources();
+  ResourceMap.reset(new DXILResourceMap(ResourceMapper(M).mapResources()));
   return false;
 }
 
@@ -757,13 +801,7 @@ void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *) const {
     OS << "No resource map has been built!\n";
     return;
   }
-  for (const auto &[Handle, Info] : *ResourceMap) {
-    OS << "Binding for ";
-    Handle->print(OS);
-    OS << "\n";
-    Info.print(OS);
-    OS << "\n";
-  }
+  ResourceMap->print(OS);
 }
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
index 65802c6d1ff87a..b26a185423597d 100644
--- a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
+++ b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
@@ -3,55 +3,48 @@
 @G = external constant <4 x float>, align 4
 
 define void @test_typedbuffer() {
-  ; RWBuffer<float4> Buf : register(u5, space3)
-  %typed0 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
-              @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0(
-                  i32 3, i32 5, i32 1, i32 0, i1 false)
-  ; CHECK: Binding for %typed0
+  ; ByteAddressBuffer Buf : register(t8, space1)
+  %srv0 = call target("dx.RawBuffer", i8, 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: 3
-  ; CHECK:     Lower Bound: 5
+  ; CHECK:     Space: 1
+  ; CHECK:     Lower Bound: 8
   ; CHECK:     Size: 1
-  ; CHECK:   Class: UAV
-  ; CHECK:   Kind: TypedBuffer
-  ; CHECK:   Globally Coherent: 0
-  ; CHECK:   HasCounter: 0
-  ; CHECK:   IsROV: 0
-  ; CHECK:   Element Type: f32
-  ; CHECK:   Element Count: 4
+  ; CHECK:   Class: SRV
+  ; CHECK:   Kind: RawBuffer
 
-  ; RWBuffer<int> Buf : register(u7, space2)
-  %typed1 = call target("dx.TypedBuffer", i32, 1, 0, 1)
-      @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_1_0t(
-          i32 2, i32 7, i32 1, i32 0, i1 false)
-  ; CHECK: Binding for %typed1
+  ; struct S { float4 a; uint4 b; };
+  ; StructuredBuffer<S> Buf : register(t2, space4)
+  %srv1 = call target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0)
+      @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: 2
-  ; CHECK:     Lower Bound: 7
+  ; CHECK:     Space: 4
+  ; CHECK:     Lower Bound: 2
   ; CHECK:     Size: 1
-  ; CHECK:   Class: UAV
-  ; CHECK:   Kind: TypedBuffer
-  ; CHECK:   Globally Coherent: 0
-  ; CHECK:   HasCounter: 0
-  ; CHECK:   IsROV: 0
-  ; CHECK:   Element Type: i32
-  ; CHECK:   Element Count: 1
+  ; CHECK:   Class: SRV
+  ; CHECK:   Kind: StructuredBuffer
+  ; CHECK:   Buffer Stride: 32
+  ; CHECK:   Alignment: 4
 
   ; Buffer<uint4> Buf[24] : register(t3, space5)
-  %typed2 = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0)
+  %srv2 = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0)
       @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_0_0t(
           i32 5, i32 3, i32 24, i32 0, i1 false)
-  ; CHECK: Binding for %typed2
+  ; CHECK: Binding [[SRV2:[0-9]+]]:
   ; CHECK:   Symbol: ptr undef
   ; CHECK:   Name: ""
   ; CHECK:   Binding:
-  ; CHECK:     Record ID: 0
+  ; CHECK:     Record ID: 2
   ; CHECK:     Space: 5
   ; CHECK:     Lower Bound: 3
   ; CHECK:     Size: 24
@@ -60,67 +53,82 @@ define void @test_typedbuffer() {
   ; CHECK:   Element Type: u32
   ; CHECK:   Element Count: 4
 
-  ret void
-}
+  ; RWBuffer<int> Buf : register(u7, space2)
+  %uav0 = call target("dx.TypedBuffer", i32, 1, 0, 1)
+      @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
+  ; CHECK:     Lower Bound: 7
+  ; CHECK:     Size: 1
+  ; CHECK:   Class: UAV
+  ; CHECK:   Kind: TypedBuffer
+  ; CHECK:   Globally Coherent: 0
+  ; CHECK:   HasCounter: 0
+  ; CHECK:   IsROV: 0
+  ; CHECK:   Element Type: i32
+  ; CHECK:   Element Count: 1
 
-define void @test_structbuffer() {
-  ; struct S { float4 a; uint4 b; };
-  ; StructuredBuffer<S> Buf : register(t2, space4)
-  %struct0 = call target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0)
-      @llvm.dx.handle.fromBinding.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(
-          i32 4, i32 2, i32 1, i32 0, i1 false)
-  ; CHECK: Binding for %struct0
+  ; RWBuffer<float4> Buf : register(u5, space3)
+  %uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+              @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: 4
-  ; CHECK:     Lower Bound: 2
+  ; CHECK:     Space: 3
+  ; CHECK:     Lower Bound: 5
   ; CHECK:     Size: 1
-  ; CHECK:   Class: SRV
-  ; CHECK:   Kind: StructuredBuffer
-  ; CHECK:   Buffer Stride: 32
-  ; CHECK:   Alignment: 4...
[truncated]

Copy link

github-actions bot commented Aug 22, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

bogner added a commit that referenced this pull request Aug 22, 2024
Created using spr 1.3.5-bogner
bogner added a commit that referenced this pull request Aug 22, 2024
Created using spr 1.3.5-bogner
bogner added a commit that referenced this pull request Aug 22, 2024
Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner
@damyanp
Copy link
Contributor

damyanp commented Aug 22, 2024

Should your example be more like this?

RWBuffer<float4> BufferArray[10] : register(u0, space4);
RWBuffer<float4> B1 = BufferArray[0];
RWBuffer<float4> B2 = BufferArray[SomeIndex];
RWBuffer<float4> B3 = BufferArray[3];

Created using spr 1.3.5-bogner
@bogner bogner merged commit 782bc4f into main Aug 23, 2024
8 checks passed
@bogner bogner deleted the users/bogner/sprdxilanalysis-uniquify-duplicate-resources-in-dxilresourceanalysis branch August 23, 2024 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX llvm:analysis Includes value tracking, cost tables and constant folding
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[DirectX] Resource analysis results should not have duplicate resources
5 participants