[llvm-branch-commits] [llvm] [HLSL] Implementation of DXILResourceImplicitBinding pass (PR #138043)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Apr 30 15:16:08 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Helena Kotas (hekota)
<details>
<summary>Changes</summary>
The `DXILResourceImplicitBinding` pass uses the results of `DXILResourceBindingAnalysis` to assigns register slots to resources that do not have explicit binding. It replaces all `llvm.dx.resource.handlefromimplicitbinding` calls with `llvm.dx.resource.handlefrombinding` using the newly assigned binding.
If a binding cannot be found for a resource, the pass will raise a diagnostic error. Currently this diagnostic message does not include the resource name, which will be addressed in a separate task (#<!-- -->137868).
Part 2/2 of #<!-- -->136786
Closes #<!-- -->136786
---
Patch is 26.40 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138043.diff
16 Files Affected:
- (modified) llvm/include/llvm/Analysis/DXILResource.h (+8)
- (modified) llvm/include/llvm/InitializePasses.h (+1)
- (modified) llvm/lib/Analysis/Analysis.cpp (+1)
- (modified) llvm/lib/Analysis/DXILResource.cpp (+53)
- (modified) llvm/lib/Target/DirectX/CMakeLists.txt (+1)
- (added) llvm/lib/Target/DirectX/DXILResourceImplicitBinding.cpp (+182)
- (added) llvm/lib/Target/DirectX/DXILResourceImplicitBinding.h (+29)
- (modified) llvm/lib/Target/DirectX/DirectX.h (+6)
- (modified) llvm/lib/Target/DirectX/DirectXPassRegistry.def (+1)
- (modified) llvm/lib/Target/DirectX/DirectXTargetMachine.cpp (+3)
- (added) llvm/test/CodeGen/DirectX/ImplicitBinding/arrays.ll (+41)
- (added) llvm/test/CodeGen/DirectX/ImplicitBinding/multiple-spaces.ll (+44)
- (added) llvm/test/CodeGen/DirectX/ImplicitBinding/simple.ll (+30)
- (added) llvm/test/CodeGen/DirectX/ImplicitBinding/unbounded-arrays-error.ll (+34)
- (added) llvm/test/CodeGen/DirectX/ImplicitBinding/unbounded-arrays.ll (+42)
- (modified) llvm/test/CodeGen/DirectX/llc-pipeline.ll (+2)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 569f5346b9e36..fd34fdfda4c1c 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -632,12 +632,15 @@ class DXILResourceBindingInfo {
RegisterSpace(uint32_t Space) : Space(Space) {
FreeRanges.emplace_back(0, UINT32_MAX);
}
+ // Size == -1 means unbounded array
+ bool findAvailableBinding(int32_t Size, uint32_t *RegSlot);
};
struct BindingSpaces {
dxil::ResourceClass ResClass;
llvm::SmallVector<RegisterSpace> Spaces;
BindingSpaces(dxil::ResourceClass ResClass) : ResClass(ResClass) {}
+ RegisterSpace &getOrInsertSpace(uint32_t Space);
};
private:
@@ -658,6 +661,7 @@ class DXILResourceBindingInfo {
OverlappingBinding(false) {}
bool hasImplicitBinding() const { return ImplicitBinding; }
+ void setHasImplicitBinding(bool Value) { ImplicitBinding = Value; }
bool hasOverlappingBinding() const { return OverlappingBinding; }
BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) {
@@ -673,6 +677,10 @@ class DXILResourceBindingInfo {
}
}
+ // Size == -1 means unbounded array
+ bool findAvailableBinding(dxil::ResourceClass RC, uint32_t Space,
+ int32_t Size, uint32_t *RegSlot);
+
friend class DXILResourceBindingAnalysis;
friend class DXILResourceBindingWrapperPass;
};
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index b84c6d6123d58..71db56d922676 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -85,6 +85,7 @@ void initializeDCELegacyPassPass(PassRegistry &);
void initializeDXILMetadataAnalysisWrapperPassPass(PassRegistry &);
void initializeDXILMetadataAnalysisWrapperPrinterPass(PassRegistry &);
void initializeDXILResourceBindingWrapperPassPass(PassRegistry &);
+void initializeDXILResourceImplicitBindingLegacyPass(PassRegistry &);
void initializeDXILResourceTypeWrapperPassPass(PassRegistry &);
void initializeDXILResourceWrapperPassPass(PassRegistry &);
void initializeDeadMachineInstructionElimPass(PassRegistry &);
diff --git a/llvm/lib/Analysis/Analysis.cpp b/llvm/lib/Analysis/Analysis.cpp
index 484a456f49f1b..9f5daf32be9a0 100644
--- a/llvm/lib/Analysis/Analysis.cpp
+++ b/llvm/lib/Analysis/Analysis.cpp
@@ -27,6 +27,7 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
initializeCallGraphViewerPass(Registry);
initializeCycleInfoWrapperPassPass(Registry);
initializeDXILMetadataAnalysisWrapperPassPass(Registry);
+ initializeDXILResourceWrapperPassPass(Registry);
initializeDXILResourceBindingWrapperPassPass(Registry);
initializeDXILResourceTypeWrapperPassPass(Registry);
initializeDXILResourceWrapperPassPass(Registry);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index ce8e250a32ebe..34355c81e77b0 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -995,6 +995,59 @@ void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
}
}
+// returns false if binding could not be found in given space
+bool DXILResourceBindingInfo::findAvailableBinding(dxil::ResourceClass RC,
+ uint32_t Space, int32_t Size,
+ uint32_t *RegSlot) {
+ BindingSpaces &BS = getBindingSpaces(RC);
+ RegisterSpace &RS = BS.getOrInsertSpace(Space);
+ return RS.findAvailableBinding(Size, RegSlot);
+}
+
+DXILResourceBindingInfo::RegisterSpace &
+DXILResourceBindingInfo::BindingSpaces::getOrInsertSpace(uint32_t Space) {
+ for (auto *I = Spaces.begin(); I != Spaces.end(); ++I) {
+ if (I->Space == Space)
+ return *I;
+ if (I->Space < Space)
+ continue;
+ return *Spaces.insert(I, Space);
+ }
+ return Spaces.emplace_back(Space);
+}
+
+bool DXILResourceBindingInfo::RegisterSpace::findAvailableBinding(
+ int32_t Size, uint32_t *RegSlot) {
+ assert((Size == -1 || Size > 0) && "invalid size");
+
+ if (FreeRanges.empty())
+ return false;
+
+ // unbounded array
+ if (Size == -1) {
+ BindingRange &Last = FreeRanges.back();
+ if (Last.UpperBound != UINT32_MAX)
+ // this space is already occupied by an unbounded array
+ return false;
+ *RegSlot = Last.LowerBound;
+ FreeRanges.pop_back();
+ return true;
+ }
+
+ // single resource or fixed-size array
+ for (BindingRange &R : FreeRanges) {
+ if (R.UpperBound - R.LowerBound + 1 < (uint32_t)Size)
+ continue;
+ *RegSlot = R.LowerBound;
+ // This might create a range where (LowerBound == UpperBound + 1), but
+ // that's ok.
+ R.LowerBound += Size;
+ return true;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
AnalysisKey DXILResourceTypeAnalysis::Key;
diff --git a/llvm/lib/Target/DirectX/CMakeLists.txt b/llvm/lib/Target/DirectX/CMakeLists.txt
index 65105d3a5f4c3..9f5550a9a9ce8 100644
--- a/llvm/lib/Target/DirectX/CMakeLists.txt
+++ b/llvm/lib/Target/DirectX/CMakeLists.txt
@@ -31,6 +31,7 @@ add_llvm_target(DirectXCodeGen
DXILPrepare.cpp
DXILPrettyPrinter.cpp
DXILResourceAccess.cpp
+ DXILResourceImplicitBinding.cpp
DXILShaderFlags.cpp
DXILTranslateMetadata.cpp
DXILRootSignature.cpp
diff --git a/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.cpp b/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.cpp
new file mode 100644
index 0000000000000..80293ad7c9716
--- /dev/null
+++ b/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.cpp
@@ -0,0 +1,182 @@
+//===- DXILResourceImplicitBinding.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 "DXILResourceImplicitBinding.h"
+#include "DirectX.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Analysis/DXILResource.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
+#include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
+#include <cstdint>
+
+#define DEBUG_TYPE "dxil-resource-implicit-binding"
+
+using namespace llvm;
+using namespace llvm::dxil;
+
+namespace {
+
+static void diagnoseImplicitBindingNotFound(CallInst *ImplBindingCall) {
+ Function *F = ImplBindingCall->getFunction();
+ LLVMContext &Context = F->getParent()->getContext();
+ // FIXME: include the name of the resource in the error message
+ // (llvm/llvm-project#137868)
+ Context.diagnose(
+ DiagnosticInfoGenericWithLoc("resource cannot be allocated", *F,
+ ImplBindingCall->getDebugLoc(), DS_Error));
+}
+
+static bool assignBindings(Module &M, DXILResourceBindingInfo &DRBI,
+ DXILResourceTypeMap &DRTM) {
+ struct ImplBindingCall {
+ int OrderID;
+ CallInst *Call;
+ ImplBindingCall(int OrderID, CallInst *Call)
+ : OrderID(OrderID), Call(Call) {}
+ };
+ SmallVector<ImplBindingCall> Calls;
+ SmallVector<Function *> FunctionsToMaybeRemove;
+
+ // collect all of the llvm.dx.resource.handlefromImplicitbinding calls
+ for (Function &F : M.functions()) {
+ if (!F.isDeclaration())
+ continue;
+
+ if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefromimplicitbinding)
+ continue;
+
+ for (User *U : F.users()) {
+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
+ int OrderID = cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
+ Calls.emplace_back(OrderID, CI);
+ }
+ }
+ FunctionsToMaybeRemove.emplace_back(&F);
+ }
+
+ // sort all the collected implicit bindings by OrderID
+ llvm::stable_sort(
+ Calls, [](auto &LHS, auto &RHS) { return LHS.OrderID < RHS.OrderID; });
+
+ // iterate over sorted calls, find binding for each new OrderID and replace
+ // each call with dx_resource_handlefrombinding using the new binding
+ int LastOrderID = -1;
+ llvm::TargetExtType *HandleTy = nullptr;
+ ConstantInt *RegSlotOp = nullptr;
+ bool AllBindingsAssigned = true;
+ bool Changed = false;
+
+ for (auto &IB : Calls) {
+ IRBuilder<> Builder(IB.Call);
+
+ if (IB.OrderID != LastOrderID) {
+ LastOrderID = IB.OrderID;
+ HandleTy = cast<TargetExtType>(IB.Call->getType());
+ ResourceTypeInfo &RTI = DRTM[HandleTy];
+
+ uint32_t Space =
+ cast<ConstantInt>(IB.Call->getArgOperand(1))->getZExtValue();
+ int32_t Size =
+ cast<ConstantInt>(IB.Call->getArgOperand(2))->getZExtValue();
+
+ uint32_t RegSlot;
+ RegSlotOp = nullptr;
+ if (!DRBI.findAvailableBinding(RTI.getResourceClass(), Space, Size,
+ &RegSlot)) {
+ diagnoseImplicitBindingNotFound(IB.Call);
+ AllBindingsAssigned = false;
+ continue;
+ }
+ RegSlotOp = ConstantInt::get(Builder.getInt32Ty(), RegSlot);
+ }
+
+ if (!RegSlotOp)
+ continue;
+
+ auto *NewCall = Builder.CreateIntrinsic(
+ HandleTy, Intrinsic::dx_resource_handlefrombinding,
+ {IB.Call->getOperand(1), /* space */
+ RegSlotOp, /* register slot */
+ IB.Call->getOperand(2), /* size */
+ IB.Call->getOperand(3), /* index */
+ IB.Call->getOperand(4)}); /* non-uniform flag */
+ IB.Call->replaceAllUsesWith(NewCall);
+ IB.Call->eraseFromParent();
+ Changed = true;
+ }
+
+ for (Function *F : FunctionsToMaybeRemove) {
+ if (F->user_empty()) {
+ F->eraseFromParent();
+ Changed = true;
+ }
+ }
+
+ DRBI.setHasImplicitBinding(!AllBindingsAssigned);
+ return Changed;
+}
+
+} // end anonymous namespace
+
+PreservedAnalyses DXILResourceImplicitBinding::run(Module &M,
+ ModuleAnalysisManager &AM) {
+
+ PreservedAnalyses PA;
+
+ DXILResourceBindingInfo &DRBI = AM.getResult<DXILResourceBindingAnalysis>(M);
+ DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
+ if (DRBI.hasImplicitBinding())
+ if (assignBindings(M, DRBI, DRTM))
+ return PA;
+ return PreservedAnalyses::all();
+}
+
+namespace {
+
+class DXILResourceImplicitBindingLegacy : public ModulePass {
+public:
+ DXILResourceImplicitBindingLegacy() : ModulePass(ID) {}
+
+ bool runOnModule(Module &M) override {
+ DXILResourceTypeMap &DRTM =
+ getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
+ DXILResourceBindingInfo &DRBI =
+ getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
+
+ if (DRBI.hasImplicitBinding())
+ return assignBindings(M, DRBI, DRTM);
+ return false;
+ }
+
+ static char ID; // Pass identification.
+ void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.addRequired<DXILResourceTypeWrapperPass>();
+ AU.addRequired<DXILResourceBindingWrapperPass>();
+ }
+};
+
+char DXILResourceImplicitBindingLegacy::ID = 0;
+} // end anonymous namespace
+
+INITIALIZE_PASS_BEGIN(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
+ "DXIL Resource Implicit Binding", false, false)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
+INITIALIZE_PASS_END(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
+ "DXIL Resource Implicit Binding", false, false)
+
+ModulePass *llvm::createDXILResourceImplicitBindingLegacyPass() {
+ return new DXILResourceImplicitBindingLegacy();
+}
diff --git a/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.h b/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.h
new file mode 100644
index 0000000000000..86ca9ec6842a0
--- /dev/null
+++ b/llvm/lib/Target/DirectX/DXILResourceImplicitBinding.h
@@ -0,0 +1,29 @@
+//===- DXILResourceImplicitBindings.h --_____________-----------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// \file Assign register slots to resources without explicit binding.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H
+#define LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Pass.h"
+
+namespace llvm {
+
+class DXILResourceImplicitBinding
+ : public PassInfoMixin<DXILResourceImplicitBinding> {
+public:
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H
diff --git a/llvm/lib/Target/DirectX/DirectX.h b/llvm/lib/Target/DirectX/DirectX.h
index f64aaaf65d937..647b8ff42867c 100644
--- a/llvm/lib/Target/DirectX/DirectX.h
+++ b/llvm/lib/Target/DirectX/DirectX.h
@@ -78,6 +78,12 @@ void initializeDXILResourceAccessLegacyPass(PassRegistry &);
/// Pass to update resource accesses to use load/store directly.
FunctionPass *createDXILResourceAccessLegacyPass();
+/// Initializer for DXILResourceImplicitBindingLegacyPass
+void initializeDXILResourceImplicitBindingLegacyPass(PassRegistry &);
+
+/// Pass to assign register slots to resources without binding.
+ModulePass *createDXILResourceImplicitBindingLegacyPass();
+
/// Initializer for DXILTranslateMetadata.
void initializeDXILTranslateMetadataLegacyPass(PassRegistry &);
diff --git a/llvm/lib/Target/DirectX/DirectXPassRegistry.def b/llvm/lib/Target/DirectX/DirectXPassRegistry.def
index da239402d01eb..ef65b96799eae 100644
--- a/llvm/lib/Target/DirectX/DirectXPassRegistry.def
+++ b/llvm/lib/Target/DirectX/DirectXPassRegistry.def
@@ -30,6 +30,7 @@ MODULE_PASS("dxil-intrinsic-expansion", DXILIntrinsicExpansion())
MODULE_PASS("dxil-op-lower", DXILOpLowering())
MODULE_PASS("dxil-pretty-printer", DXILPrettyPrinterPass(dbgs()))
MODULE_PASS("dxil-translate-metadata", DXILTranslateMetadata())
+MODULE_PASS("dxil-resource-implicit-binding", DXILResourceImplicitBinding())
// TODO: rename to print<foo> after NPM switch
MODULE_PASS("print-dx-shader-flags", dxil::ShaderFlagsAnalysisPrinter(dbgs()))
MODULE_PASS("print<dxil-root-signature>", dxil::RootSignatureAnalysisPrinter(dbgs()))
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
index d3d1f94f3ab1c..2f2372b779092 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
@@ -21,6 +21,7 @@
#include "DXILOpLowering.h"
#include "DXILPrettyPrinter.h"
#include "DXILResourceAccess.h"
+#include "DXILResourceImplicitBinding.h"
#include "DXILRootSignature.h"
#include "DXILShaderFlags.h"
#include "DXILTranslateMetadata.h"
@@ -62,6 +63,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() {
initializeDXContainerGlobalsPass(*PR);
initializeDXILOpLoweringLegacyPass(*PR);
initializeDXILResourceAccessLegacyPass(*PR);
+ initializeDXILResourceImplicitBindingLegacyPass(*PR);
initializeDXILTranslateMetadataLegacyPass(*PR);
initializeShaderFlagsAnalysisWrapperPass(*PR);
initializeRootSignatureAnalysisWrapperPass(*PR);
@@ -99,6 +101,7 @@ class DirectXPassConfig : public TargetPassConfig {
FunctionPass *createTargetRegisterAllocator(bool) override { return nullptr; }
void addCodeGenPrepare() override {
addPass(createDXILFinalizeLinkageLegacyPass());
+ addPass(createDXILResourceImplicitBindingLegacyPass());
addPass(createDXILIntrinsicExpansionLegacyPass());
addPass(createDXILCBufferAccessLegacyPass());
addPass(createDXILDataScalarizationLegacyPass());
diff --git a/llvm/test/CodeGen/DirectX/ImplicitBinding/arrays.ll b/llvm/test/CodeGen/DirectX/ImplicitBinding/arrays.ll
new file mode 100644
index 0000000000000..6196472cb8374
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ImplicitBinding/arrays.ll
@@ -0,0 +1,41 @@
+; RUN: opt -S -dxil-resource-implicit-binding %s | FileCheck %s
+
+; Resources defined (with random order of handlefromimplicitbinding calls):
+; RWBuffer<float> A : register(u2);
+; RWBuffer<float> B[4]; // gets u3 because it does not fit before A (range 4)
+; RWBuffer<int> C[2]; // gets u0 because it fits before A (range 2)
+; RWBuffer<float> E[5]; // gets u7 which is right after B (range 5)
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+define void @test_arrays() {
+
+; RWBuffer<float> A : register(u2);
+ %bufA = call target("dx.TypedBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, i1 false)
+; no change to llvm.dx.resource.handlefrombinding
+; CHECK: %bufA = call target("dx.TypedBuffer", float, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 2, i32 1, i32 0, i1 false)
+
+; RWBuffer<float> E[2];
+ %bufE = call target("dx.TypedBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefromimplicitbinding(i32 30, i32 0, i32 5, i32 4, i1 false)
+; CHECK: %{{.*}} = call target("dx.TypedBuffer", float, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 7, i32 5, i32 4, i1 false)
+
+; RWBuffer<float> B[4];
+ %bufB = call target("dx.TypedBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefromimplicitbinding(i32 10, i32 0, i32 4, i32 2, i1 false)
+; CHECK: %{{.*}} = call target("dx.TypedBuffer", float, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 3, i32 4, i32 2, i1 false)
+
+; RWBuffer<int> C[2];
+ %bufC = call target("dx.TypedBuffer", i32, 1, 0, 0)
+ @llvm.dx.resource.handlefromimplicitbinding(i32 20, i32 0, i32 2, i32 1, i1 false)
+; CHECK: %{{.*}} = call target("dx.TypedBuffer", i32, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_1_0_0t(i32 0, i32 0, i32 2, i32 1, i1 false)
+
+; CHECK-NOT: @llvm.dx.resource.handlefromimplicitbinding
+ ret void
+}
+
diff --git a/llvm/test/CodeGen/DirectX/ImplicitBinding/multiple-spaces.ll b/llvm/test/CodeGen/DirectX/ImplicitBinding/multiple-spaces.ll
new file mode 100644
index 0000000000000..fce904e45ba09
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ImplicitBinding/multiple-spaces.ll
@@ -0,0 +1,44 @@
+; RUN: opt -S -dxil-resource-implicit-binding %s | FileCheck %s
+
+; Resources defined (with random order of handlefromimplicitbinding calls):
+; RWBuffer<float> A : register(u5); // defaults to space0
+; RWBuffer<int> B[]; // gets u6 (unbounded range)
+; RWBuffer<float> C[4] : register(space5); // gets u0 in space5
+; RWBuffer<int> D[] : register(space5); // gets u4 in space5
+; RWBuffer<float> E[3] : register(space10); // gets u0, space10
+; StructuredBuffer<int> F : register(space3);; // gets t0 in space3
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+define void @test_many_spaces() {
+
+; RWBuffer<float> A : register(u1);
+ %bufA = call target("dx.TypedBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 1, i32 1, i32 0, i1 false)
+; no change to llvm.dx.resource.handlefrombinding
+; CHECK: %bufA = call target("dx.TypedBuffer", float, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 1, i32 1, i32 0, i1 false)
+
+; RWBuffer<float> B[];
+%bufB = call target("dx.TypedBuffer", float, 1, 0, 0)
+ @llvm.dx.resource.handlefromimplicitbinding(i32 100, i32 0, i32 -1, i32 0, i1 false)
+; CHECK: %{{.*}} = call target("dx.TypedBuffer", float, 1, 0, 0)
+; CHECK-SAME: @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 6, i32 -1, i32 0, i1 false)
+
+; RWBuffer<int> C : register(u5);
+ %bufC = call target("dx.TypedBuffer", i32, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 5, i32 1, i32 0, i1 false)
+; no change to llvm.dx.resource.handlefrombinding
+; CHECK: %bufC = call target("dx.TypedBuffer", i32, 1, 0, 0)
+; CHECK-SAME:...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/138043
More information about the llvm-branch-commits
mailing list