[llvm] [HLSL] Implement DXILResourceBindingAnalysis (PR #137258)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 24 15:15:03 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-directx
Author: Helena Kotas (hekota)
<details>
<summary>Changes</summary>
`DXILResourceBindingAnalysis` analyses explicit resource bindings in the module and puts together lists of used virtual register spaces and available virtual register slot ranges for each binding type. It also stores additional information found during the analysis such as whether the module uses implicit bindings or if any of the bindings overlap.
This information will be used in `DXILResourceImplicitBindings` pass (coming soon) to assign register slots to resources with implicit bindings, and in a post-optimization validation pass that will raise diagnostic about overlapping bindings.
Part 1/2 of #<!-- -->136786
---
Patch is 22.86 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/137258.diff
6 Files Affected:
- (modified) llvm/include/llvm/Analysis/DXILResource.h (+105)
- (modified) llvm/include/llvm/IR/IntrinsicsDirectX.td (+9)
- (modified) llvm/lib/Analysis/DXILResource.cpp (+125)
- (modified) llvm/lib/Passes/PassRegistry.def (+1)
- (modified) llvm/unittests/Target/DirectX/CMakeLists.txt (+1)
- (added) llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp (+268)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 1d871a448c16c..5019fc38665ff 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -10,6 +10,7 @@
#define LLVM_ANALYSIS_DXILRESOURCE_H
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
@@ -17,6 +18,8 @@
#include "llvm/Pass.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/DXILABI.h"
+#include <climits>
+#include <cstdint>
namespace llvm {
class CallInst;
@@ -586,6 +589,108 @@ class DXILResourceWrapperPass : public ModulePass {
ModulePass *createDXILResourceWrapperPassPass();
+//===----------------------------------------------------------------------===//
+
+// DXILResourceBindingsInfo stores the results of DXILResourceBindingAnalysis
+// which analyses all llvm.dx.resource.handlefrombinding calls in the module
+// and puts together lists of used virtual register spaces and available
+// virtual register slot ranges for each binding type.
+// It also stores additional information found during the analysis such as
+// whether the module uses implicit bindings or if any of the bindings overlap.
+//
+// This information will be used in DXILResourceImplicitBindings pass to assign
+// register slots to resources with implicit bindings, and in a
+// post-optimization validation pass that will raise diagnostic about
+// overlapping bindings.
+//
+// For example for these resource bindings:
+//
+// RWBuffer<float> A[10] : register(u3);
+// RWBuffer<float> B[] : register(u5, space2)
+//
+// The analysis result for UAV binding type will look like this:
+//
+// UAVSpaces {
+// ResClass = ResourceClass::UAV,
+// Spaces = {
+// { Space = 0, FreeRanges = {{ 0, 2 }, { 13, UINT32_MAX }} },
+// { Space = 2, FreeRanges = {{ 0, 4 }} }
+// }
+// }
+//
+class DXILResourceBindingsInfo {
+public:
+ struct BindingRange {
+ uint32_t LowerBound;
+ uint32_t UpperBound;
+ BindingRange(uint32_t LB, uint32_t UB) : LowerBound(LB), UpperBound(UB) {}
+ };
+
+ struct RegisterSpace {
+ uint32_t Space;
+ SmallVector<BindingRange> FreeRanges;
+ RegisterSpace(uint32_t Space) : Space(Space) {
+ FreeRanges.emplace_back(0, UINT32_MAX);
+ }
+ };
+
+ struct BindingSpaces {
+ dxil::ResourceClass ResClass;
+ llvm::SmallVector<RegisterSpace> Spaces;
+ BindingSpaces(dxil::ResourceClass ResClass) : ResClass(ResClass) {
+ // initialize space0
+ Spaces.emplace_back(0);
+ }
+ };
+
+private:
+ BindingSpaces SRVSpaces, UAVSpaces, CBufferSpaces, SamplerSpaces;
+ bool ImplicitBinding;
+ bool OverlappingBinding;
+
+ // Populate the resource binding info given explicit resource binding calls
+ // in the module.
+ void populate(Module &M, DXILResourceTypeMap &DRTM);
+
+public:
+ DXILResourceBindingsInfo()
+ : SRVSpaces(dxil::ResourceClass::SRV),
+ UAVSpaces(dxil::ResourceClass::UAV),
+ CBufferSpaces(dxil::ResourceClass::CBuffer),
+ SamplerSpaces(dxil::ResourceClass::Sampler), ImplicitBinding(false),
+ OverlappingBinding(false) {}
+
+ bool containsImplicitBinding() const { return ImplicitBinding; }
+ bool containsOverlappingBinding() const { return OverlappingBinding; }
+
+ BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) {
+ switch (RC) {
+ case dxil::ResourceClass::SRV:
+ return SRVSpaces;
+ case dxil::ResourceClass::UAV:
+ return UAVSpaces;
+ case dxil::ResourceClass::CBuffer:
+ return CBufferSpaces;
+ case dxil::ResourceClass::Sampler:
+ return SamplerSpaces;
+ }
+ }
+
+ friend class DXILResourceBindingAnalysis;
+};
+
+class DXILResourceBindingAnalysis
+ : public AnalysisInfoMixin<DXILResourceBindingAnalysis> {
+ friend AnalysisInfoMixin<DXILResourceBindingAnalysis>;
+
+ static AnalysisKey Key;
+
+public:
+ using Result = DXILResourceBindingsInfo;
+
+ DXILResourceBindingsInfo run(Module &M, ModuleAnalysisManager &AM);
+};
+
} // namespace llvm
#endif // LLVM_ANALYSIS_DXILRESOURCE_H
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index b1a27311e2a9c..444600980fc1e 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -27,6 +27,15 @@ def int_dx_resource_handlefrombinding
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty],
[IntrNoMem]>;
+// Create resource handle with implicit binding in given register space.
+// Returns a `target("dx.")` type appropriate for the kind of resource and
+// the range size and index of the binding.
+def int_dx_resource_handlefromimplicitbinding
+ : DefaultAttrsIntrinsic<
+ [llvm_any_ty],
+ [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
+ [IntrNoMem]>;
+
def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index cc1d931c9e077..1ca73ce81789a 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -8,7 +8,9 @@
#include "llvm/Analysis/DXILResource.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DiagnosticInfo.h"
@@ -19,6 +21,8 @@
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/FormatVariadic.h"
+#include <climits>
+#include <cstdint>
#define DEBUG_TYPE "dxil-resource"
@@ -879,8 +883,121 @@ SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) {
//===----------------------------------------------------------------------===//
+void DXILResourceBindingsInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
+ struct Binding {
+ ResourceClass ResClass;
+ uint32_t Space;
+ uint32_t LowerBound;
+ uint32_t UpperBound;
+ Binding(ResourceClass RC, uint32_t Sp, uint32_t LB, uint32_t UB)
+ : ResClass(RC), Space(Sp), LowerBound(LB), UpperBound(UB) {}
+ };
+ SmallVector<Binding> Bindings;
+
+ // collect all of the llvm.dx.resource.handlefrombinding calls;
+ // make a note if there is llvm.dx.resource.handlefromimplicitbinding
+ for (Function &F : M.functions()) {
+ if (!F.isDeclaration())
+ continue;
+
+ switch (F.getIntrinsicID()) {
+ default:
+ continue;
+ case Intrinsic::dx_resource_handlefrombinding: {
+ auto *HandleTy = cast<TargetExtType>(F.getReturnType());
+ ResourceTypeInfo &RTI = DRTM[HandleTy];
+
+ for (User *U : F.users())
+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
+ uint32_t Space =
+ cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
+ uint32_t LowerBound =
+ cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
+ int32_t Size =
+ cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
+
+ // negative size means unbounded resource array;
+ // upper bound register overflow should be detected in Sema
+ assert((Size < 0 || (unsigned)LowerBound + Size - 1 <= UINT32_MAX) &&
+ "upper bound register overflow");
+ uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1;
+ Bindings.emplace_back(RTI.getResourceClass(), Space, LowerBound,
+ UpperBound);
+ }
+ break;
+ }
+ case Intrinsic::dx_resource_handlefromimplicitbinding: {
+ if (!F.user_empty())
+ ImplicitBinding = true;
+ break;
+ }
+ }
+ }
+
+ // sort all the collected bindings
+ llvm::stable_sort(Bindings, [](auto &LHS, auto &RHS) {
+ return std::tie(LHS.ResClass, LHS.Space, LHS.LowerBound) <
+ std::tie(RHS.ResClass, RHS.Space, RHS.LowerBound);
+ });
+
+ // remove duplicates
+ llvm::unique(Bindings, [](auto &LHS, auto &RHS) {
+ return std::tie(LHS.ResClass, LHS.Space, LHS.LowerBound, LHS.UpperBound) ==
+ std::tie(RHS.ResClass, RHS.Space, RHS.LowerBound, RHS.UpperBound);
+ });
+
+ // Go over the sorted bindings and build up lists of free register ranges
+ // for each binding type and used spaces. Bindings are sorted by resource
+ // class, space, and lower bound register slot.
+ BindingSpaces *BS = &SRVSpaces;
+ for (unsigned I = 0, E = Bindings.size(); I != E; ++I) {
+ Binding &B = Bindings[I];
+
+ if (BS->ResClass != B.ResClass)
+ // move to the next resource class spaces
+ BS = &getBindingSpaces(B.ResClass);
+
+ RegisterSpace *S = &BS->Spaces.back();
+ assert(S->Space <= B.Space && "bindings not sorted correctly?");
+ if (B.Space != S->Space)
+ // add new space
+ S = &BS->Spaces.emplace_back(B.Space);
+
+ // the space is full - set flag to report overlapping binding later
+ if (S->FreeRanges.empty()) {
+ OverlappingBinding = true;
+ continue;
+ }
+
+ // adjust the last free range lower bound, split it in two, or remove it
+ BindingRange &LastFreeRange = S->FreeRanges.back();
+ assert(LastFreeRange.UpperBound == UINT32_MAX);
+ if (LastFreeRange.LowerBound == B.LowerBound) {
+ if (B.UpperBound < UINT32_MAX)
+ LastFreeRange.LowerBound = B.UpperBound + 1;
+ else
+ S->FreeRanges.pop_back();
+
+ } else if (LastFreeRange.LowerBound < B.LowerBound) {
+ LastFreeRange.UpperBound = B.LowerBound - 1;
+ if (B.UpperBound < UINT32_MAX)
+ S->FreeRanges.emplace_back(B.UpperBound + 1, UINT32_MAX);
+ } else {
+ OverlappingBinding = true;
+ if (B.UpperBound < UINT32_MAX)
+ LastFreeRange.LowerBound =
+ std::max(LastFreeRange.LowerBound, B.UpperBound + 1);
+ else
+ S->FreeRanges.pop_back();
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+
AnalysisKey DXILResourceTypeAnalysis::Key;
AnalysisKey DXILResourceAnalysis::Key;
+AnalysisKey DXILResourceBindingAnalysis::Key;
DXILResourceMap DXILResourceAnalysis::run(Module &M,
ModuleAnalysisManager &AM) {
@@ -890,6 +1007,14 @@ DXILResourceMap DXILResourceAnalysis::run(Module &M,
return Data;
}
+DXILResourceBindingsInfo
+DXILResourceBindingAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
+ DXILResourceBindingsInfo 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);
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index d5d1b2173da69..ea792280ed975 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -24,6 +24,7 @@ MODULE_ANALYSIS("ctx-prof-analysis", CtxProfAnalysis())
MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
MODULE_ANALYSIS("dxil-resources", DXILResourceAnalysis())
MODULE_ANALYSIS("dxil-resource-type", DXILResourceTypeAnalysis())
+MODULE_ANALYSIS("dxil-resource-bindings", DXILResourceBindingAnalysis())
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
diff --git a/llvm/unittests/Target/DirectX/CMakeLists.txt b/llvm/unittests/Target/DirectX/CMakeLists.txt
index b1359b37ad521..2c135c1b4b499 100644
--- a/llvm/unittests/Target/DirectX/CMakeLists.txt
+++ b/llvm/unittests/Target/DirectX/CMakeLists.txt
@@ -22,4 +22,5 @@ add_llvm_target_unittest(DirectXTests
PointerTypeAnalysisTests.cpp
UniqueResourceFromUseTests.cpp
RegisterCostTests.cpp
+ ResourceBindingAnalysisTests.cpp
)
diff --git a/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp b/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp
new file mode 100644
index 0000000000000..3ff091d67a886
--- /dev/null
+++ b/llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp
@@ -0,0 +1,268 @@
+//===- llvm/unittests/Target/DirectX/ResourceBindingAnalysisTests.cpp -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Analysis/DXILResource.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/Passes/PassBuilder.h"
+#include "llvm/Support/DXILABI.h"
+#include "gtest/gtest.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::dxil;
+
+namespace {
+class ResourceBindingAnalysisTest : public testing::Test {
+protected:
+ PassBuilder *PB;
+ ModuleAnalysisManager *MAM;
+ LLVMContext *Context;
+
+ virtual void SetUp() {
+ PB = new PassBuilder();
+ MAM = new ModuleAnalysisManager();
+ Context = new LLVMContext();
+ PB->registerModuleAnalyses(*MAM);
+ MAM->registerPass([&] { return DXILResourceBindingAnalysis(); });
+ }
+
+ std::unique_ptr<Module> parseAsm(StringRef Asm) {
+ SMDiagnostic Error;
+ std::unique_ptr<Module> M = parseAssemblyString(Asm, Error, *Context);
+ EXPECT_TRUE(M) << "Bad assembly?: " << Error.getMessage();
+ return M;
+ }
+
+ virtual void TearDown() {
+ delete PB;
+ delete MAM;
+ delete Context;
+ }
+
+ void checkExpectedSpaceAndFreeRanges(
+ DXILResourceBindingsInfo::RegisterSpace &RegSpace, uint32_t ExpSpace,
+ ArrayRef<uint32_t> ExpValues) {
+ EXPECT_EQ(RegSpace.Space, ExpSpace);
+ EXPECT_EQ(RegSpace.FreeRanges.size() * 2, ExpValues.size());
+ unsigned I = 0;
+ for (auto &R : RegSpace.FreeRanges) {
+ EXPECT_EQ(R.LowerBound, ExpValues[I]);
+ EXPECT_EQ(R.UpperBound, ExpValues[I + 1]);
+ I += 2;
+ }
+ }
+};
+
+TEST_F(ResourceBindingAnalysisTest, TestTrivialCase) {
+ // RWBuffer<float> Buf : register(u5);
+ StringRef Assembly = R"(
+define void @main() {
+entry:
+ %handle = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false)
+
+ call void @a.func(target("dx.TypedBuffer", float, 1, 0, 0) %handle)
+ ret void
+}
+
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+ )";
+
+ auto M = parseAsm(Assembly);
+
+ DXILResourceBindingsInfo &DRBI =
+ MAM->getResult<DXILResourceBindingAnalysis>(*M);
+
+ EXPECT_EQ(false, DRBI.containsImplicitBinding());
+ EXPECT_EQ(false, DRBI.containsOverlappingBinding());
+
+ // check that UAV has exactly one gap
+ DXILResourceBindingsInfo::BindingSpaces &UAVSpaces =
+ DRBI.getBindingSpaces(ResourceClass::UAV);
+ EXPECT_EQ(UAVSpaces.ResClass, ResourceClass::UAV);
+ EXPECT_EQ(UAVSpaces.Spaces.size(), 1u);
+ checkExpectedSpaceAndFreeRanges(UAVSpaces.Spaces[0], 0,
+ {0, 4, 6, UINT32_MAX});
+
+ // check that other kinds of register spaces are all available
+ for (auto RC :
+ {ResourceClass::SRV, ResourceClass::CBuffer, ResourceClass::Sampler}) {
+ DXILResourceBindingsInfo::BindingSpaces &Spaces = DRBI.getBindingSpaces(RC);
+ EXPECT_EQ(Spaces.ResClass, RC);
+ EXPECT_EQ(Spaces.Spaces.size(), 1u);
+ checkExpectedSpaceAndFreeRanges(Spaces.Spaces[0], 0, {0, UINT32_MAX});
+ }
+}
+
+TEST_F(ResourceBindingAnalysisTest, TestManyBindings) {
+ // cbuffer CB : register(b3) { int a; }
+ // RWBuffer<float4> A[5] : register(u10, space20);
+ // StructuredBuffer<int> B : register(t5);
+ // RWBuffer<float> C : register(u5);
+ // StructuredBuffer<int> D[5] : register(t0);
+ // RWBuffer<float> E[2] : register(u2);
+ StringRef Assembly = R"(
+%__cblayout_CB = type <{ i32 }>
+define void @main() {
+entry:
+ %handleCB = call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) @llvm.dx.resource.handlefrombinding(i32 0, i32 3, i32 1, i32 0, i1 false)
+ %handleA = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 20, i32 10, i32 5, i32 0, i1 false)
+ %handleB = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false)
+ %handleC = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false)
+ %handleD = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 5, i32 4, i1 false)
+ %handleE = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 2, i32 0, i1 false)
+
+ call void @a.func(target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) %handleCB)
+ call void @a.func(target("dx.TypedBuffer", float, 1, 0, 0) %handleA)
+ call void @a.func(target("dx.TypedBuffer", float, 1, 0, 0) %handleC)
+ call void @a.func(target("dx.TypedBuffer", float, 1, 0, 0) %handleE)
+ call void @a.func(target("dx.RawBuffer", i32, 0, 0) %handleB)
+ call void @a.func(target("dx.RawBuffer", i32, 0, 0) %handleD)
+
+ ret void
+}
+
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+ )";
+
+ auto M = parseAsm(Assembly);
+
+ DXILResourceBindingsInfo &DRBI =
+ MAM->getResult<DXILResourceBindingAnalysis>(*M);
+
+ EXPECT_EQ(false, DRBI.containsImplicitBinding());
+ EXPECT_EQ(false, DRBI.containsOverlappingBinding());
+
+ DXILResourceBindingsInfo::BindingSpaces &SRVSpaces =
+ DRBI.getBindingSpaces(ResourceClass::SRV);
+ EXPECT_EQ(SRVSpaces.ResClass, ResourceClass::SRV);
+ EXPECT_EQ(SRVSpaces.Spaces.size(), 1u);
+ checkExpectedSpaceAndFreeRanges(SRVSpaces.Spaces[0], 0, {6, UINT32_MAX});
+
+ DXILResourceBindingsInfo::BindingSpaces &UAVSpaces =
+ DRBI.getBindingSpaces(ResourceClass::UAV);
+ EXPECT_EQ(UAVSpaces.ResClass, ResourceClass::UAV);
+ EXPECT_EQ(UAVSpaces.Spaces.size(), 2u);
+ checkExpectedSpaceAndFreeRanges(UAVSpaces.Spaces[0], 0,
+ {0, 1, 4, 4, 6, UINT32_MAX});
+ checkExpectedSpaceAndFreeRanges(UAVSpaces.Spaces[1], 20,
+ {0, 9, 15, UINT32_MAX});
+
+ DXILResourceBindingsInfo::BindingSpaces &CBufferSpaces =
+ DRBI.getBindingSpaces(ResourceClass::CBuffer);
+ EXPECT_EQ(CBufferSpaces.ResClass, ResourceClass::CBuffer);
+ EXPECT_EQ(CBufferSpaces.Spaces.size(), 1u);
+ checkExpectedSpaceAndFreeRanges(CBufferSpaces.Spaces[0], 0,
+ {0, 2, 4, UINT32_MAX});
+}
+
+TEST_F(ResourceBindingAnalysisTest, TestUnboundedAndOverlap) {
+ // StructuredBuffer<float> A[] : register(t5);
+ // StructuredBuffer<float> B[3] : register(t0);
+ // StructuredBuffer<float> C[] : register(t0, space2);
+ // StructuredBuffer<float> D : register(t4, space2); /* overlapping */
+ StringRef Assembly = R"(
+%__cblayout_CB = type <{ i32 }>
+define void @main() {
+entry:
+ %handleA = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 -1, i32 10, i1 false)
+ %handleB = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 3, i32 0, i1 false)
+ %handleC = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 0, i32 -1, i32 100, i1 false)
+ %handleD = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 4, i32 1, i32 0, i1 false)
+
+ call void @a.func(target("dx.RawBuffer", float, 0, 0) %handleA)
+ call void @a.func(target("dx.RawBuffer", float, 0, 0) %handleB)
+ call void @a.func(target("dx.RawBuffer", float, 0, 0) %handleC)
+ call void @a.func(target("dx.RawBuffer", float, 0, 0) %handleD)
+
+ ret void
+}
+
+declare void @a.func(target("dx.RawBuffer", float, 0, 0) %handle)
+ )";
+
+ auto M = parseAsm(Assembly);
+
+ DXILResourceBindingsInfo &DRBI =
+ MAM->getResult<DXILResourceBindingAnalysis>(*M);
+
+ EXPECT_EQ(false, DRBI.containsImplicitBinding());
+ EXPECT_EQ(true, DRBI.containsOverlappingBinding());
+
+ DXILResourceBindingsInfo::BindingSpaces &SRVSpaces =
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/137258
More information about the llvm-commits
mailing list