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