Skip to content

Commit f58e2d5

Browse files
committed
[HLSL] Implementation of DXILResourceImplicitBinding pass
This pass takes advantage of the DXILResourceBinding analysis and assigns register slots to resources that do not have explicit binding. Part 2/2 of #136786 Closes #136786
1 parent bca1bf3 commit f58e2d5

16 files changed

+478
-0
lines changed

llvm/include/llvm/Analysis/DXILResource.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,12 +632,15 @@ class DXILResourceBindingInfo {
632632
RegisterSpace(uint32_t Space) : Space(Space) {
633633
FreeRanges.emplace_back(0, UINT32_MAX);
634634
}
635+
// Size == -1 means unbounded array
636+
bool findAvailableBinding(int32_t Size, uint32_t *RegSlot);
635637
};
636638

637639
struct BindingSpaces {
638640
dxil::ResourceClass ResClass;
639641
llvm::SmallVector<RegisterSpace> Spaces;
640642
BindingSpaces(dxil::ResourceClass ResClass) : ResClass(ResClass) {}
643+
RegisterSpace &getOrInsertSpace(uint32_t Space);
641644
};
642645

643646
private:
@@ -658,6 +661,7 @@ class DXILResourceBindingInfo {
658661
OverlappingBinding(false) {}
659662

660663
bool hasImplicitBinding() const { return ImplicitBinding; }
664+
void setHasImplicitBinding(bool Value) { ImplicitBinding = Value; }
661665
bool hasOverlappingBinding() const { return OverlappingBinding; }
662666

663667
BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) {
@@ -673,6 +677,10 @@ class DXILResourceBindingInfo {
673677
}
674678
}
675679

680+
// Size == -1 means unbounded array
681+
bool findAvailableBinding(dxil::ResourceClass RC, uint32_t Space,
682+
int32_t Size, uint32_t *RegSlot);
683+
676684
friend class DXILResourceBindingAnalysis;
677685
friend class DXILResourceBindingWrapperPass;
678686
};

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ void initializeDCELegacyPassPass(PassRegistry &);
8585
void initializeDXILMetadataAnalysisWrapperPassPass(PassRegistry &);
8686
void initializeDXILMetadataAnalysisWrapperPrinterPass(PassRegistry &);
8787
void initializeDXILResourceBindingWrapperPassPass(PassRegistry &);
88+
void initializeDXILResourceImplicitBindingLegacyPass(PassRegistry &);
8889
void initializeDXILResourceTypeWrapperPassPass(PassRegistry &);
8990
void initializeDXILResourceWrapperPassPass(PassRegistry &);
9091
void initializeDeadMachineInstructionElimPass(PassRegistry &);

llvm/lib/Analysis/Analysis.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
2727
initializeCallGraphViewerPass(Registry);
2828
initializeCycleInfoWrapperPassPass(Registry);
2929
initializeDXILMetadataAnalysisWrapperPassPass(Registry);
30+
initializeDXILResourceWrapperPassPass(Registry);
3031
initializeDXILResourceBindingWrapperPassPass(Registry);
3132
initializeDXILResourceTypeWrapperPassPass(Registry);
3233
initializeDXILResourceWrapperPassPass(Registry);

llvm/lib/Analysis/DXILResource.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,59 @@ void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
995995
}
996996
}
997997

998+
// returns false if binding could not be found in given space
999+
bool DXILResourceBindingInfo::findAvailableBinding(dxil::ResourceClass RC,
1000+
uint32_t Space, int32_t Size,
1001+
uint32_t *RegSlot) {
1002+
BindingSpaces &BS = getBindingSpaces(RC);
1003+
RegisterSpace &RS = BS.getOrInsertSpace(Space);
1004+
return RS.findAvailableBinding(Size, RegSlot);
1005+
}
1006+
1007+
DXILResourceBindingInfo::RegisterSpace &
1008+
DXILResourceBindingInfo::BindingSpaces::getOrInsertSpace(uint32_t Space) {
1009+
for (auto *I = Spaces.begin(); I != Spaces.end(); ++I) {
1010+
if (I->Space == Space)
1011+
return *I;
1012+
if (I->Space < Space)
1013+
continue;
1014+
return *Spaces.insert(I, Space);
1015+
}
1016+
return Spaces.emplace_back(Space);
1017+
}
1018+
1019+
bool DXILResourceBindingInfo::RegisterSpace::findAvailableBinding(
1020+
int32_t Size, uint32_t *RegSlot) {
1021+
assert((Size == -1 || Size > 0) && "invalid size");
1022+
1023+
if (FreeRanges.empty())
1024+
return false;
1025+
1026+
// unbounded array
1027+
if (Size == -1) {
1028+
BindingRange &Last = FreeRanges.back();
1029+
if (Last.UpperBound != UINT32_MAX)
1030+
// this space is already occupied by an unbounded array
1031+
return false;
1032+
*RegSlot = Last.LowerBound;
1033+
FreeRanges.pop_back();
1034+
return true;
1035+
}
1036+
1037+
// single resource or fixed-size array
1038+
for (BindingRange &R : FreeRanges) {
1039+
if (R.UpperBound - R.LowerBound + 1 < (uint32_t)Size)
1040+
continue;
1041+
*RegSlot = R.LowerBound;
1042+
// This might create a range where (LowerBound == UpperBound + 1), but
1043+
// that's ok.
1044+
R.LowerBound += Size;
1045+
return true;
1046+
}
1047+
1048+
return false;
1049+
}
1050+
9981051
//===----------------------------------------------------------------------===//
9991052

10001053
AnalysisKey DXILResourceTypeAnalysis::Key;

llvm/lib/Target/DirectX/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ add_llvm_target(DirectXCodeGen
3131
DXILPrepare.cpp
3232
DXILPrettyPrinter.cpp
3333
DXILResourceAccess.cpp
34+
DXILResourceImplicitBinding.cpp
3435
DXILShaderFlags.cpp
3536
DXILTranslateMetadata.cpp
3637
DXILRootSignature.cpp
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
//===- DXILResourceImplicitBinding.cpp -----------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DXILResourceImplicitBinding.h"
10+
#include "DirectX.h"
11+
#include "llvm/ADT/APInt.h"
12+
#include "llvm/ADT/STLExtras.h"
13+
#include "llvm/Analysis/DXILResource.h"
14+
#include "llvm/IR/Constants.h"
15+
#include "llvm/IR/DiagnosticInfo.h"
16+
#include "llvm/IR/Function.h"
17+
#include "llvm/IR/IRBuilder.h"
18+
#include "llvm/IR/Instructions.h"
19+
#include "llvm/IR/IntrinsicsDirectX.h"
20+
#include "llvm/IR/Module.h"
21+
#include "llvm/InitializePasses.h"
22+
#include <cstdint>
23+
24+
#define DEBUG_TYPE "dxil-resource-implicit-binding"
25+
26+
using namespace llvm;
27+
using namespace llvm::dxil;
28+
29+
namespace {
30+
31+
static void diagnoseImplicitBindingNotFound(CallInst *ImplBindingCall) {
32+
Function *F = ImplBindingCall->getFunction();
33+
LLVMContext &Context = F->getParent()->getContext();
34+
// FIXME: include the name of the resource in the error message
35+
// (llvm/llvm-project#137868)
36+
Context.diagnose(
37+
DiagnosticInfoGenericWithLoc("resource cannot be allocated", *F,
38+
ImplBindingCall->getDebugLoc(), DS_Error));
39+
}
40+
41+
static bool assignBindings(Module &M, DXILResourceBindingInfo &DRBI,
42+
DXILResourceTypeMap &DRTM) {
43+
struct ImplBindingCall {
44+
int OrderID;
45+
CallInst *Call;
46+
ImplBindingCall(int OrderID, CallInst *Call)
47+
: OrderID(OrderID), Call(Call) {}
48+
};
49+
SmallVector<ImplBindingCall> Calls;
50+
SmallVector<Function *> FunctionsToMaybeRemove;
51+
52+
// collect all of the llvm.dx.resource.handlefromImplicitbinding calls
53+
for (Function &F : M.functions()) {
54+
if (!F.isDeclaration())
55+
continue;
56+
57+
if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefromimplicitbinding)
58+
continue;
59+
60+
for (User *U : F.users()) {
61+
if (CallInst *CI = dyn_cast<CallInst>(U)) {
62+
int OrderID = cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
63+
Calls.emplace_back(OrderID, CI);
64+
}
65+
}
66+
FunctionsToMaybeRemove.emplace_back(&F);
67+
}
68+
69+
// sort all the collected implicit bindings by OrderID
70+
llvm::stable_sort(
71+
Calls, [](auto &LHS, auto &RHS) { return LHS.OrderID < RHS.OrderID; });
72+
73+
// iterate over sorted calls, find binding for each new OrderID and replace
74+
// each call with dx_resource_handlefrombinding using the new binding
75+
int LastOrderID = -1;
76+
llvm::TargetExtType *HandleTy = nullptr;
77+
ConstantInt *RegSlotOp = nullptr;
78+
bool AllBindingsAssigned = true;
79+
bool Changed = false;
80+
81+
for (auto &IB : Calls) {
82+
IRBuilder<> Builder(IB.Call);
83+
84+
if (IB.OrderID != LastOrderID) {
85+
LastOrderID = IB.OrderID;
86+
HandleTy = cast<TargetExtType>(IB.Call->getType());
87+
ResourceTypeInfo &RTI = DRTM[HandleTy];
88+
89+
uint32_t Space =
90+
cast<ConstantInt>(IB.Call->getArgOperand(1))->getZExtValue();
91+
int32_t Size =
92+
cast<ConstantInt>(IB.Call->getArgOperand(2))->getZExtValue();
93+
94+
uint32_t RegSlot;
95+
RegSlotOp = nullptr;
96+
if (!DRBI.findAvailableBinding(RTI.getResourceClass(), Space, Size,
97+
&RegSlot)) {
98+
diagnoseImplicitBindingNotFound(IB.Call);
99+
AllBindingsAssigned = false;
100+
continue;
101+
}
102+
RegSlotOp = ConstantInt::get(Builder.getInt32Ty(), RegSlot);
103+
}
104+
105+
if (!RegSlotOp)
106+
continue;
107+
108+
auto *NewCall = Builder.CreateIntrinsic(
109+
HandleTy, Intrinsic::dx_resource_handlefrombinding,
110+
{IB.Call->getOperand(1), /* space */
111+
RegSlotOp, /* register slot */
112+
IB.Call->getOperand(2), /* size */
113+
IB.Call->getOperand(3), /* index */
114+
IB.Call->getOperand(4)}); /* non-uniform flag */
115+
IB.Call->replaceAllUsesWith(NewCall);
116+
IB.Call->eraseFromParent();
117+
Changed = true;
118+
}
119+
120+
for (Function *F : FunctionsToMaybeRemove) {
121+
if (F->user_empty()) {
122+
F->eraseFromParent();
123+
Changed = true;
124+
}
125+
}
126+
127+
DRBI.setHasImplicitBinding(!AllBindingsAssigned);
128+
return Changed;
129+
}
130+
131+
} // end anonymous namespace
132+
133+
PreservedAnalyses DXILResourceImplicitBinding::run(Module &M,
134+
ModuleAnalysisManager &AM) {
135+
136+
PreservedAnalyses PA;
137+
138+
DXILResourceBindingInfo &DRBI = AM.getResult<DXILResourceBindingAnalysis>(M);
139+
DXILResourceTypeMap &DRTM = AM.getResult<DXILResourceTypeAnalysis>(M);
140+
if (DRBI.hasImplicitBinding())
141+
if (assignBindings(M, DRBI, DRTM))
142+
return PA;
143+
return PreservedAnalyses::all();
144+
}
145+
146+
namespace {
147+
148+
class DXILResourceImplicitBindingLegacy : public ModulePass {
149+
public:
150+
DXILResourceImplicitBindingLegacy() : ModulePass(ID) {}
151+
152+
bool runOnModule(Module &M) override {
153+
DXILResourceTypeMap &DRTM =
154+
getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
155+
DXILResourceBindingInfo &DRBI =
156+
getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
157+
158+
if (DRBI.hasImplicitBinding())
159+
return assignBindings(M, DRBI, DRTM);
160+
return false;
161+
}
162+
163+
static char ID; // Pass identification.
164+
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
165+
AU.addRequired<DXILResourceTypeWrapperPass>();
166+
AU.addRequired<DXILResourceBindingWrapperPass>();
167+
}
168+
};
169+
170+
char DXILResourceImplicitBindingLegacy::ID = 0;
171+
} // end anonymous namespace
172+
173+
INITIALIZE_PASS_BEGIN(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
174+
"DXIL Resource Implicit Binding", false, false)
175+
INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
176+
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
177+
INITIALIZE_PASS_END(DXILResourceImplicitBindingLegacy, DEBUG_TYPE,
178+
"DXIL Resource Implicit Binding", false, false)
179+
180+
ModulePass *llvm::createDXILResourceImplicitBindingLegacyPass() {
181+
return new DXILResourceImplicitBindingLegacy();
182+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===- DXILResourceImplicitBindings.h --_____________-----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// \file Assign register slots to resources without explicit binding.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H
14+
#define LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H
15+
16+
#include "llvm/IR/PassManager.h"
17+
#include "llvm/Pass.h"
18+
19+
namespace llvm {
20+
21+
class DXILResourceImplicitBinding
22+
: public PassInfoMixin<DXILResourceImplicitBinding> {
23+
public:
24+
PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
25+
};
26+
27+
} // namespace llvm
28+
29+
#endif // LLVM_LIB_TARGET_DIRECTX_DXILRESOURCEIMPLICITBINDING_H

llvm/lib/Target/DirectX/DirectX.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ void initializeDXILResourceAccessLegacyPass(PassRegistry &);
7878
/// Pass to update resource accesses to use load/store directly.
7979
FunctionPass *createDXILResourceAccessLegacyPass();
8080

81+
/// Initializer for DXILResourceImplicitBindingLegacyPass
82+
void initializeDXILResourceImplicitBindingLegacyPass(PassRegistry &);
83+
84+
/// Pass to assign register slots to resources without binding.
85+
ModulePass *createDXILResourceImplicitBindingLegacyPass();
86+
8187
/// Initializer for DXILTranslateMetadata.
8288
void initializeDXILTranslateMetadataLegacyPass(PassRegistry &);
8389

llvm/lib/Target/DirectX/DirectXPassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ MODULE_PASS("dxil-intrinsic-expansion", DXILIntrinsicExpansion())
3030
MODULE_PASS("dxil-op-lower", DXILOpLowering())
3131
MODULE_PASS("dxil-pretty-printer", DXILPrettyPrinterPass(dbgs()))
3232
MODULE_PASS("dxil-translate-metadata", DXILTranslateMetadata())
33+
MODULE_PASS("dxil-resource-implicit-binding", DXILResourceImplicitBinding())
3334
// TODO: rename to print<foo> after NPM switch
3435
MODULE_PASS("print-dx-shader-flags", dxil::ShaderFlagsAnalysisPrinter(dbgs()))
3536
MODULE_PASS("print<dxil-root-signature>", dxil::RootSignatureAnalysisPrinter(dbgs()))

llvm/lib/Target/DirectX/DirectXTargetMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "DXILOpLowering.h"
2222
#include "DXILPrettyPrinter.h"
2323
#include "DXILResourceAccess.h"
24+
#include "DXILResourceImplicitBinding.h"
2425
#include "DXILRootSignature.h"
2526
#include "DXILShaderFlags.h"
2627
#include "DXILTranslateMetadata.h"
@@ -62,6 +63,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeDirectXTarget() {
6263
initializeDXContainerGlobalsPass(*PR);
6364
initializeDXILOpLoweringLegacyPass(*PR);
6465
initializeDXILResourceAccessLegacyPass(*PR);
66+
initializeDXILResourceImplicitBindingLegacyPass(*PR);
6567
initializeDXILTranslateMetadataLegacyPass(*PR);
6668
initializeShaderFlagsAnalysisWrapperPass(*PR);
6769
initializeRootSignatureAnalysisWrapperPass(*PR);
@@ -99,6 +101,7 @@ class DirectXPassConfig : public TargetPassConfig {
99101
FunctionPass *createTargetRegisterAllocator(bool) override { return nullptr; }
100102
void addCodeGenPrepare() override {
101103
addPass(createDXILFinalizeLinkageLegacyPass());
104+
addPass(createDXILResourceImplicitBindingLegacyPass());
102105
addPass(createDXILIntrinsicExpansionLegacyPass());
103106
addPass(createDXILCBufferAccessLegacyPass());
104107
addPass(createDXILDataScalarizationLegacyPass());

0 commit comments

Comments
 (0)