[llvm-branch-commits] [clang] [llvm] [DirectX] Validate if Textures/TypedBuffers are being bound in Root Signatures (PR #147573)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jul 8 13:52:02 PDT 2025
https://github.com/joaosaffran updated https://github.com/llvm/llvm-project/pull/147573
>From 01a558be2b36a6bb00e1027c4d042c7bacd4ed5a Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Mon, 7 Jul 2025 19:26:24 +0000
Subject: [PATCH 1/6] add validation
---
.../DXILPostOptimizationValidation.cpp | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index a52a04323514c..1a57cd56f8eef 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -18,6 +18,7 @@
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
+#include "llvm/Support/Casting.h"
#define DEBUG_TYPE "dxil-post-optimization-validation"
@@ -85,6 +86,16 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}
+static void reportTextureBoundInRs(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.";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static void reportRegNotBound(Module &M, Twine Type,
ResourceInfo::ResourceBinding Binding) {
SmallString<128> Message;
@@ -155,24 +166,40 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &CBuf : DRM.cbuffers()) {
ResourceInfo::ResourceBinding Binding = CBuf.getBinding();
+
+ if (auto *TB = dyn_cast<TextureExtType>(CBuf.getHandleTy()))
+ reportTextureBoundInRs(M, "cbuffer", Binding);
+
if (!Validation.checkCRegBinding(Binding))
reportRegNotBound(M, "cbuffer", Binding);
}
for (const ResourceInfo &SRV : DRM.srvs()) {
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
+
+ if (auto *TB = dyn_cast<TextureExtType>(SRV.getHandleTy()))
+ reportTextureBoundInRs(M, "srv", Binding);
+
if (!Validation.checkTRegBinding(Binding))
reportRegNotBound(M, "srv", Binding);
}
for (const ResourceInfo &UAV : DRM.uavs()) {
ResourceInfo::ResourceBinding Binding = UAV.getBinding();
+
+ if (auto *TB = dyn_cast<TextureExtType>(UAV.getHandleTy()))
+ reportTextureBoundInRs(M, "uav", Binding);
+
if (!Validation.checkURegBinding(Binding))
reportRegNotBound(M, "uav", Binding);
}
for (const ResourceInfo &Sampler : DRM.samplers()) {
ResourceInfo::ResourceBinding Binding = Sampler.getBinding();
+
+ if (auto *TB = dyn_cast<TextureExtType>(Sampler.getHandleTy()))
+ reportTextureBoundInRs(M, "sampler", Binding);
+
if (!Validation.checkSamplerBinding(Binding))
reportRegNotBound(M, "sampler", Binding);
}
>From 43eb04ecebd44ec86a688abc9f067db0dfce2620 Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Tue, 8 Jul 2025 02:01:02 +0000
Subject: [PATCH 2/6] adding validation
---
.../RootSignature-Validation-Textures.hlsl | 13 ++++++++
.../SemaHLSL/RootSignature-Validation.hlsl | 6 ++--
.../DXILPostOptimizationValidation.cpp | 33 ++++++++++---------
3 files changed, 34 insertions(+), 18 deletions(-)
create mode 100644 clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl
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/clang/test/SemaHLSL/RootSignature-Validation.hlsl b/clang/test/SemaHLSL/RootSignature-Validation.hlsl
index 5a7f5baf00619..c4ea897c6f490 100644
--- a/clang/test/SemaHLSL/RootSignature-Validation.hlsl
+++ b/clang/test/SemaHLSL/RootSignature-Validation.hlsl
@@ -16,11 +16,11 @@ cbuffer CB : register(b3, space1) {
StructuredBuffer<int> In : register(t0, space0);
RWStructuredBuffer<int> Out : register(u0);
-RWBuffer<float> UAV : register(u4294967294);
+RWStructuredBuffer<float> UAV : register(u4294967294);
-RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
+RWStructuredBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
-RWBuffer<float> UAV3 : register(space0);
+RWStructuredBuffer<float> UAV3 : register(space0);
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index 1a57cd56f8eef..13ac6a28d44f7 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -86,13 +86,14 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}
-static void reportTextureBoundInRs(Module &M, Twine Type,
- ResourceInfo::ResourceBinding Binding) {
+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.";
+ << " is bound to a texture or typed buffer.";
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}
@@ -167,9 +168,6 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &CBuf : DRM.cbuffers()) {
ResourceInfo::ResourceBinding Binding = CBuf.getBinding();
- if (auto *TB = dyn_cast<TextureExtType>(CBuf.getHandleTy()))
- reportTextureBoundInRs(M, "cbuffer", Binding);
-
if (!Validation.checkCRegBinding(Binding))
reportRegNotBound(M, "cbuffer", Binding);
}
@@ -177,29 +175,34 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &SRV : DRM.srvs()) {
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
- if (auto *TB = dyn_cast<TextureExtType>(SRV.getHandleTy()))
- reportTextureBoundInRs(M, "srv", Binding);
-
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 (auto *TB = dyn_cast<TextureExtType>(UAV.getHandleTy()))
- reportTextureBoundInRs(M, "uav", Binding);
-
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()) {
ResourceInfo::ResourceBinding Binding = Sampler.getBinding();
- if (auto *TB = dyn_cast<TextureExtType>(Sampler.getHandleTy()))
- reportTextureBoundInRs(M, "sampler", Binding);
-
if (!Validation.checkSamplerBinding(Binding))
reportRegNotBound(M, "sampler", Binding);
}
>From d7b4cf44541866a47160ac005e85223b3b7b076d Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Tue, 8 Jul 2025 17:06:19 +0000
Subject: [PATCH 3/6] format
---
llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index 13ac6a28d44f7..c34f31fbe35e5 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -18,7 +18,6 @@
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
-#include "llvm/Support/Casting.h"
#define DEBUG_TYPE "dxil-post-optimization-validation"
@@ -167,14 +166,12 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &CBuf : DRM.cbuffers()) {
ResourceInfo::ResourceBinding Binding = CBuf.getBinding();
-
if (!Validation.checkCRegBinding(Binding))
reportRegNotBound(M, "cbuffer", Binding);
}
for (const ResourceInfo &SRV : DRM.srvs()) {
ResourceInfo::ResourceBinding Binding = SRV.getBinding();
-
if (!Validation.checkTRegBinding(Binding))
reportRegNotBound(M, "srv", Binding);
else {
@@ -188,7 +185,6 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &UAV : DRM.uavs()) {
ResourceInfo::ResourceBinding Binding = UAV.getBinding();
-
if (!Validation.checkURegBinding(Binding))
reportRegNotBound(M, "uav", Binding);
else {
@@ -202,7 +198,6 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
for (const ResourceInfo &Sampler : DRM.samplers()) {
ResourceInfo::ResourceBinding Binding = Sampler.getBinding();
-
if (!Validation.checkSamplerBinding(Binding))
reportRegNotBound(M, "sampler", Binding);
}
>From c7d5be77bd7c5421aca2e105dbab84854e335703 Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Tue, 8 Jul 2025 17:18:15 +0000
Subject: [PATCH 4/6] format
---
llvm/lib/Target/DirectX/DXILRootSignature.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h
index e975ceb22ea54..41c63939f93a6 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.h
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.h
@@ -47,7 +47,7 @@ class RootSignatureBindingInfo {
RootSignatureBindingInfo() = default;
RootSignatureBindingInfo(
SmallDenseMap<const Function *, mcdxbc::RootSignatureDesc> Map)
- : FuncToRsMap(Map){};
+ : FuncToRsMap(Map) {};
iterator find(const Function *F) { return FuncToRsMap.find(F); }
>From cc5afaefcafe97e92547c42c43c8747c0c7981fe Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Tue, 8 Jul 2025 19:02:00 +0000
Subject: [PATCH 5/6] address changes
---
llvm/lib/Target/DirectX/DXILRootSignature.cpp | 12 ++++--------
llvm/lib/Target/DirectX/DXILRootSignature.h | 3 ---
2 files changed, 4 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
index 5a53ea8a3631b..3848ad63dc468 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp
@@ -556,10 +556,7 @@ AnalysisKey RootSignatureAnalysis::Key;
RootSignatureAnalysis::Result
RootSignatureAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
- if (!AnalysisResult)
- AnalysisResult = std::make_unique<RootSignatureBindingInfo>(
- RootSignatureBindingInfo(analyzeModule(M)));
- return *AnalysisResult;
+ return RootSignatureBindingInfo(analyzeModule(M));
}
//===----------------------------------------------------------------------===//
@@ -638,15 +635,14 @@ PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M,
//===----------------------------------------------------------------------===//
bool RootSignatureAnalysisWrapper::runOnModule(Module &M) {
- if (!FuncToRsMap)
- FuncToRsMap = std::make_unique<RootSignatureBindingInfo>(
- RootSignatureBindingInfo(analyzeModule(M)));
+ FuncToRsMap = std::make_unique<RootSignatureBindingInfo>(
+ RootSignatureBindingInfo(analyzeModule(M)));
return false;
}
void RootSignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
- AU.addRequired<DXILMetadataAnalysisWrapperPass>();
+ AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
}
char RootSignatureAnalysisWrapper::ID = 0;
diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h
index 41c63939f93a6..07dbd51bed391 100644
--- a/llvm/lib/Target/DirectX/DXILRootSignature.h
+++ b/llvm/lib/Target/DirectX/DXILRootSignature.h
@@ -73,9 +73,6 @@ class RootSignatureAnalysis : public AnalysisInfoMixin<RootSignatureAnalysis> {
using Result = RootSignatureBindingInfo;
Result run(Module &M, ModuleAnalysisManager &AM);
-
-private:
- std::unique_ptr<RootSignatureBindingInfo> AnalysisResult;
};
/// Wrapper pass for the legacy pass manager.
>From aea75dac9df35611a5e8d46be8091621985e8ca7 Mon Sep 17 00:00:00 2001
From: joaosaffran <joao.saffran at microsoft.com>
Date: Tue, 8 Jul 2025 20:51:49 +0000
Subject: [PATCH 6/6] fix test
---
.../rootsignature-validation-textures.ll | 87 +++++++++++++++++++
1 file changed, 87 insertions(+)
create mode 100644 llvm/test/CodeGen/DirectX/rootsignature-validation-textures.ll
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-textures.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-textures.ll
new file mode 100644
index 0000000000000..8c407fdd60205
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-textures.ll
@@ -0,0 +1,87 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1
+; CHECK: error: register srv (space=0, register=0) is bound to a texture or typed buffer.
+
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ---------
+; B texture f32 buf T0 t0 1
+; Out UAV struct r/w U0 u0 1
+;
+; ModuleID = '../clang/test/SemaHLSL/RootSignature-Validation-Textures.hlsl'
+target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
+target triple = "dxilv1.5-unknown-shadermodel6.5-compute"
+
+%"Buffer<float>" = type { float }
+%"RWStructuredBuffer<int32_t>" = type { i32 }
+
+ at .str = private unnamed_addr constant [4 x i8] c"Out\00", align 1
+ at .str.2 = private unnamed_addr constant [2 x i8] c"B\00", align 1
+ at B = external constant %"Buffer<float>"
+ at Out = external constant %"RWStructuredBuffer<int32_t>"
+
+; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
+define void @CSMain() local_unnamed_addr #0 {
+entry:
+ %0 = tail call target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+ %1 = tail call target("dx.TypedBuffer", float, 0, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_0_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false, ptr nonnull @.str.2)
+ %2 = call { float, i1 } @llvm.dx.resource.load.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0) %1, i32 0)
+ %3 = extractvalue { float, i1 } %2, 0
+ %conv.i = fptosi float %3 to i32
+ call void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer", i32, 1, 0) %0, i32 0, i32 0, i32 %conv.i)
+ ret void
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
+declare target("dx.RawBuffer", i32, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32, i32, i32, i32, i1, ptr) #1
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
+declare target("dx.TypedBuffer", float, 0, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_0_0_0t(i32, i32, i32, i32, i1, ptr) #1
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", i32, 1, 0), i32) #1
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0), i32) #1
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(read)
+declare { float, i1 } @llvm.dx.resource.load.typedbuffer.f32.tdx.TypedBuffer_f32_0_0_0t(target("dx.TypedBuffer", float, 0, 0, 0), i32) #2
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(write)
+declare void @llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer", i32, 1, 0), i32, i32, i32) #3
+
+attributes #0 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) "approx-func-fp-math"="true" "frame-pointer"="all" "hlsl.numthreads"="8,8,1" "hlsl.shader"="compute" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(none) }
+attributes #2 = { nocallback nofree nosync nounwind willreturn memory(read) }
+attributes #3 = { nocallback nofree nosync nounwind willreturn memory(write) }
+
+!dx.rootsignatures = !{!0}
+!llvm.module.flags = !{!4, !5}
+!dx.valver = !{!6}
+!llvm.ident = !{!7}
+!dx.shaderModel = !{!8}
+!dx.version = !{!9}
+!dx.resources = !{!10}
+!dx.entryPoints = !{!17}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2, !3}
+!2 = !{!"RootSRV", i32 0, i32 0, i32 0, i32 4}
+!3 = !{!"RootUAV", i32 0, i32 0, i32 0, i32 2}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"frame-pointer", i32 2}
+!6 = !{i32 1, i32 8}
+!7 = !{!"clang version 21.0.0git (https://github.com/joaosaffran/llvm-project.git c16f15b4cd469a3f6efc2e4b0e098190d7fd0787)"}
+!8 = !{!"cs", i32 6, i32 5}
+!9 = !{i32 1, i32 5}
+!10 = !{!11, !14, null, null}
+!11 = !{!12}
+!12 = !{i32 0, ptr @B, !"B", i32 0, i32 0, i32 1, i32 10, i32 0, !13}
+!13 = !{i32 0, i32 9}
+!14 = !{!15}
+!15 = !{i32 0, ptr @Out, !"Out", i32 0, i32 0, i32 1, i32 12, i1 false, i1 false, i1 false, !16}
+!16 = !{i32 1, i32 4}
+!17 = !{ptr @CSMain, !"CSMain", null, !10, !18}
+!18 = !{i32 0, i64 16, i32 4, !19}
+!19 = !{i32 8, i32 8, i32 1}
More information about the llvm-branch-commits
mailing list