Skip to content

[DirectX] Implement DXILResourceImplicitBinding pass #138043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
#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"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/DXILABI.h"
#include <climits>
#include <cstdint>

namespace llvm {
class CallInst;
Expand Down Expand Up @@ -586,6 +589,133 @@ class DXILResourceWrapperPass : public ModulePass {

ModulePass *createDXILResourceWrapperPassPass();

//===----------------------------------------------------------------------===//

// DXILResourceBindingInfo 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 DXILResourceBindingInfo {
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);
}
// 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:
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:
DXILResourceBindingInfo()
: SRVSpaces(dxil::ResourceClass::SRV),
UAVSpaces(dxil::ResourceClass::UAV),
CBufferSpaces(dxil::ResourceClass::CBuffer),
SamplerSpaces(dxil::ResourceClass::Sampler), ImplicitBinding(false),
OverlappingBinding(false) {}

bool hasImplicitBinding() const { return ImplicitBinding; }
void setHasImplicitBinding(bool Value) { ImplicitBinding = Value; }
bool hasOverlappingBinding() 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;
}
}

// 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;
};

class DXILResourceBindingAnalysis
: public AnalysisInfoMixin<DXILResourceBindingAnalysis> {
friend AnalysisInfoMixin<DXILResourceBindingAnalysis>;

static AnalysisKey Key;

public:
using Result = DXILResourceBindingInfo;

DXILResourceBindingInfo run(Module &M, ModuleAnalysisManager &AM);
};

class DXILResourceBindingWrapperPass : public ModulePass {
std::unique_ptr<DXILResourceBindingInfo> BindingInfo;

public:
static char ID;

DXILResourceBindingWrapperPass();
~DXILResourceBindingWrapperPass() override;

DXILResourceBindingInfo &getBindingInfo() { return *BindingInfo; }
const DXILResourceBindingInfo &getBindingInfo() const { return *BindingInfo; }

void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnModule(Module &M) override;
void releaseMemory() override;
};

ModulePass *createDXILResourceBindingWrapperPassPass();

} // namespace llvm

#endif // LLVM_ANALYSIS_DXILRESOURCE_H
9 changes: 9 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -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, llvm_i1_ty],
[IntrNoMem]>;

def int_dx_resource_getpointer
: DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty],
[IntrNoMem]>;
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ void initializeDAHPass(PassRegistry &);
void initializeDCELegacyPassPass(PassRegistry &);
void initializeDXILMetadataAnalysisWrapperPassPass(PassRegistry &);
void initializeDXILMetadataAnalysisWrapperPrinterPass(PassRegistry &);
void initializeDXILResourceWrapperPassPass(PassRegistry &);
void initializeDXILResourceBindingWrapperPassPass(PassRegistry &);
void initializeDXILResourceImplicitBindingLegacyPass(PassRegistry &);
void initializeDXILResourceTypeWrapperPassPass(PassRegistry &);
void initializeDXILResourceWrapperPassPass(PassRegistry &);
void initializeDeadMachineInstructionElimPass(PassRegistry &);
void initializeDebugifyMachineModulePass(PassRegistry &);
void initializeDependenceAnalysisWrapperPassPass(PassRegistry &);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Analysis/Analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ void llvm::initializeAnalysis(PassRegistry &Registry) {
initializeCycleInfoWrapperPassPass(Registry);
initializeDXILMetadataAnalysisWrapperPassPass(Registry);
initializeDXILResourceWrapperPassPass(Registry);
initializeDXILResourceBindingWrapperPassPass(Registry);
initializeDXILResourceTypeWrapperPassPass(Registry);
initializeDXILResourceWrapperPassPass(Registry);
initializeDependenceAnalysisWrapperPassPass(Registry);
initializeDominanceFrontierWrapperPassPass(Registry);
initializeDomViewerWrapperPassPass(Registry);
Expand Down
Loading
Loading