Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b1e34ff
adding validaiton and tests
Aug 12, 2025
90c2578
fix?
Aug 12, 2025
6e20bdf
Merge branch 'users/joaosaffran/153276' into validation/root-flags
joaosaffran Aug 12, 2025
84a4c4b
format
Aug 12, 2025
4400e2e
format
Aug 12, 2025
eb425c5
making validation function according to spec
Aug 14, 2025
ffcff83
merge
Aug 15, 2025
51ff280
format
Aug 15, 2025
e5812ce
clean up
Aug 15, 2025
d186ebd
clean up
Aug 15, 2025
5c35c32
clean up
Aug 15, 2025
9c09f21
Merge branch 'validation/descriptor-tables' into validation/root-flags
joaosaffran Sep 15, 2025
9169be0
formatting
joaosaffran Sep 15, 2025
65089ce
clean up
joaosaffran Sep 15, 2025
5910271
clean up
joaosaffran Sep 15, 2025
311a2e5
clean up
joaosaffran Sep 15, 2025
901bd1d
clean up
joaosaffran Sep 15, 2025
aba77f9
fix test
joaosaffran Sep 15, 2025
22319f9
rename test
joaosaffran Sep 15, 2025
4c86232
rename test
joaosaffran Sep 15, 2025
6641d66
rename test
joaosaffran Sep 15, 2025
c9986ed
refactoring follow inbelic suggestion
joaosaffran Sep 15, 2025
a0916e1
formating
joaosaffran Sep 15, 2025
1f8e5b6
adding getEnvironmentDenyFlagMask
joaosaffran Sep 15, 2025
1c2a864
format
joaosaffran Sep 15, 2025
8cccaf3
making getEnvironmentDenyFlagMask return optional
joaosaffran Sep 17, 2025
b3bc8b8
renaming SRVorUAV flag
joaosaffran Sep 17, 2025
18f9e9c
Merge branch 'validation/descriptor-tables' into validation/root-flags
joaosaffran Sep 18, 2025
83ee5fe
addressing comments from bogner
joaosaffran Sep 24, 2025
fdcd3e3
removing consts
joaosaffran Sep 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 60 additions & 12 deletions llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,40 @@ tripleToVisibility(llvm::Triple::EnvironmentType ET) {
}
}

static void reportIfDeniedShaderStageAccess(Module &M, dxbc::RootFlags Flags,
dxbc::RootFlags Mask) {
if ((Flags & Mask) != Mask)
return;
Comment on lines +166 to +167
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this check here, because I think it simplifies the code. If this is not here, I need to make the same check in all statements of the switch with slightly different masks.


SmallString<128> Message;
raw_svector_ostream OS(Message);
OS << "Shader has root bindings but root signature uses a DENY flag to "
"disallow root binding access to the shader stage.";
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}

static dxbc::RootFlags
getEnvironmentDenyFlagMask(Triple::EnvironmentType ShaderProfile) {
switch (ShaderProfile) {
case Triple::Pixel:
return dxbc::RootFlags::DenyPixelShaderRootAccess;
case Triple::Vertex:
return dxbc::RootFlags::DenyVertexShaderRootAccess;
case Triple::Geometry:
return dxbc::RootFlags::DenyGeometryShaderRootAccess;
case Triple::Hull:
return dxbc::RootFlags::DenyHullShaderRootAccess;
case Triple::Domain:
return dxbc::RootFlags::DenyDomainShaderRootAccess;
case Triple::Mesh:
return dxbc::RootFlags::DenyMeshShaderRootAccess;
case Triple::Amplification:
return dxbc::RootFlags::DenyAmplificationShaderRootAccess;
default:
llvm_unreachable("Invalid triple to shader stage conversion");
}
}

static void validateRootSignature(Module &M,
const mcdxbc::RootSignatureDesc &RSD,
dxil::ModuleMetadataInfo &MMI,
Expand Down Expand Up @@ -225,7 +259,9 @@ static void validateRootSignature(Module &M,
Builder.findOverlapping(ReportedBinding);
reportOverlappingRegisters(M, ReportedBinding, Overlaping);
});

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is intentional, I think it improves readability.

const hlsl::BoundRegs &BoundRegs = Builder.takeBoundRegs();
bool HasBindings = false;
for (const ResourceInfo &RI : DRM) {
const ResourceInfo::ResourceBinding &Binding = RI.getBinding();
const dxil::ResourceTypeInfo &RTI = DRTM[RI.getHandleTy()];
Expand All @@ -236,21 +272,33 @@ static void validateRootSignature(Module &M,
BoundRegs.findBoundReg(RC, Binding.Space, Binding.LowerBound,
Binding.LowerBound + Binding.Size - 1);

if (Reg != nullptr) {
const auto *ParamInfo =
static_cast<const mcdxbc::RootParameterInfo *>(Reg->Cookie);
if (!Reg) {
reportRegNotBound(M, RC, Binding);
continue;
}

if (RC != ResourceClass::SRV && RC != ResourceClass::UAV)
continue;
const auto *ParamInfo =
static_cast<const mcdxbc::RootParameterInfo *>(Reg->Cookie);

const bool IsRootSRVOrUAV =
RC == ResourceClass::SRV || RC == ResourceClass::UAV;
const bool IsDescriptorTable =
ParamInfo->Type == dxbc::RootParameterType::DescriptorTable;
const bool IsRawOrStructuredBuffer =
RK != ResourceKind::RawBuffer && RK != ResourceKind::StructuredBuffer;
if (IsRootSRVOrUAV && !IsDescriptorTable && IsRawOrStructuredBuffer) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the !IsDescriptorTable needed? I would've assumed that IsRootSRVOrUAV would imply that.

Copy link
Contributor Author

@joaosaffran joaosaffran Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsRootSRVOrUAV only check if the resource being bound is SRV or UAV, is not checking what kind of resource is being bounded to. In this validation, you can bound to a DescriptorTable but not with a RootSRV or RootUAV.

Here is a godbolt link with this example:
https://hlsl.godbolt.org/z/WW4qTs4hf

reportInvalidHandleTyError(M, RC, Binding);
continue;
}

if (ParamInfo->Type == dxbc::RootParameterType::DescriptorTable)
continue;
HasBindings = true;
}

if (RK != ResourceKind::RawBuffer && RK != ResourceKind::StructuredBuffer)
reportInvalidHandleTyError(M, RC, Binding);
} else {
reportRegNotBound(M, RC, Binding);
}
if (HasBindings && MMI.ShaderProfile != Triple::Compute) {
const dxbc::RootFlags Flags = dxbc::RootFlags(RSD.Flags);
const dxbc::RootFlags Mask = getEnvironmentDenyFlagMask(MMI.ShaderProfile);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this do the right thing for Library shaders? What about the various raytracing profiles (RayGeneration, Intersection, AnyHit, etc)? Is there some reason we can't get here for those?


reportIfDeniedShaderStageAccess(M, Flags, Mask);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
; RUN: opt -S -passes='dxil-post-optimization-validation' %s
; This is a valid case where no resource is being used
target triple = "dxil-pc-shadermodel6.6-pixel"

define void @CSMain() #0 {
entry:
ret void
}
attributes #0 = { noinline nounwind "exp-shader"="cs" "hlsl.numthreads"="1,2,1" "hlsl.shader"="geometry" }

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3, !4}
!2 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4}
!3 = !{ !"RootFlags", i32 294 } ; 294 = deny_pixel/hull/vertex/amplification_shader_root_access
!4 = !{ !"RootSRV", i32 0, i32 1, i32 0, i32 0 }
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: not opt -S -passes='dxil-post-optimization-validation' %s 2>&1 | FileCheck %s
; CHECK: error: Shader has root bindings but root signature uses a DENY flag to disallow root binding access to the shader stage.
target triple = "dxil-pc-shadermodel6.6-pixel"

%__cblayout_CB = type <{ float }>

@CB.str = private unnamed_addr constant [3 x i8] c"CB\00", align 1

define void @CSMain() "hlsl.shader"="compute" {
entry:
%CB = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, ptr nonnull @CB.str)
ret void
}

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3}
!2 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4}
!3 = !{!"RootFlags", i32 294} ; 294 = deny_pixel/hull/vertex/amplification_shader_root_access
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
; RUN: not opt -S -passes='dxil-post-optimization-validation' %s 2>&1 | FileCheck %s

; CHECK: error: Shader has root bindings but root signature uses a DENY flag to disallow root binding access to the shader stage.
target triple = "dxil-pc-shadermodel6.6-pixel"

@SB.str = private unnamed_addr constant [3 x i8] c"SB\00", align 1

define void @CSMain() "hlsl.shader"="pixel" {
entry:
%SB = tail call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @SB.str)
ret void
}

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3}
!2 = !{!"DescriptorTable", i32 0, !4}
!4 = !{!"SRV", i32 1, i32 0, i32 0, i32 -1, i32 4}
!3 = !{!"RootFlags", i32 32} ; 32 = deny_pixel_shader_root_access
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
; RUN: not opt -S -passes='dxil-post-optimization-validation' %s 2>&1 | FileCheck %s

; CHECK: error: Shader has root bindings but root signature uses a DENY flag to disallow root binding access to the shader stage.
target triple = "dxil-pc-shadermodel6.6-pixel"

@SB.str = private unnamed_addr constant [3 x i8] c"SB\00", align 1

define void @CSMain() "hlsl.shader"="pixel" {
entry:
%SB = tail call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @SB.str)
ret void
}

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3}
!2 = !{!"RootSRV", i32 0, i32 0, i32 0, i32 4}
!3 = !{!"RootFlags", i32 32} ; 32 = deny_pixel_shader_root_access
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; RUN: opt -S -passes='dxil-post-optimization-validation' %s
; Valid scenario where shader stage is not blocked from accessing root bindings
target triple = "dxil-pc-shadermodel6.6-geometry"

%__cblayout_CB = type <{ float }>

@CB.str = private unnamed_addr constant [3 x i8] c"CB\00", align 1

define void @CSMain() "hlsl.shader"="geometry" {
entry:
%CB = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, ptr nonnull @CB.str)
ret void
}
attributes #0 = { noinline nounwind "exp-shader"="cs" "hlsl.numthreads"="1,2,1" "hlsl.shader"="geometry" }

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3}
!2 = !{ !"RootFlags", i32 294 } ; 294 = deny_pixel/hull/vertex/amplification_shader_root_access
!3 = !{ !"RootCBV", i32 0, i32 2, i32 0, i32 0 }
Loading