From 01a558be2b36a6bb00e1027c4d042c7bacd4ed5a Mon Sep 17 00:00:00 2001 From: joaosaffran 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(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(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(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(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 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 Out : register(u0); +Buffer 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 In : register(t0, space0); RWStructuredBuffer Out : register(u0); -RWBuffer UAV : register(u4294967294); +RWStructuredBuffer UAV : register(u4294967294); -RWBuffer UAV1 : register(u2), UAV2 : register(u4); +RWStructuredBuffer UAV1 : register(u2), UAV2 : register(u4); -RWBuffer UAV3 : register(space0); +RWStructuredBuffer 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(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(SRV.getHandleTy())) - reportTextureBoundInRs(M, "srv", Binding); - if (!Validation.checkTRegBinding(Binding)) reportRegNotBound(M, "srv", Binding); + else { + const auto *Handle = + dyn_cast_or_null(SRV.getHandleTy()); + + if (!Handle) + reportInvalidHandleTyBoundInRs(M, "srv", Binding); + } } for (const ResourceInfo &UAV : DRM.uavs()) { ResourceInfo::ResourceBinding Binding = UAV.getBinding(); - if (auto *TB = dyn_cast(UAV.getHandleTy())) - reportTextureBoundInRs(M, "uav", Binding); - if (!Validation.checkURegBinding(Binding)) reportRegNotBound(M, "uav", Binding); + else { + const auto *Handle = + dyn_cast_or_null(UAV.getHandleTy()); + + if (!Handle) + reportInvalidHandleTyBoundInRs(M, "srv", Binding); + } } for (const ResourceInfo &Sampler : DRM.samplers()) { ResourceInfo::ResourceBinding Binding = Sampler.getBinding(); - if (auto *TB = dyn_cast(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 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 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 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 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(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(analyzeModule(M))); + FuncToRsMap = std::make_unique( + RootSignatureBindingInfo(analyzeModule(M))); return false; } void RootSignatureAnalysisWrapper::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); - AU.addRequired(); + AU.addPreserved(); } 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 { using Result = RootSignatureBindingInfo; Result run(Module &M, ModuleAnalysisManager &AM); - -private: - std::unique_ptr AnalysisResult; }; /// Wrapper pass for the legacy pass manager. From aea75dac9df35611a5e8d46be8091621985e8ca7 Mon Sep 17 00:00:00 2001 From: joaosaffran 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" = type { float } +%"RWStructuredBuffer" = type { i32 } + +@.str = private unnamed_addr constant [4 x i8] c"Out\00", align 1 +@.str.2 = private unnamed_addr constant [2 x i8] c"B\00", align 1 +@B = external constant %"Buffer" +@Out = external constant %"RWStructuredBuffer" + +; 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}