-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[DirectX] Adding missing descriptor table validations #153276
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/147573
Are you sure you want to change the base?
[DirectX] Adding missing descriptor table validations #153276
Conversation
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-backend-directx Author: None (joaosaffran) ChangesThis patch adds 2 small validation to DirectX backend. First, it checks if registers in descriptor tables are not overflowing, meaning they don't try to bind registers over the maximum allowed value; second, it checks if samplers are being mixed with other resource types. Full diff: https://github.com/llvm/llvm-project/pull/153276.diff 4 Files Affected:
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index abcefe287d9bc..7067d6a2960e8 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -155,6 +155,31 @@ reportRegNotBound(Module &M, ResourceClass Class,
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}
+static void
+reportDescriptorTableMixingTypes(Module &M, uint32_t Location,
+ dxbc::DescriptorRangeType RangeType) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << "Samplers cannot be mixed with other "
+ << "resource types in a descriptor table, "
+ << getResourceClassName(toResourceClass(RangeType))
+ << "(location=" << Location << ")";
+
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
+static void reportOverlowingRange(Module &M, const dxbc::RTS0::v2::DescriptorRange &Range) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << "Cannot append range with implicit lower "
+ << "bound after an unbounded range "
+ << getResourceClassName(toResourceClass(static_cast<dxbc::DescriptorRangeType>(Range.RangeType)))
+ << "(register=" << Range.BaseShaderRegister << ", space=" <<
+ Range.RegisterSpace
+ << ") exceeds maximum allowed value.";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static void reportInvalidHandleTy(
Module &M, const llvm::ArrayRef<dxil::ResourceInfo::ResourceBinding> &RDs,
const iterator_range<SmallVectorImpl<dxil::ResourceInfo>::iterator>
@@ -236,10 +261,73 @@ getRootDescriptorsBindingInfo(const mcdxbc::RootSignatureDesc &RSD,
return RDs;
}
-static void validateRootSignature(Module &M,
- const mcdxbc::RootSignatureDesc &RSD,
- dxil::ModuleMetadataInfo &MMI,
- DXILResourceMap &DRM) {
+
+
+static void validateDescriptorTables(Module &M,
+ const mcdxbc::RootSignatureDesc &RSD,
+ dxil::ModuleMetadataInfo &MMI,
+ DXILResourceMap &DRM) {
+ for (const mcdxbc::RootParameterInfo &ParamInfo : RSD.ParametersContainer) {
+ if (static_cast<dxbc::RootParameterType>(ParamInfo.Header.ParameterType) !=
+ dxbc::RootParameterType::DescriptorTable)
+ continue;
+
+ mcdxbc::DescriptorTable Table =
+ RSD.ParametersContainer.getDescriptorTable(ParamInfo.Location);
+
+ bool HasSampler = false;
+ bool HasOtherRangeType = false;
+ dxbc::DescriptorRangeType OtherRangeType;
+ uint32_t OtherRangeTypeLocation = 0;
+
+ uint64_t AppendingOffset = 0;
+
+
+ for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) {
+ dxbc::DescriptorRangeType RangeType =
+ static_cast<dxbc::DescriptorRangeType>(Range.RangeType);
+
+ uint64_t Offset = AppendingOffset;
+ if(Range.OffsetInDescriptorsFromTableStart != ~0U)
+ Offset = Range.OffsetInDescriptorsFromTableStart;
+
+ if(Offset > ~0U)
+ reportOverlowingRange(M, Range);
+ if(Range.NumDescriptors == ~0U) {
+ AppendingOffset = (uint64_t)~0U + (uint64_t)1ULL;
+ } else {
+ uint64_t UpperBound = (uint64_t)Range.BaseShaderRegister + (uint64_t)Range.NumDescriptors - (uint64_t)1U;
+ if(UpperBound > ~0U)
+ reportOverlowingRange(M, Range);
+
+ uint64_t AppendingUpperBound = (uint64_t)Offset + (uint64_t)Range.NumDescriptors - (uint64_t)1U;
+ if(AppendingUpperBound > ~0U)
+ reportOverlowingRange(M, Range);
+ AppendingOffset = Offset + Range.NumDescriptors;
+ }
+
+ if (RangeType == dxbc::DescriptorRangeType::Sampler) {
+ HasSampler = true;
+ } else {
+ HasOtherRangeType = true;
+ OtherRangeType = RangeType;
+ OtherRangeTypeLocation = ParamInfo.Location;
+ }
+ }
+
+ // Samplers cannot be mixed with other resources in a descriptor table.
+ if (HasSampler && HasOtherRangeType) {
+ reportDescriptorTableMixingTypes(M, OtherRangeTypeLocation,
+ OtherRangeType);
+ continue;
+ }
+ }
+}
+
+static void validateRootSignatureBindings(Module &M,
+ const mcdxbc::RootSignatureDesc &RSD,
+ dxil::ModuleMetadataInfo &MMI,
+ DXILResourceMap &DRM) {
hlsl::BindingInfoBuilder Builder;
dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile);
@@ -309,7 +397,6 @@ static void validateRootSignature(Module &M,
reportOverlappingRegisters(M, ReportedBinding, Overlaping);
});
// Next checks require that the root signature definition is valid.
- // Next checks require that the root signature definition is valid.
if (!HasOverlap) {
SmallVector<ResourceInfo::ResourceBinding> RDs =
getRootDescriptorsBindingInfo(RSD, Visibility);
@@ -351,8 +438,10 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
"DXILResourceImplicitBinding pass");
- if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI))
- validateRootSignature(M, *RSD, MMI, DRM);
+ if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI)) {
+ validateRootSignatureBindings(M, *RSD, MMI, DRM);
+ validateDescriptorTables(M, *RSD, MMI, DRM);
+ }
}
PreservedAnalyses
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-appending-overflow.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-appending-overflow.ll
new file mode 100644
index 0000000000000..865312a43b5a8
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-appending-overflow.ll
@@ -0,0 +1,18 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: Cannot append range with implicit lower bound after an unbounded range UAV(register=3, space=4) exceeds maximum allowed value.
+
+@TB.str = private unnamed_addr constant [3 x i8] c"TB\00", align 1
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!3}
+!3 = !{!"DescriptorTable", i32 0, !4, !5}
+!4 = !{!"UAV", i32 -1, i32 1, i32 2, i32 -1, i32 0}
+!5 = !{!"UAV", i32 1, i32 3, i32 4, i32 -1, i32 0}
+
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-register-overflow.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-register-overflow.ll
new file mode 100644
index 0000000000000..ef887baf80728
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-register-overflow.ll
@@ -0,0 +1,17 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: Cannot append range with implicit lower bound after an unbounded range UAV(register=4294967295, space=0) exceeds maximum allowed value.
+
+@TB.str = private unnamed_addr constant [3 x i8] c"TB\00", align 1
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!3}
+!3 = !{!"DescriptorTable", i32 0, !4}
+!4 = !{!"UAV", i32 100, i32 4294967295, i32 0, i32 -1, i32 0}
+
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-mix.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-mix.ll
new file mode 100644
index 0000000000000..d4caeb2675d82
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-mix.ll
@@ -0,0 +1,18 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: Samplers cannot be mixed with other resource types in a descriptor table, UAV(location=0)
+
+@TB.str = private unnamed_addr constant [3 x i8] c"TB\00", align 1
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!3}
+!3 = !{!"DescriptorTable", i32 0, !4, !5}
+!4 = !{!"UAV", i32 1, i32 0, i32 0, i32 -1, i32 0}
+!5 = !{!"Sampler", i32 2, i32 0, i32 0, i32 -1, i32 0}
+
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
@@ -0,0 +1,17 @@ | |||
; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s | |||
; CHECK: error: Cannot append range with implicit lower bound after an unbounded range UAV(register=4294967295, space=0) exceeds maximum allowed value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message is incorrect, this case does have an explicit binding
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is the same error message as DXC. It has nothing to do with implicit binding. It means that you cannot bind if the lower bound is, implicit, exceeding the maximum allowed value. This happens when you append a range after an unbounded range.
Thant being said, I change the error message to fix this confusion.
static void validateDescriptorTables(Module &M, | ||
const mcdxbc::RootSignatureDesc &RSD) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static void validateDescriptorTables(Module &M, | |
const mcdxbc::RootSignatureDesc &RSD) { | |
static void validateDescriptorTable(Module &M, | |
const mcdxbc::DescriptorTable &Table) { |
Does it make more sense to call validateDescriptorTable
when we encounter a descriptor table while iterating in validateRootSignature
?
// Samplers cannot be mixed with other resources in a descriptor table. | ||
if (HasSampler && HasOtherRangeType) { | ||
reportDescriptorTableMixingTypes(M, OtherRangeTypeLocation, | ||
OtherRangeType); | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Samplers cannot be mixed with other resources in a descriptor table. | |
if (HasSampler && HasOtherRangeType) { | |
reportDescriptorTableMixingTypes(M, OtherRangeTypeLocation, | |
OtherRangeType); | |
continue; | |
} | |
// Samplers cannot be mixed with other resources in a descriptor table. | |
if (HasSampler && HasOtherRangeType) | |
reportDescriptorTableMixingTypes(M, OtherRangeTypeLocation, | |
OtherRangeType); |
dxbc::DescriptorRangeType RangeType = | ||
static_cast<dxbc::DescriptorRangeType>(Range.RangeType); | ||
|
||
uint64_t Offset = AppendingOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am having a really hard time trying to figure what it happening here to validate it is correct. Can you add some comments to describe how this checks for an overflow
Given we want to use these for the frontend as well. Would it be possible to do these validations with an |
This patch adds 2 small validation to DirectX backend. First, it checks if registers in descriptor tables are not overflowing, meaning they don't try to bind registers over the maximum allowed value; second, it checks if samplers are being mixed with other resource types.
Closes: #153057, #153058