-
Notifications
You must be signed in to change notification settings - Fork 15k
[DirectX] Validate if Textures/TypedBuffers are being bound in Root Signatures #147573
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
[DirectX] Validate if Textures/TypedBuffers are being bound in Root Signatures #147573
Conversation
…idation/check-descriptors-are-bound
…/textures-not-bind-root-signatures
@llvm/pr-subscribers-hlsl Author: None (joaosaffran) ChangesDXC doesn't allow Textures/TypedBuffers to bind with root signature descriptors, this implements the same check in clang. Closes: #126647 Full diff: https://github.com/llvm/llvm-project/pull/147573.diff 2 Files Affected:
diff --git a/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
new file mode 100644
index 0000000000000..9daf38e30dd67
--- /dev/null
+++ b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
@@ -0,0 +1,13 @@
+// RUN: not %clang_dxc -T cs_6_6 -E CSMain %s 2>&1 | FileCheck %s
+
+// CHECK: error: register srv (space=0, register=0) is bound to a texture or typed buffer.
+
+RWStructuredBuffer<int> Out : register(u0);
+Buffer<float> B : register(t0);
+// Compute Shader for UAV testing
+[numthreads(8, 8, 1)]
+[RootSignature("SRV(t0), UAV(u0)")]
+void CSMain(uint id : SV_GroupID)
+{
+ Out[0] = B[0];
+}
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index a52a04323514c..c34f31fbe35e5 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -85,6 +85,17 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}
+static void
+reportInvalidHandleTyBoundInRs(Module &M, Twine Type,
+ ResourceInfo::ResourceBinding Binding) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << "register " << Type << " (space=" << Binding.Space
+ << ", register=" << Binding.LowerBound << ")"
+ << " is bound to a texture or typed buffer.";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static void reportRegNotBound(Module &M, Twine Type,
ResourceInfo::ResourceBinding Binding) {
SmallString<128> Message;
@@ -163,12 +174,26 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
if (!Validation.checkTRegBinding(Binding))
reportRegNotBound(M, "srv", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(SRV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &UAV : DRM.uavs()) {
ResourceInfo::ResourceBinding Binding = UAV.getBinding();
if (!Validation.checkURegBinding(Binding))
reportRegNotBound(M, "uav", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(UAV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &Sampler : DRM.samplers()) {
|
@llvm/pr-subscribers-backend-directx Author: None (joaosaffran) ChangesDXC doesn't allow Textures/TypedBuffers to bind with root signature descriptors, this implements the same check in clang. Closes: #126647 Full diff: https://github.com/llvm/llvm-project/pull/147573.diff 2 Files Affected:
diff --git a/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
new file mode 100644
index 0000000000000..9daf38e30dd67
--- /dev/null
+++ b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
@@ -0,0 +1,13 @@
+// RUN: not %clang_dxc -T cs_6_6 -E CSMain %s 2>&1 | FileCheck %s
+
+// CHECK: error: register srv (space=0, register=0) is bound to a texture or typed buffer.
+
+RWStructuredBuffer<int> Out : register(u0);
+Buffer<float> B : register(t0);
+// Compute Shader for UAV testing
+[numthreads(8, 8, 1)]
+[RootSignature("SRV(t0), UAV(u0)")]
+void CSMain(uint id : SV_GroupID)
+{
+ Out[0] = B[0];
+}
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index a52a04323514c..c34f31fbe35e5 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -85,6 +85,17 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}
+static void
+reportInvalidHandleTyBoundInRs(Module &M, Twine Type,
+ ResourceInfo::ResourceBinding Binding) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << "register " << Type << " (space=" << Binding.Space
+ << ", register=" << Binding.LowerBound << ")"
+ << " is bound to a texture or typed buffer.";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static void reportRegNotBound(Module &M, Twine Type,
ResourceInfo::ResourceBinding Binding) {
SmallString<128> Message;
@@ -163,12 +174,26 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
if (!Validation.checkTRegBinding(Binding))
reportRegNotBound(M, "srv", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(SRV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &UAV : DRM.uavs()) {
ResourceInfo::ResourceBinding Binding = UAV.getBinding();
if (!Validation.checkURegBinding(Binding))
reportRegNotBound(M, "uav", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(UAV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &Sampler : DRM.samplers()) {
|
@llvm/pr-subscribers-clang Author: None (joaosaffran) ChangesDXC doesn't allow Textures/TypedBuffers to bind with root signature descriptors, this implements the same check in clang. Closes: #126647 Full diff: https://github.com/llvm/llvm-project/pull/147573.diff 2 Files Affected:
diff --git a/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
new file mode 100644
index 0000000000000..9daf38e30dd67
--- /dev/null
+++ b/clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
@@ -0,0 +1,13 @@
+// RUN: not %clang_dxc -T cs_6_6 -E CSMain %s 2>&1 | FileCheck %s
+
+// CHECK: error: register srv (space=0, register=0) is bound to a texture or typed buffer.
+
+RWStructuredBuffer<int> Out : register(u0);
+Buffer<float> B : register(t0);
+// Compute Shader for UAV testing
+[numthreads(8, 8, 1)]
+[RootSignature("SRV(t0), UAV(u0)")]
+void CSMain(uint id : SV_GroupID)
+{
+ Out[0] = B[0];
+}
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index a52a04323514c..c34f31fbe35e5 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -85,6 +85,17 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}
+static void
+reportInvalidHandleTyBoundInRs(Module &M, Twine Type,
+ ResourceInfo::ResourceBinding Binding) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << "register " << Type << " (space=" << Binding.Space
+ << ", register=" << Binding.LowerBound << ")"
+ << " is bound to a texture or typed buffer.";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static void reportRegNotBound(Module &M, Twine Type,
ResourceInfo::ResourceBinding Binding) {
SmallString<128> Message;
@@ -163,12 +174,26 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
if (!Validation.checkTRegBinding(Binding))
reportRegNotBound(M, "srv", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(SRV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &UAV : DRM.uavs()) {
ResourceInfo::ResourceBinding Binding = UAV.getBinding();
if (!Validation.checkURegBinding(Binding))
reportRegNotBound(M, "uav", Binding);
+ else {
+ const auto *Handle =
+ dyn_cast_or_null<RawBufferExtType>(UAV.getHandleTy());
+
+ if (!Handle)
+ reportInvalidHandleTyBoundInRs(M, "srv", Binding);
+ }
}
for (const ResourceInfo &Sampler : DRM.samplers()) {
|
std::optional<const Binding *> findBoundReg(dxil::ResourceClass RC, | ||
uint32_t Space, | ||
uint32_t LowerBound, | ||
uint32_t UpperBound) const { |
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.
Formatting done to fit within 80 columns
StringRef RCName = getResourceClassName(RC); | ||
OS << RCName << " at register " << Binding.LowerBound << " and space " | ||
<< Binding.Space << " is bound to a texture or typed buffer. " << RCName | ||
<< " root descriptors can only be Raw or Structured buffers."; |
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.
Last sentence added to match DXC diagnostic message
const auto *ParamInfo = | ||
static_cast<const mcdxbc::RootParameterInfo *>((*Reg)->Cookie); | ||
|
||
if (RC != ResourceClass::SRV && RC != ResourceClass::UAV) | ||
continue; | ||
|
||
if (ParamInfo->Type == dxbc::RootParameterType::DescriptorTable) | ||
continue; | ||
|
||
if (RK != ResourceKind::RawBuffer && RK != ResourceKind::StructuredBuffer) | ||
reportInvalidHandleTyError(M, RC, 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.
Using continues
instead of long bool expression, as recommended in llvm coding guides: https://llvm.org/docs/CodingStandards.html#use-early-exits-and-continue-to-simplify-code
@@ -0,0 +1,17 @@ | |||
; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s | |||
; "This is a valid root signature with a texture/typed buffer resource" |
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 is using descriptor table instead of root descriptors, that is why it is allowed, as far as my understanding of DXC goes
@@ -0,0 +1,17 @@ | |||
; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | |||
; This is a valid root signature with a texture/typed buffer resource |
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.
Same as previous valid test
@@ -133,17 +133,21 @@ class BoundRegs { | |||
public: | |||
BoundRegs(SmallVector<Binding> &&Bindings) : Bindings(std::move(Bindings)) {} | |||
|
|||
bool isBound(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound, | |||
uint32_t UpperBound) const { | |||
std::optional<const Binding *> findBoundReg(dxil::ResourceClass RC, |
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.
std::optional<>
of a pointer type is weird - pointers are already nullable. Better to just return the pointer directly and use nullptr
for not found.
@@ -118,6 +118,17 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) { | |||
"true, yet no overlapping binding was found"); | |||
} | |||
|
|||
static void reportInvalidHandleTyError(Module &M, ResourceClass RC, | |||
ResourceInfo::ResourceBinding Binding) { | |||
SmallString<128> Message; |
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.
The message here is always longer than 128 characters, so this SmallString is never able to use its "small" storage. We should bump this to something like 160 and avoid an unnecessary heap allocation
|
||
define void @CSMain() "hlsl.shader"="compute" { | ||
entry: | ||
%TB = tail call target("dx.Texture", float, 1, 0, 0, 4) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @TB.str) |
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.
You can skip the overload type here and let the IR parser add it implicitly
%TB = tail call target("dx.Texture", float, 1, 0, 0, 4) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, ptr nonnull @TB.str) | |
%TB = tail call target("dx.Texture", float, 1, 0, 0, 4) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @TB.str) |
Similarly in the other tests.
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.
It might be better to name this test "valid" rather than "validation" like rootsignature-valid-textures.ll
. I think it's a bit clearer.
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.
Should rename this test to match the new name on rootsignature-valid-textures.ll
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.
Sorry, missed this one
…//github.com/joaosaffran/llvm-project into validation/textures-not-bind-root-signatures
DXC doesn't allow Textures/TypedBuffers to bind with root signature descriptors, this implements the same check.
Closes: #126647