llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-directx

Author: Helena Kotas (hekota)

<details>
<summary>Changes</summary>

Adds reporting of overlapping binding errors to 
`DXILPostOptimizationValidation` pass. Only runs when 
`DXILResourceBindingAnalysis` detects there is an overlapping binding.

Fixes #<!-- -->110723

Depends on #<!-- -->140635, #<!-- -->140645, #<!-- -->140981

---
Full diff: https://github.com/llvm/llvm-project/pull/140982.diff


6 Files Affected:

- (modified) llvm/include/llvm/Analysis/DXILResource.h (+5-2) 
- (modified) llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp (+51-8) 
- (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll (+17) 
- (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll (+17) 
- (added) llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll (+44) 
- (modified) 
llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll 
(+2-2) 


``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h 
b/llvm/include/llvm/Analysis/DXILResource.h
index a274e2294561e..f6e924041da11 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -355,6 +355,9 @@ class ResourceInfo {
       return std::tie(RecordID, Space, LowerBound, Size) <
              std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
     }
+    bool overlapsWith(const ResourceBinding &RHS) const {
+      return Space == RHS.Space && LowerBound + Size - 1 >= RHS.LowerBound;
+    }
   };
 
 private:
@@ -393,8 +396,8 @@ class ResourceInfo {
   getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const;
 
   bool operator==(const ResourceInfo &RHS) const {
-    return std::tie(Binding, HandleTy, Symbol) ==
-           std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
+    return std::tie(Binding, HandleTy, Symbol, Name) ==
+           std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol, RHS.Name);
   }
   bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); }
   bool operator<(const ResourceInfo &RHS) const {
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp 
b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index 1dc0c2fb13c11..c0bb6a61e8a24 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -9,6 +9,7 @@
 #include "DXILPostOptimizationValidation.h"
 #include "DXILShaderFlags.h"
 #include "DirectX.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/Analysis/DXILMetadataAnalysis.h"
 #include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/DiagnosticInfo.h"
@@ -50,15 +51,55 @@ static void reportInvalidDirection(Module &M, 
DXILResourceMap &DRM) {
   }
 }
 
-} // namespace
+static void reportOverlappingError(Module &M, ResourceInfo R1,
+                                   ResourceInfo R2) {
+  SmallString<64> Message;
+  raw_svector_ostream OS(Message);
+  OS << "resource " << R1.getName() << " at register "
+     << R1.getBinding().LowerBound << " overlaps with resource " << 
R2.getName()
+     << " at register " << R2.getBinding().LowerBound << ", space "
+     << R2.getBinding().Space;
+  M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
 
-PreservedAnalyses
-DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
-  DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
+static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
+  if (DRM.empty())
+    return;
 
+  for (auto ResList :
+       {DRM.srvs(), DRM.uavs(), DRM.cbuffers(), DRM.samplers()}) {
+    if (ResList.empty())
+      continue;
+    const ResourceInfo *PrevRI = &*ResList.begin();
+    for (auto *I = ResList.begin() + 1; I != ResList.end(); ++I) {
+      const ResourceInfo *RI = &*I;
+      if (PrevRI->getBinding().overlapsWith(RI->getBinding())) {
+        reportOverlappingError(M, *PrevRI, *RI);
+        continue;
+      }
+      PrevRI = RI;
+    }
+  }
+}
+
+static void reportErrors(Module &M, DXILResourceMap &DRM,
+                         DXILResourceBindingInfo &DRBI) {
   if (DRM.hasInvalidCounterDirection())
     reportInvalidDirection(M, DRM);
 
+  if (DRBI.hasOverlappingBinding())
+    reportOverlappingBinding(M, DRM);
+
+  assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in 
"
+                                       "DXILResourceImplicitBinding pass");
+}
+} // namespace
+
+PreservedAnalyses
+DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
+  DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
+  DXILResourceBindingInfo &DRBI = 
MAM.getResult<DXILResourceBindingAnalysis>(M);
+  reportErrors(M, DRM, DRBI);
   return PreservedAnalyses::all();
 }
 
@@ -68,10 +109,9 @@ class DXILPostOptimizationValidationLegacy : public 
ModulePass {
   bool runOnModule(Module &M) override {
     DXILResourceMap &DRM =
         getAnalysis<DXILResourceWrapperPass>().getResourceMap();
-
-    if (DRM.hasInvalidCounterDirection())
-      reportInvalidDirection(M, DRM);
-
+    DXILResourceBindingInfo &DRBI =
+        getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
+    reportErrors(M, DRM, DRBI);
     return false;
   }
   StringRef getPassName() const override {
@@ -82,7 +122,9 @@ class DXILPostOptimizationValidationLegacy : public 
ModulePass {
   static char ID; // Pass identification.
   void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
     AU.addRequired<DXILResourceWrapperPass>();
+    AU.addRequired<DXILResourceBindingWrapperPass>();
     AU.addPreserved<DXILResourceWrapperPass>();
+    AU.addPreserved<DXILResourceBindingWrapperPass>();
     AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
     AU.addPreserved<ShaderFlagsAnalysisWrapper>();
   }
@@ -92,6 +134,7 @@ char DXILPostOptimizationValidationLegacy::ID = 0;
 
 INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
                       "DXIL Post Optimization Validation", false, false)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
 INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
diff --git a/llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll 
b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll
new file mode 100644
index 0000000000000..2f8ad52e72e3b
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-1.ll
@@ -0,0 +1,17 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' 
-mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
+
+; Check overlap error for two resource arrays.
+
+; CHECK: error: resource A at register 0 overlaps with resource B at register 
5, space 0
+
+@A.str = private unnamed_addr constant [2 x i8] c"A\00", align 1
+@B.str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @test_overlapping() {
+entry:
+; RWBuffer<float> A[10] : register(u0);
+; RWBuffer<float> B[10] : register(u5);
+  %h1 = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 10, i32 4, i1 false, ptr 
@A.str)
+  %h2 = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 10, i32 4, i1 false, ptr 
@B.str)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll 
b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll
new file mode 100644
index 0000000000000..043f8c87dcc90
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-2.ll
@@ -0,0 +1,17 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' 
-mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
+
+; Check overlap error for two resources with identical binding
+
+; CHECK: error: resource R at register 5 overlaps with resource S at register 
5, space 10
+
+@R.str = private unnamed_addr constant [2 x i8] c"R\00", align 1
+@S.str = private unnamed_addr constant [2 x i8] c"S\00", align 1
+
+define void @test_overlapping() {
+entry:
+; RWBuffer<float> R : register(u5, space10);
+; RWBuffer<float> S : register(u5, space10);
+  %h1 = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 10, i32 5, i32 1, i32 0, i1 false, ptr 
@R.str)
+  %h2 = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 10, i32 5, i32 1, i32 0, i1 false, ptr 
@S.str)
+  ret void
+}
diff --git a/llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll 
b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll
new file mode 100644
index 0000000000000..f69f82f206106
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Binding/binding-overlap-3.ll
@@ -0,0 +1,44 @@
+; Use llc for this test so that we don't abort after the first error.
+; RUN: not llc %s -o /dev/null 2>&1 | FileCheck %s
+
+; Check multiple overlap errors.
+; Also check different resource class with same binding values is ok (no error 
expected).
+
+target triple = "dxil-pc-shadermodel6.3-library"
+
+; CHECK: error: resource C at register 0 overlaps with resource A at register 
5, space 0
+; CHECK: error: resource C at register 0 overlaps with resource B at register 
9, space 0
+
+@A.str = private unnamed_addr constant [2 x i8] c"A\00", align 1
+@B.str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+@C.str = private unnamed_addr constant [2 x i8] c"C\00", align 1
+@S.str = private unnamed_addr constant [2 x i8] c"S\00", align 1
+
+; Fake globals to store handles in; this is to make sure the handlefrombinding 
calls
+; are not optimized away by llc.
+@One = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 4
+@Two = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 4
+@Three = internal global { target("dx.RawBuffer", float, 0, 0) } poison, align 
4
+@Four = internal global { target("dx.TypedBuffer", float, 1, 0, 0) } poison, 
align 4
+
+define void @test_overlapping() "hlsl.export" {
+entry:
+; StructuredBuffer<float> A : register(t5);
+; StructuredBuffer<float> B : register(t9);
+; StructuredBuffer<float> C[10] : register(t0);
+; RWBuffer<float> S[10] : register(u0);
+
+  %h1 = call target("dx.RawBuffer", float, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false, ptr 
@A.str)
+  store target("dx.RawBuffer", float, 0, 0) %h1, ptr @One, align 4
+  
+  %h2 = call target("dx.RawBuffer", float, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 9, i32 1, i32 0, i1 false, ptr 
@B.str)
+  store target("dx.RawBuffer", float, 0, 0) %h2, ptr @Two, align 4
+ 
+  %h3 = call target("dx.RawBuffer", float, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 10, i32 4, i1 false, ptr 
@C.str)
+  store target("dx.RawBuffer", float, 0, 0) %h3, ptr @Three, align 4
+ 
+  %h4 = call target("dx.TypedBuffer", float, 1, 0, 0) 
@llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 false, ptr 
@S.str)
+  store target("dx.TypedBuffer", float, 1, 0, 0) %h4, ptr @Four, align 4
+  
+  ret void
+}
diff --git 
a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll 
b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
index 2c18d0b24326a..b0a5d5de77c29 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
@@ -26,7 +26,7 @@ define <4 x float> @multicomponent() #0 {
 ; CHECK: Function onecomponent : 0x00000000
 define float @onecomponent() #0 {
   %res = call target("dx.TypedBuffer", float, 1, 0, 0)
-      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 
false, ptr null)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 1, i32 1, i32 0, i1 
false, ptr null)
   %load = call {float, i1} @llvm.dx.resource.load.typedbuffer(
       target("dx.TypedBuffer", float, 1, 0, 0) %res, i32 0)
   %val = extractvalue {float, i1} %load, 0
@@ -36,7 +36,7 @@ define float @onecomponent() #0 {
 ; CHECK: Function noload : 0x00000000
 define void @noload(<4 x float> %val) #0 {
   %res = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
-      @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, i1 
false, ptr null)
+      @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, i1 
false, ptr null)
   call void @llvm.dx.resource.store.typedbuffer(
       target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %res, i32 0,
       <4 x float> %val)

``````````

</details>


https://github.com/llvm/llvm-project/pull/140982
_______________________________________________
llvm-branch-commits mailing list
llvm-branch-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to