diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp index a564f8f150ef9..85ce1a4d569d4 100644 --- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp +++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp @@ -15,12 +15,14 @@ #include "llvm/ADT/SmallString.h" #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" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/DXILABI.h" #define DEBUG_TYPE "dxil-post-optimization-validation" @@ -295,6 +297,105 @@ 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); + 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 Infos; + + 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) { + assert(Range.NumDescriptors > 0); + RangeInfo Info; + Info.Space = Range.RegisterSpace; + Info.LowerBound = Range.BaseShaderRegister; + Info.UpperBound = Info.LowerBound + ((Range.NumDescriptors == ~0U) + ? Range.NumDescriptors + : Range.NumDescriptors - 1); + Info.Class = RangeToResourceClass(Range.RangeType); + Info.Visibility = (dxbc::ShaderVisibility)Header.ShaderVisibility; + + Infos.push_back(Info); + } + break; + } + } + } + + for (const dxbc::RTS0::v1::StaticSampler &Sampler : RSD.StaticSamplers) { + RangeInfo Info; + Info.Space = Sampler.RegisterSpace; + Info.LowerBound = Sampler.ShaderRegister; + Info.UpperBound = Info.LowerBound; + Info.Class = ResourceClass::Sampler; + Info.Visibility = (dxbc::ShaderVisibility)Sampler.ShaderVisibility; + + Infos.push_back(Info); + } + + llvm::SmallVector Overlaps = + llvm::hlsl::rootsig::findOverlappingRanges(Infos); + for (OverlappingRanges Overlap : Overlaps) + reportOverlappingRegisters(M, Overlap); + + return Overlaps.size() > 0; +} + static void reportInvalidHandleTy( Module &M, const llvm::ArrayRef &RDs, const iterator_range::iterator> @@ -359,6 +460,8 @@ static void reportErrors(Module &M, DXILResourceMap &DRM, "DXILResourceImplicitBinding pass"); if (auto RSD = getRootSignature(RSBI, MMI)) { + if (reportOverlappingRanges(M, *RSD)) + return; dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile); llvm::hlsl::rootsig::RootSignatureBindingValidation Validation = initRSBindingValidation(*RSD, Visibility); diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbuffer-range.ll new file mode 100644 index 0000000000000..bcc05c61637ec --- /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(b0, 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-descriptor-table-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-descriptor-table-range.ll new file mode 100644 index 0000000000000..17b22b62ff8f5 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-descriptor-table-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} diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-range.ll new file mode 100644 index 0000000000000..79544a4fbbc7c --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-root-descriptor-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 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_ALL), UAV(u2, space=0, visibility=SHADER_VISIBILITY_ALL)) +!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 4} +!4 = !{!"RootUAV", i32 0, i32 2, i32 0, i32 4} diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll new file mode 100644 index 0000000000000..5574b64c015cc --- /dev/null +++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-static-sampler-range.ll @@ -0,0 +1,14 @@ +; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s +; CHECK: error: register Sampler (space=0, register=42) is overlapping with register Sampler (space=0, register=42), verify your root signature definition. + +define void @CSMain() "hlsl.shader"="compute" { +entry: + ret void +} + +; RootConstants(num32BitConstants=4, b2), DescriptorTable(CBV(b0, numDescriptors=3)) +!dx.rootsignatures = !{!0} +!0 = !{ptr @CSMain, !1, i32 2} +!1 = !{!2, !3} +!2 = !{ !"StaticSampler", i32 4, i32 2, i32 3, i32 5, float 0x3FF6CCCCC0000000, i32 9, i32 3, i32 2, float -1.280000e+02, float 1.280000e+02, i32 42, i32 0, i32 0 } +!3 = !{ !"StaticSampler", i32 4, i32 2, i32 3, i32 5, float 0x3FF6CCCCC0000000, i32 9, i32 3, i32 2, float -1.280000e+02, float 1.280000e+02, i32 42, i32 0, i32 0 }