-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[DirectX] Validate registers are bound to root signature #146785
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
base: users/joaosaffran/152229
Are you sure you want to change the base?
Changes from 2 commits
0e8828c
2edd215
242545e
3f8dec4
3b1ce3b
f5720af
ea54904
a49aa19
d90676f
a04eb9f
5994b8f
e8b14bf
8f40e83
28350b2
4fd2e0b
e25ee87
881dd36
8779ee9
c16f15b
c7d5be7
cc5afae
571a0ef
974d4bc
e0bc862
b5a0b32
00a74af
5ccb842
5423aba
a7637a7
da42c0c
edb015d
9f3888e
578a03b
b4a0e16
ef14638
662c3a8
260633c
d42f156
9ee3a4b
6db6224
04658b8
adf3feb
fc338b5
f5b5b3e
03d571a
ef51048
21675e6
47662f0
6da5fb0
0c72dcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
|
||
#include "llvm/Frontend/HLSL/HLSLBinding.h" | ||
#include "llvm/ADT/STLExtras.h" | ||
#include <cstdint> | ||
|
||
using namespace llvm; | ||
using namespace hlsl; | ||
|
@@ -66,6 +67,22 @@ BindingInfo::RegisterSpace::findAvailableBinding(int32_t Size) { | |
return std::nullopt; | ||
} | ||
|
||
bool BindingInfo::RegisterSpace::isBound(BindingRange B) { | ||
for (BindingRange &R : FreeRanges) { | ||
if (B.LowerBound >= R.LowerBound && B.LowerBound < R.UpperBound && | ||
B.UpperBound > R.LowerBound && B.UpperBound <= R.UpperBound) | ||
return false; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can take advantage of |
||
return true; | ||
} | ||
|
||
bool BindingInfo::isBound(dxil::ResourceClass RC, uint32_t Space, | ||
BindingRange B) { | ||
BindingSpaces &BS = getBindingSpaces(RC); | ||
RegisterSpace &RS = BS.getOrInsertSpace(Space); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it worth it to add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
return RS.isBound(B); | ||
} | ||
|
||
BindingInfo BindingInfoBuilder::calculateBindingInfo( | ||
llvm::function_ref<void(const BindingInfoBuilder &Builder, | ||
const Binding &Overlapping)> | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -14,12 +14,16 @@ | |||||||||||||
#include "llvm/ADT/StringRef.h" | ||||||||||||||
#include "llvm/Analysis/DXILMetadataAnalysis.h" | ||||||||||||||
#include "llvm/Analysis/DXILResource.h" | ||||||||||||||
#include "llvm/BinaryFormat/DXContainer.h" | ||||||||||||||
#include "llvm/Frontend/HLSL/HLSLBinding.h" | ||||||||||||||
#include "llvm/Frontend/HLSL/RootSignatureValidations.h" | ||||||||||||||
#include "llvm/IR/DiagnosticInfo.h" | ||||||||||||||
#include "llvm/IR/Instructions.h" | ||||||||||||||
#include "llvm/IR/IntrinsicsDirectX.h" | ||||||||||||||
#include "llvm/IR/Module.h" | ||||||||||||||
#include "llvm/InitializePasses.h" | ||||||||||||||
#include "llvm/Support/DXILABI.h" | ||||||||||||||
#include <utility> | ||||||||||||||
|
||||||||||||||
#define DEBUG_TYPE "dxil-post-optimization-validation" | ||||||||||||||
|
||||||||||||||
|
@@ -116,11 +120,12 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
static void reportRegNotBound(Module &M, | ||||||||||||||
llvm::hlsl::rootsig::RangeInfo Unbound) { | ||||||||||||||
static void | ||||||||||||||
reportRegNotBound(Module &M, ResourceClass Class, | ||||||||||||||
llvm::dxil::ResourceInfo::ResourceBinding Unbound) { | ||||||||||||||
SmallString<128> Message; | ||||||||||||||
raw_svector_ostream OS(Message); | ||||||||||||||
OS << "register " << getResourceClassName(Unbound.Class) | ||||||||||||||
OS << "register " << getResourceClassName(Class) | ||||||||||||||
<< " (space=" << Unbound.Space << ", register=" << Unbound.LowerBound | ||||||||||||||
<< ")" | ||||||||||||||
<< " does not have a binding in the Root Signature"; | ||||||||||||||
|
@@ -155,12 +160,9 @@ tripleToVisibility(llvm::Triple::EnvironmentType ET) { | |||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
static hlsl::rootsig::RootSignatureBindingValidation | ||||||||||||||
initRSBindingValidation(const mcdxbc::RootSignatureDesc &RSD, | ||||||||||||||
dxbc::ShaderVisibility Visibility) { | ||||||||||||||
|
||||||||||||||
hlsl::rootsig::RootSignatureBindingValidation Validation; | ||||||||||||||
|
||||||||||||||
static void trackRootSigDescBinding(hlsl::BindingInfoBuilder &Builder, | ||||||||||||||
const mcdxbc::RootSignatureDesc &RSD, | ||||||||||||||
dxbc::ShaderVisibility Visibility) { | ||||||||||||||
for (size_t I = 0; I < RSD.ParametersContainer.size(); I++) { | ||||||||||||||
const auto &[Type, Loc] = | ||||||||||||||
RSD.ParametersContainer.getTypeAndLocForParameter(I); | ||||||||||||||
|
@@ -175,15 +177,10 @@ initRSBindingValidation(const mcdxbc::RootSignatureDesc &RSD, | |||||||||||||
case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was originally a design decision. The decision was made to avoid converting uint_32t to enum in obj2yaml/yaml2obj and when reading and writing root signature to/from the binary format. This simplified the code at the time. |
||||||||||||||
dxbc::RTS0::v1::RootConstants Const = | ||||||||||||||
RSD.ParametersContainer.getConstant(Loc); | ||||||||||||||
|
||||||||||||||
hlsl::rootsig::RangeInfo Binding; | ||||||||||||||
Binding.LowerBound = Const.ShaderRegister; | ||||||||||||||
Binding.Space = Const.RegisterSpace; | ||||||||||||||
Binding.UpperBound = Binding.LowerBound; | ||||||||||||||
|
||||||||||||||
// Root Constants Bind to CBuffers | ||||||||||||||
Validation.addBinding(ResourceClass::CBuffer, Binding); | ||||||||||||||
|
||||||||||||||
Builder.trackBinding(dxil::ResourceClass::CBuffer, Const.RegisterSpace, | ||||||||||||||
Const.ShaderRegister, | ||||||||||||||
Const.ShaderRegister + Const.Num32BitValues, | ||||||||||||||
nullptr); | ||||||||||||||
break; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
|
@@ -192,32 +189,25 @@ initRSBindingValidation(const mcdxbc::RootSignatureDesc &RSD, | |||||||||||||
case llvm::to_underlying(dxbc::RootParameterType::CBV): { | ||||||||||||||
dxbc::RTS0::v2::RootDescriptor Desc = | ||||||||||||||
RSD.ParametersContainer.getRootDescriptor(Loc); | ||||||||||||||
Builder.trackBinding(ParameterToResourceClass(Type), Desc.RegisterSpace, | ||||||||||||||
Desc.ShaderRegister, Desc.ShaderRegister, nullptr); | ||||||||||||||
|
||||||||||||||
hlsl::rootsig::RangeInfo Binding; | ||||||||||||||
Binding.LowerBound = Desc.ShaderRegister; | ||||||||||||||
Binding.Space = Desc.RegisterSpace; | ||||||||||||||
Binding.UpperBound = Binding.LowerBound; | ||||||||||||||
|
||||||||||||||
Validation.addBinding(ParameterToResourceClass(Type), Binding); | ||||||||||||||
break; | ||||||||||||||
} | ||||||||||||||
case llvm::to_underlying(dxbc::RootParameterType::DescriptorTable): { | ||||||||||||||
const mcdxbc::DescriptorTable &Table = | ||||||||||||||
RSD.ParametersContainer.getDescriptorTable(Loc); | ||||||||||||||
|
||||||||||||||
for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) { | ||||||||||||||
hlsl::rootsig::RangeInfo Binding; | ||||||||||||||
Binding.LowerBound = Range.BaseShaderRegister; | ||||||||||||||
Binding.Space = Range.RegisterSpace; | ||||||||||||||
Binding.UpperBound = Binding.LowerBound + Range.NumDescriptors - 1; | ||||||||||||||
Validation.addBinding(RangeToResourceClass(Range.RangeType), Binding); | ||||||||||||||
Builder.trackBinding(RangeToResourceClass(Range.RangeType), | ||||||||||||||
Range.RegisterSpace, Range.BaseShaderRegister, | ||||||||||||||
Range.BaseShaderRegister + Range.NumDescriptors, | ||||||||||||||
nullptr); | ||||||||||||||
} | ||||||||||||||
break; | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
return Validation; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
std::optional<mcdxbc::RootSignatureDesc> | ||||||||||||||
|
@@ -232,30 +222,6 @@ getRootSignature(RootSignatureBindingInfo &RSBI, | |||||||||||||
return RootSigDesc; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
static void reportUnboundRegisters( | ||||||||||||||
Module &M, | ||||||||||||||
const llvm::hlsl::rootsig::RootSignatureBindingValidation &Validation, | ||||||||||||||
ResourceClass Class, | ||||||||||||||
const iterator_range<SmallVectorImpl<dxil::ResourceInfo>::iterator> | ||||||||||||||
&Resources) { | ||||||||||||||
SmallVector<hlsl::rootsig::RangeInfo> Ranges; | ||||||||||||||
for (auto Res = Resources.begin(), End = Resources.end(); Res != End; Res++) { | ||||||||||||||
ResourceInfo::ResourceBinding ResBinding = Res->getBinding(); | ||||||||||||||
hlsl::rootsig::RangeInfo Range; | ||||||||||||||
Range.Space = ResBinding.Space; | ||||||||||||||
Range.LowerBound = ResBinding.LowerBound; | ||||||||||||||
Range.UpperBound = Range.LowerBound + ResBinding.Size - 1; | ||||||||||||||
Range.Class = Class; | ||||||||||||||
Ranges.push_back(Range); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
SmallVector<hlsl::rootsig::RangeInfo> Unbounds = | ||||||||||||||
hlsl::rootsig::findUnboundRanges(Ranges, | ||||||||||||||
Validation.getBindingsOfType(Class)); | ||||||||||||||
for (const auto &Unbound : Unbounds) | ||||||||||||||
reportRegNotBound(M, Unbound); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
static void reportErrors(Module &M, DXILResourceMap &DRM, | ||||||||||||||
DXILResourceBindingInfo &DRBI, | ||||||||||||||
RootSignatureBindingInfo &RSBI, | ||||||||||||||
|
@@ -271,15 +237,29 @@ static void reportErrors(Module &M, DXILResourceMap &DRM, | |||||||||||||
|
||||||||||||||
if (auto RSD = getRootSignature(RSBI, MMI)) { | ||||||||||||||
|
||||||||||||||
llvm::hlsl::rootsig::RootSignatureBindingValidation Validation = | ||||||||||||||
initRSBindingValidation(*RSD, tripleToVisibility(MMI.ShaderProfile)); | ||||||||||||||
|
||||||||||||||
reportUnboundRegisters(M, Validation, ResourceClass::CBuffer, | ||||||||||||||
DRM.cbuffers()); | ||||||||||||||
reportUnboundRegisters(M, Validation, ResourceClass::UAV, DRM.uavs()); | ||||||||||||||
reportUnboundRegisters(M, Validation, ResourceClass::Sampler, | ||||||||||||||
DRM.samplers()); | ||||||||||||||
reportUnboundRegisters(M, Validation, ResourceClass::SRV, DRM.srvs()); | ||||||||||||||
hlsl::BindingInfoBuilder Builder; | ||||||||||||||
dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile); | ||||||||||||||
trackRootSigDescBinding(Builder, *RSD, Visibility); | ||||||||||||||
|
||||||||||||||
bool HasOverlap; | ||||||||||||||
hlsl::BindingInfo Info = Builder.calculateBindingInfo(HasOverlap); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't seem to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is another PR that takes care of checking if there are overlapping ranges. The original implementation that order made sense, now, I might need to change the PRs orders, will fix that today. |
||||||||||||||
|
||||||||||||||
for (const auto &ResList : | ||||||||||||||
{std::make_pair(ResourceClass::SRV, DRM.srvs()), | ||||||||||||||
std::make_pair(ResourceClass::UAV, DRM.uavs()), | ||||||||||||||
std::make_pair(ResourceClass::CBuffer, DRM.cbuffers()), | ||||||||||||||
std::make_pair(ResourceClass::Sampler, DRM.samplers())}) { | ||||||||||||||
for (auto Res : ResList.second) { | ||||||||||||||
llvm::dxil::ResourceInfo::ResourceBinding ResBinding = Res.getBinding(); | ||||||||||||||
llvm::hlsl::BindingInfo::BindingRange ResRange( | ||||||||||||||
ResBinding.LowerBound, ResBinding.LowerBound + ResBinding.Size); | ||||||||||||||
|
||||||||||||||
auto IsBound = Info.isBound(ResList.first, ResBinding.Space, ResRange); | ||||||||||||||
if (!IsBound) { | ||||||||||||||
reportRegNotBound(M, ResList.first, ResBinding); | ||||||||||||||
} | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Suggested change
|
||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} // namespace | ||||||||||||||
|
Uh oh!
There was an error while loading. Please reload this page.