Skip to content

Commit 0c00e30

Browse files
committed
[HLSL][DirectX] Extract HLSLBinding out of DXILResource. NFC
We extract the binding logic out of the DXILResource analysis passes into the FrontendHLSL library. This will allow us to use this logic for resource and root signature bindings in both the DirectX backend and the HLSL frontend.
1 parent 3b5aff5 commit 0c00e30

File tree

9 files changed

+603
-365
lines changed

9 files changed

+603
-365
lines changed

llvm/include/llvm/Analysis/DXILResource.h

Lines changed: 11 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/ADT/MapVector.h"
1313
#include "llvm/ADT/SmallVector.h"
1414
#include "llvm/ADT/StringRef.h"
15+
#include "llvm/Frontend/HLSL/HLSLBinding.h"
1516
#include "llvm/IR/DerivedTypes.h"
1617
#include "llvm/IR/GlobalVariable.h"
1718
#include "llvm/IR/PassManager.h"
@@ -633,86 +634,25 @@ LLVM_ABI ModulePass *createDXILResourceWrapperPassPass();
633634
// register slots to resources with implicit bindings, and in a
634635
// post-optimization validation pass that will raise diagnostic about
635636
// overlapping bindings.
636-
//
637-
// For example for these resource bindings:
638-
//
639-
// RWBuffer<float> A[10] : register(u3);
640-
// RWBuffer<float> B[] : register(u5, space2)
641-
//
642-
// The analysis result for UAV binding type will look like this:
643-
//
644-
// UAVSpaces {
645-
// ResClass = ResourceClass::UAV,
646-
// Spaces = {
647-
// { Space = 0, FreeRanges = {{ 0, 2 }, { 13, UINT32_MAX }} },
648-
// { Space = 2, FreeRanges = {{ 0, 4 }} }
649-
// }
650-
// }
651-
//
652637
class DXILResourceBindingInfo {
653-
public:
654-
struct BindingRange {
655-
uint32_t LowerBound;
656-
uint32_t UpperBound;
657-
BindingRange(uint32_t LB, uint32_t UB) : LowerBound(LB), UpperBound(UB) {}
658-
};
659-
660-
struct RegisterSpace {
661-
uint32_t Space;
662-
SmallVector<BindingRange> FreeRanges;
663-
RegisterSpace(uint32_t Space) : Space(Space) {
664-
FreeRanges.emplace_back(0, UINT32_MAX);
665-
}
666-
// Size == -1 means unbounded array
667-
LLVM_ABI std::optional<uint32_t> findAvailableBinding(int32_t Size);
668-
};
669-
670-
struct BindingSpaces {
671-
dxil::ResourceClass RC;
672-
llvm::SmallVector<RegisterSpace> Spaces;
673-
BindingSpaces(dxil::ResourceClass RC) : RC(RC) {}
674-
LLVM_ABI RegisterSpace &getOrInsertSpace(uint32_t Space);
675-
};
676-
677-
private:
678-
BindingSpaces SRVSpaces, UAVSpaces, CBufferSpaces, SamplerSpaces;
679-
bool ImplicitBinding;
680-
bool OverlappingBinding;
638+
hlsl::BindingInfo Bindings;
639+
bool HasImplicitBinding = false;
640+
bool HasOverlappingBinding = false;
681641

682642
// Populate the resource binding info given explicit resource binding calls
683643
// in the module.
684644
void populate(Module &M, DXILResourceTypeMap &DRTM);
685645

686646
public:
687-
DXILResourceBindingInfo()
688-
: SRVSpaces(dxil::ResourceClass::SRV),
689-
UAVSpaces(dxil::ResourceClass::UAV),
690-
CBufferSpaces(dxil::ResourceClass::CBuffer),
691-
SamplerSpaces(dxil::ResourceClass::Sampler), ImplicitBinding(false),
692-
OverlappingBinding(false) {}
693-
694-
bool hasImplicitBinding() const { return ImplicitBinding; }
695-
void setHasImplicitBinding(bool Value) { ImplicitBinding = Value; }
696-
bool hasOverlappingBinding() const { return OverlappingBinding; }
697-
698-
BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) {
699-
switch (RC) {
700-
case dxil::ResourceClass::SRV:
701-
return SRVSpaces;
702-
case dxil::ResourceClass::UAV:
703-
return UAVSpaces;
704-
case dxil::ResourceClass::CBuffer:
705-
return CBufferSpaces;
706-
case dxil::ResourceClass::Sampler:
707-
return SamplerSpaces;
708-
}
647+
bool hasImplicitBinding() const { return HasImplicitBinding; }
648+
void setHasImplicitBinding(bool Value) { HasImplicitBinding = Value; }
649+
bool hasOverlappingBinding() const { return HasOverlappingBinding; }
650+
void setHasOverlappingBinding(bool Value) { HasOverlappingBinding = Value; }
709651

710-
llvm_unreachable("Invalid resource class");
711-
}
712-
713-
// Size == -1 means unbounded array
714652
LLVM_ABI std::optional<uint32_t>
715-
findAvailableBinding(dxil::ResourceClass RC, uint32_t Space, int32_t Size);
653+
findAvailableBinding(dxil::ResourceClass RC, uint32_t Space, int32_t Size) {
654+
return Bindings.findAvailableBinding(RC, Space, Size);
655+
}
716656

717657
friend class DXILResourceBindingAnalysis;
718658
friend class DXILResourceBindingWrapperPass;
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//===- HLSLBinding.h - Representation for resource bindings in HLSL -------===//
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 This file contains objects to represent resource bindings.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_FRONTEND_HLSL_HLSLBINDING_H
14+
#define LLVM_FRONTEND_HLSL_HLSLBINDING_H
15+
16+
#include "llvm/ADT/STLFunctionalExtras.h"
17+
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/Support/DXILABI.h"
19+
#include "llvm/Support/ErrorHandling.h"
20+
21+
namespace llvm {
22+
namespace hlsl {
23+
24+
/// BindingInfo represents the ranges of bindings and free space for each
25+
/// `dxil::ResourceClass`. This can represent HLSL-level bindings as well as
26+
/// bindings described in root signatures, and can be used for analysis of
27+
/// overlapping or missing bindings as well as for finding space for implicit
28+
/// bindings.
29+
///
30+
/// As an example, given these resource bindings:
31+
///
32+
/// RWBuffer<float> A[10] : register(u3);
33+
/// RWBuffer<float> B[] : register(u5, space2)
34+
///
35+
/// The binding info for UAV bindings should look like this:
36+
///
37+
/// UAVSpaces {
38+
/// ResClass = ResourceClass::UAV,
39+
/// Spaces = {
40+
/// { Space = 0, FreeRanges = {{ 0, 2 }, { 13, UINT32_MAX }} },
41+
/// { Space = 2, FreeRanges = {{ 0, 4 }} }
42+
/// }
43+
/// }
44+
class BindingInfo {
45+
public:
46+
struct BindingRange {
47+
uint32_t LowerBound;
48+
uint32_t UpperBound;
49+
BindingRange(uint32_t LB, uint32_t UB) : LowerBound(LB), UpperBound(UB) {}
50+
};
51+
52+
struct RegisterSpace {
53+
uint32_t Space;
54+
SmallVector<BindingRange> FreeRanges;
55+
RegisterSpace(uint32_t Space) : Space(Space) {
56+
FreeRanges.emplace_back(0, UINT32_MAX);
57+
}
58+
// Size == -1 means unbounded array
59+
LLVM_ABI std::optional<uint32_t> findAvailableBinding(int32_t Size);
60+
};
61+
62+
struct BindingSpaces {
63+
dxil::ResourceClass RC;
64+
llvm::SmallVector<RegisterSpace> Spaces;
65+
BindingSpaces(dxil::ResourceClass RC) : RC(RC) {}
66+
LLVM_ABI RegisterSpace &getOrInsertSpace(uint32_t Space);
67+
};
68+
69+
private:
70+
BindingSpaces SRVSpaces{dxil::ResourceClass::SRV};
71+
BindingSpaces UAVSpaces{dxil::ResourceClass::UAV};
72+
BindingSpaces CBufferSpaces{dxil::ResourceClass::CBuffer};
73+
BindingSpaces SamplerSpaces{dxil::ResourceClass::Sampler};
74+
75+
public:
76+
BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) {
77+
switch (RC) {
78+
case dxil::ResourceClass::SRV:
79+
return SRVSpaces;
80+
case dxil::ResourceClass::UAV:
81+
return UAVSpaces;
82+
case dxil::ResourceClass::CBuffer:
83+
return CBufferSpaces;
84+
case dxil::ResourceClass::Sampler:
85+
return SamplerSpaces;
86+
}
87+
88+
llvm_unreachable("Invalid resource class");
89+
}
90+
const BindingSpaces &getBindingSpaces(dxil::ResourceClass RC) const {
91+
return const_cast<BindingInfo *>(this)->getBindingSpaces(RC);
92+
}
93+
94+
// Size == -1 means unbounded array
95+
LLVM_ABI std::optional<uint32_t>
96+
findAvailableBinding(dxil::ResourceClass RC, uint32_t Space, int32_t Size);
97+
98+
friend class BindingInfoBuilder;
99+
};
100+
101+
/// Builder class for creating a /c BindingInfo.
102+
class BindingInfoBuilder {
103+
public:
104+
struct Binding {
105+
dxil::ResourceClass RC;
106+
uint32_t Space;
107+
uint32_t LowerBound;
108+
uint32_t UpperBound;
109+
const void *Cookie;
110+
111+
Binding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound,
112+
uint32_t UpperBound, const void *Cookie)
113+
: RC(RC), Space(Space), LowerBound(LowerBound), UpperBound(UpperBound),
114+
Cookie(Cookie) {}
115+
116+
bool isUnbounded() const { return UpperBound == ~0U; }
117+
118+
bool operator==(const Binding &RHS) const {
119+
return std::tie(RC, Space, LowerBound, UpperBound, Cookie) ==
120+
std::tie(RHS.RC, RHS.Space, RHS.LowerBound, RHS.UpperBound,
121+
RHS.Cookie);
122+
}
123+
bool operator!=(const Binding &RHS) const { return !(*this == RHS); }
124+
125+
bool operator<(const Binding &RHS) const {
126+
return std::tie(RC, Space, LowerBound) <
127+
std::tie(RHS.RC, RHS.Space, RHS.LowerBound);
128+
}
129+
};
130+
131+
private:
132+
SmallVector<Binding> Bindings;
133+
134+
public:
135+
void trackBinding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound,
136+
uint32_t UpperBound, const void *Cookie) {
137+
Bindings.emplace_back(RC, Space, LowerBound, UpperBound, Cookie);
138+
}
139+
/// Calculate the binding info - \c ReportOverlap will be called once for each
140+
/// overlapping binding.
141+
BindingInfo calculateBindingInfo(
142+
llvm::function_ref<void(const BindingInfoBuilder &Builder,
143+
const Binding &Overlapping)>
144+
ReportOverlap);
145+
146+
/// Calculate the binding info - \c HasOverlap will be set to indicate whether
147+
/// there are any overlapping bindings.
148+
BindingInfo calculateBindingInfo(bool &HasOverlap) {
149+
HasOverlap = false;
150+
return calculateBindingInfo(
151+
[&HasOverlap](auto, auto) { HasOverlap = true; });
152+
}
153+
154+
/// For use in the \c ReportOverlap callback of \c calculateBindingInfo -
155+
/// finds a binding that the \c ReportedBinding overlaps with.
156+
const Binding &findOverlapping(const Binding &ReportedBinding) const;
157+
};
158+
159+
} // namespace hlsl
160+
} // namespace llvm
161+
162+
#endif // LLVM_FRONTEND_HLSL_HLSLBINDING_H

llvm/lib/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ add_llvm_component_library(LLVMAnalysis
175175
LINK_COMPONENTS
176176
BinaryFormat
177177
Core
178+
FrontendHLSL
178179
Object
179180
ProfileData
180181
Support

0 commit comments

Comments
 (0)