- Notifications
You must be signed in to change notification settings - Fork14.5k
[DirectX] Add Range Overlap validation toDXILPostOptimizationValidation.cpp
#148919
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 ourterms of service andprivacy 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] Add Range Overlap validation toDXILPostOptimizationValidation.cpp
#148919
Uh oh!
There was an error while loading.Please reload this page.
Conversation
@llvm/pr-subscribers-backend-directx Author: None (joaosaffran) ChangesAccording to Root Signature spec, we need to validate if ranges defined in root signature are overlapping. This PR adds such check. Full diff:https://github.com/llvm/llvm-project/pull/148919.diff 3 Files Affected:
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cppindex f95a1d5913fd9..f22ae36df98b8 100644--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp@@ -15,6 +15,7 @@ #include "llvm/Analysis/DXILMetadataAnalysis.h" #include "llvm/Analysis/DXILResource.h" #include "llvm/BinaryFormat/DXContainer.h"+#include "llvm/Frontend/HLSL/RootSignatureValidations.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicsDirectX.h"@@ -227,6 +228,139 @@ getRootSignature(RootSignatureBindingInfo &RSBI, return RootSigDesc; }+static void+reportOverlappingRegisters(Module &M,+ llvm::hlsl::rootsig::OverlappingRanges Overlap) {+ const llvm::hlsl::rootsig::RangeInfo *Info = Overlap.A;+ const llvm::hlsl::rootsig::RangeInfo *OInfo = Overlap.B;+ SmallString<128> Message;+ raw_svector_ostream OS(Message);+ auto ResourceClassToString =+ [](llvm::dxil::ResourceClass Class) -> const char * {+ switch (Class) {++ case ResourceClass::SRV:+ return "SRV";+ case ResourceClass::UAV:+ return "UAV";+ case ResourceClass::CBuffer:+ return "CBuffer";+ case ResourceClass::Sampler:+ return "Sampler";+ break;+ }+ };+ OS << "register " << ResourceClassToString(Info->Class)+ << " (space=" << Info->Space << ", register=" << Info->LowerBound << ")"+ << " is overlapping with"+ << " register " << ResourceClassToString(OInfo->Class)+ << " (space=" << OInfo->Space << ", register=" << OInfo->LowerBound << ")"+ << ", verify your root signature definition";++ M.getContext().diagnose(DiagnosticInfoGeneric(Message));+}++static bool reportOverlappingRanges(Module &M,+ const mcdxbc::RootSignatureDesc &RSD) {+ using namespace llvm::hlsl::rootsig;++ llvm::SmallVector<RangeInfo> Infos;+ // Helper to map DescriptorRangeType to ResourceClass+ auto RangeToResourceClass = [](uint32_t RangeType) -> ResourceClass {+ using namespace dxbc;+ switch (static_cast<DescriptorRangeType>(RangeType)) {+ case DescriptorRangeType::SRV:+ return ResourceClass::SRV;+ case DescriptorRangeType::UAV:+ return ResourceClass::UAV;+ case DescriptorRangeType::CBV:+ return ResourceClass::CBuffer;+ case DescriptorRangeType::Sampler:+ return ResourceClass::Sampler;+ }+ };++ // Helper to map RootParameterType to ResourceClass+ auto ParameterToResourceClass = [](uint32_t Type) -> ResourceClass {+ using namespace dxbc;+ switch (Type) {+ case llvm::to_underlying(RootParameterType::Constants32Bit):+ return ResourceClass::CBuffer;+ case llvm::to_underlying(RootParameterType::SRV):+ return ResourceClass::SRV;+ case llvm::to_underlying(RootParameterType::UAV):+ return ResourceClass::UAV;+ case llvm::to_underlying(RootParameterType::CBV):+ return ResourceClass::CBuffer;+ default:+ llvm_unreachable("Unknown RootParameterType");+ }+ };++ for (size_t I = 0; I < RSD.ParametersContainer.size(); I++) {+ const auto &[Type, Loc] =+ RSD.ParametersContainer.getTypeAndLocForParameter(I);+ const auto &Header = RSD.ParametersContainer.getHeader(I);+ switch (Type) {+ case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): {+ dxbc::RTS0::v1::RootConstants Const =+ RSD.ParametersContainer.getConstant(Loc);++ RangeInfo Info;+ Info.Space = Const.RegisterSpace;+ Info.LowerBound = Const.ShaderRegister;+ Info.UpperBound = Info.LowerBound;+ Info.Class = ParameterToResourceClass(Type);+ Info.Visibility = (dxbc::ShaderVisibility)Header.ShaderVisibility;++ Infos.push_back(Info);+ break;+ }+ case llvm::to_underlying(dxbc::RootParameterType::SRV):+ case llvm::to_underlying(dxbc::RootParameterType::UAV):+ case llvm::to_underlying(dxbc::RootParameterType::CBV): {+ dxbc::RTS0::v2::RootDescriptor Desc =+ RSD.ParametersContainer.getRootDescriptor(Loc);++ RangeInfo Info;+ Info.Space = Desc.RegisterSpace;+ Info.LowerBound = Desc.ShaderRegister;+ Info.UpperBound = Info.LowerBound;+ Info.Class = ParameterToResourceClass(Type);+ Info.Visibility = (dxbc::ShaderVisibility)Header.ShaderVisibility;++ Infos.push_back(Info);+ 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) {+ RangeInfo Info;+ Info.Space = Range.RegisterSpace;+ Info.LowerBound = Range.BaseShaderRegister;+ Info.UpperBound = Info.LowerBound + ((Range.NumDescriptors == ~0U)+ ? Range.NumDescriptors+ : Range.NumDescriptors - 1);+ Info.Visibility = (dxbc::ShaderVisibility)Header.ShaderVisibility;+ Info.Class = RangeToResourceClass(Range.RangeType);++ Infos.push_back(Info);+ }+ break;+ }+ }+ }++ llvm::SmallVector<OverlappingRanges> Overlaps =+ llvm::hlsl::rootsig::findOverlappingRanges(Infos);+ for (OverlappingRanges Overlap : Overlaps)+ reportOverlappingRegisters(M, Overlap);++ return Overlaps.size() > 0;+}+ static void reportInvalidRegistersBinding( Module &M, const llvm::ArrayRef<llvm::dxil::ResourceInfo::ResourceBinding> &Bindings,@@ -272,21 +406,25 @@ static void reportErrors(Module &M, DXILResourceMap &DRM, if (auto RSD = getRootSignature(RSBI, MMI)) {- RootSignatureBindingValidation Validation =- initRSBindingValidation(*RSD, tripleToVisibility(MMI.ShaderProfile));-- reportInvalidRegistersBinding(- M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::CBV),- DRM.cbuffers());- reportInvalidRegistersBinding(- M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::UAV),- DRM.uavs());- reportInvalidRegistersBinding(- M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::Sampler),- DRM.samplers());- reportInvalidRegistersBinding(- M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::SRV),- DRM.srvs());+ if (!reportOverlappingRanges(M, *RSD)) {+ // Those checks require that no range is overlapping to provide correct+ // diagnostic.+ RootSignatureBindingValidation Validation =+ initRSBindingValidation(*RSD, tripleToVisibility(MMI.ShaderProfile));++ reportInvalidRegistersBinding(+ M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::CBV),+ DRM.cbuffers());+ reportInvalidRegistersBinding(+ M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::UAV),+ DRM.uavs());+ reportInvalidRegistersBinding(+ M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::Sampler),+ DRM.samplers());+ reportInvalidRegistersBinding(+ M, Validation.getBindingsOfType(dxbc::DescriptorRangeType::SRV),+ DRM.srvs());+ } } } } // namespacediff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.llnew file mode 100644index 0000000000000..431ec577efc5f--- /dev/null+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll@@ -0,0 +1,15 @@+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s+; CHECK: error: register CBuffer (space=0, register=0) is overlapping with register CBuffer (space=0, register=2), verify your root signature definition++define void @CSMain() "hlsl.shader"="compute" {+entry:+ ret void+}++; RootConstants(num32BitConstants=4, b2), DescriptorTable(CBV(b10, numDescriptors=3))+!dx.rootsignatures = !{!0}+!0 = !{ptr @CSMain, !1, i32 2}+!1 = !{!2, !3}+!2 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4}+!3 = !{!"DescriptorTable", i32 0, !4}+!4 = !{!"CBV", i32 3, i32 0, i32 0, i32 -1, i32 4}diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-overlap-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-overlap-range.llnew file mode 100644index 0000000000000..17b22b62ff8f5--- /dev/null+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-overlap-range.ll@@ -0,0 +1,16 @@+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s+; CHECK: error: register UAV (space=0, register=2) is overlapping with register UAV (space=0, register=0), verify your root signature definition++define void @CSMain() "hlsl.shader"="compute" {+entry:+ ret void+}++; DescriptorTable(UAV(u0, numDescriptors=unbounded), visibility = SHADER_VISIBILITY_HULL), DescriptorTable(UAV(u2, numDescriptors=4))+!dx.rootsignatures = !{!0}+!0 = !{ptr @CSMain, !1, i32 2}+!1 = !{!2, !4}+!2 = !{!"DescriptorTable", i32 2, !3}+!3 = !{!"UAV", i32 -1, i32 0, i32 0, i32 -1, i32 2}+!4 = !{!"DescriptorTable", i32 0, !5}+!5 = !{!"UAV", i32 4, i32 2, i32 0, i32 -1, i32 2} |
…dation/overlapping-ranges
…dation/overlapping-ranges
reportInvalidHandleTy(M, DRM.srvs()); | ||
reportInvalidHandleTy(M, DRM.uavs()); | ||
reportInvalidHandleTy(M, DRM.samplers()); | ||
if (!reportOverlappingRanges(M, *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.
if (!reportOverlappingRanges(M, *RSD)) { | |
if (reportOverlappingRanges(M, *RSD)) | |
return; |
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.
Can we add a test for when there are multiple overlaps. Just to make sure multiple diagnostics are being generated.
for (const dxbc::RTS0::v2::DescriptorRange &Range : Table.Ranges) { | ||
RangeInfo Info; | ||
Info.Space = Range.RegisterSpace; | ||
Info.LowerBound = Range.BaseShaderRegister; |
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 assumeRange.NumDescriptors > 0
will have been checked before here. Might be nice to add an assert in any case
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 see your test case for UAV, and if I understand correctly, the second test file you added might be testing the Constants32Bit.
Is there an existing test for the Descriptor table overlapping case?
reportInvalidHandleTy(M, DRM.srvs()); | ||
reportInvalidHandleTy(M, DRM.uavs()); | ||
reportInvalidHandleTy(M, DRM.samplers()); | ||
if (!reportOverlappingRanges(M, *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.
Why do the subsequent checks depend on this condition? Is it possible to report this and then unconditionally report the rest of the possible errors?
? Range.NumDescriptors | ||
: Range.NumDescriptors - 1); | ||
Info.Visibility = (dxbc::ShaderVisibility)Header.ShaderVisibility; | ||
Info.Class = RangeToResourceClass(Range.RangeType); |
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.
Nit: it looks like class should be assigned before visibility for consistency
<< " is overlapping with" | ||
<< " register " << ResourceClassToString(OInfo->Class) | ||
<< " (space=" << OInfo->Space << ", register=" << OInfo->LowerBound << ")" | ||
<< ", verify your root signature definition"; |
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.
Nit: you might reference other diagnostics, but I think diagnostics should end with punctuation
@@ -13,7 +13,7 @@ | |||
definevoid@CSMain()"hlsl.shader"="compute" { | |||
entry: | |||
%TB =tailcalltarget("dx.Texture",float,1,0,0)@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i320,i320,i321,i320,i1false,ptrnonnull@TB.str) | |||
%TB =tailcalltarget("dx.TypedBuffer",float,1,0,0)@llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i320,i320,i321,i320,i1false,ptrnonnull@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.
Why did this change?
ret void | ||
} | ||
; RootConstants(num32BitConstants=4, b2), DescriptorTable(CBV(b10, numDescriptors=3)) |
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.
Is this comment correct? I don't see the conflict that is happening based on this root signature
Uh oh!
There was an error while loading.Please reload this page.
According to Root Signature spec, we need to validate if ranges defined in root signature are overlapping. This PR adds such check.
Closes:#126645