Skip to content

[DirectX] Add Range Overlap validation #152229

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
14 changes: 14 additions & 0 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ class DXILResourceTypeMap;

namespace dxil {

inline StringRef getResourceClassName(ResourceClass RC) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't an appropriate place for this function - the enum is defined in Support/DXILABI.h and this is just an arbitrary user of that that happens to also be a dependency of where you're using this functionality. Also, it's not a "great" practice to have a bunch of string literals in an inline function in a header - these will end up as duplicate data in every translation unit and we have to rely on the linker to clean it all up later.

I guess it would probably be best to add a DXILABI.cpp in Support and out-of-line the resource class enum stringify-ing function there.

switch (RC) {
case ResourceClass::SRV:
return "SRV";
case ResourceClass::UAV:
return "UAV";
case ResourceClass::CBuffer:
return "CBuffer";
case ResourceClass::Sampler:
return "Sampler";
}
llvm_unreachable("Unhandled ResourceClass");
}

// Returns the resource name from dx_resource_handlefrombinding or
// dx_resource_handlefromimplicitbinding call
LLVM_ABI StringRef getResourceNameFromBindingCall(CallInst *CI);
Expand Down
14 changes: 0 additions & 14 deletions llvm/lib/Analysis/DXILResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@
using namespace llvm;
using namespace dxil;

static StringRef getResourceClassName(ResourceClass RC) {
switch (RC) {
case ResourceClass::SRV:
return "SRV";
case ResourceClass::UAV:
return "UAV";
case ResourceClass::CBuffer:
return "CBuffer";
case ResourceClass::Sampler:
return "Sampler";
}
llvm_unreachable("Unhandled ResourceClass");
}

static StringRef getResourceKindName(ResourceKind RK) {
switch (RK) {
case ResourceKind::Texture1D:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/DirectX/DXILOpLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "DXILOpLowering.h"
#include "DXILConstants.h"
#include "DXILOpBuilder.h"
#include "DXILRootSignature.h"
#include "DXILShaderFlags.h"
#include "DirectX.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -945,6 +946,7 @@ class DXILOpLoweringLegacy : public ModulePass {
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
AU.addPreserved<ShaderFlagsAnalysisWrapper>();
AU.addPreserved<RootSignatureAnalysisWrapper>();
Copy link
Contributor

Choose a reason for hiding this comment

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

We'll need to preserve the root signature analysis in the new-PM version of the pass as well (that is, in DXILOpLowering::run)

}
};
char DXILOpLoweringLegacy::ID = 0;
Expand Down
177 changes: 174 additions & 3 deletions llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "DXILPostOptimizationValidation.h"
#include "DXILRootSignature.h"
#include "DXILShaderFlags.h"
#include "DirectX.h"
#include "llvm/ADT/SmallString.h"
Expand All @@ -24,6 +25,35 @@ using namespace llvm;
using namespace llvm::dxil;

namespace {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is already there, but static functions don't need to be in an anonymous namespace (only classes and structs do). I guess we could remove this particular anonymous namespace completely.

static ResourceClass RangeToResourceClass(uint32_t RangeType) {
using namespace dxbc;
switch (static_cast<DescriptorRangeType>(RangeType)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's weird for this function to take a uint32_t, and this function isn't following llvm naming conventions. We can solve both of these by creating a strongly typed conversion function that can be overloaded, like static ResourceClass toResourceClass(dxbc::DescriptorRangeType).

case DescriptorRangeType::SRV:
return ResourceClass::SRV;
case DescriptorRangeType::UAV:
return ResourceClass::UAV;
case DescriptorRangeType::CBV:
return ResourceClass::CBuffer;
case DescriptorRangeType::Sampler:
return ResourceClass::Sampler;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You'll need an llvm_unreachable() outside of the switch block or MSVC will get upset that not all control paths return a value.


ResourceClass ParameterToResourceClass(uint32_t Type) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, toResourceClass(dxbc::RootParameterType) would be better.

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");
Copy link
Contributor

Choose a reason for hiding this comment

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

Better to explicitly have the case we're intentionally not handling and no default at all. I also think it would be a good idea to have a different messages for that case and for the fall through llvm_unreachable - in one case the value should be impossible but in the other we have a misuse of the API if we're passing in RootParameterType::DescriptorTable

}
}

static void reportInvalidDirection(Module &M, DXILResourceMap &DRM) {
for (const auto &UAV : DRM.uavs()) {
Expand Down Expand Up @@ -84,8 +114,122 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
}
}

static void reportOverlappingRegisters(
Module &M, const llvm::hlsl::BindingInfoBuilder::Binding &Reported,
const llvm::hlsl::BindingInfoBuilder::Binding &Overlaping) {
SmallString<128> Message;
raw_svector_ostream OS(Message);
OS << "register " << getResourceClassName(Reported.RC)
<< " (space=" << Reported.Space << ", register=" << Reported.LowerBound
<< ")" << " is overlapping with" << " register "
<< getResourceClassName(Overlaping.RC) << " (space=" << Overlaping.Space
<< ", register=" << Overlaping.LowerBound << ")"
<< ", verify your root signature definition.";

M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}

static dxbc::ShaderVisibility
tripleToVisibility(llvm::Triple::EnvironmentType ET) {
assert((ET == Triple::Pixel || ET == Triple::Vertex ||
ET == Triple::Geometry || ET == Triple::Hull ||
ET == Triple::Domain || ET == Triple::Mesh ||
ET == Triple::Compute) &&
"Invalid Triple to shader stage conversion");
Copy link
Contributor

Choose a reason for hiding this comment

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

This assert is redundant with the llvm_unreachable below.


switch (ET) {
case Triple::Pixel:
return dxbc::ShaderVisibility::Pixel;
case Triple::Vertex:
return dxbc::ShaderVisibility::Vertex;
case Triple::Geometry:
return dxbc::ShaderVisibility::Geometry;
case Triple::Hull:
return dxbc::ShaderVisibility::Hull;
case Triple::Domain:
return dxbc::ShaderVisibility::Domain;
case Triple::Mesh:
return dxbc::ShaderVisibility::Mesh;
case Triple::Compute:
return dxbc::ShaderVisibility::All;
default:
llvm_unreachable("Invalid triple to shader stage conversion");
}
}

static void trackRootSigDescBinding(hlsl::BindingInfoBuilder &Builder,
const mcdxbc::RootSignatureDesc &RSD,
dxbc::ShaderVisibility Visibility) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function name isn't very clear as to what this is doing. Would it be better in reportErrors to just call a validateRootSignature(...) function if the root signature exists and inline this logic, rather than splitting it between there and here?

for (size_t I = 0; I < RSD.ParametersContainer.size(); I++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems to me we could use the range-for here: for (const mcdxbc::RootParameterInfo &ParamInfo : RSD.ParametersContainer)

const auto &[Type, Loc] =
RSD.ParametersContainer.getTypeAndLocForParameter(I);

const auto &Header = RSD.ParametersContainer.getHeader(I);
if (Header.ShaderVisibility !=
llvm::to_underlying(dxbc::ShaderVisibility::All) &&
Header.ShaderVisibility != llvm::to_underlying(Visibility))
continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems backwards. We know we have a valid visibility here but it isn't the right type, we should convert it and compare against that:

    dxbc::ShaderVisibility ParamVisibility =
        static_cast<dxbc::ShaderVisibility>(ParamInfo.Header.ShaderVisibility);
    if (ParamVisibility != dxbc::ShaderVisibility::All &&
        ParamVisibility != Visibility)
      continue;


switch (Type) {
case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): {
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly here - Using the underlying type for the switch is needlessly confusing and defeats covered enum warnings. Why not:

    dxbc::RootParameterType ParamType =
        static_cast<dxbc::RootParameterType>(ParamInfo.Header.ParameterType);
    switch (ParamType) {
    case dxbc::RootParameterType::Constants32Bit: {
    // ...

dxbc::RTS0::v1::RootConstants Const =
RSD.ParametersContainer.getConstant(Loc);
Builder.trackBinding(dxil::ResourceClass::CBuffer, Const.RegisterSpace,
Const.ShaderRegister,
Const.ShaderRegister + Const.Num32BitValues, &Const);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Const.ShaderRegister + Const.Num32BitValues, &Const);
Const.ShaderRegister, &Const);

This is what we do in the frontend, and iirc, I did check the behaviour with DXC. In either case, can you double-check what the correct behaviour is. But I believe it will always have a size of 1.

Copy link
Contributor

Choose a reason for hiding this comment

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

&Const is a reference to a local here - this is undefined behaviour. If we need a cookie to deduplicate these bindings we'll need something that has a sufficient lifetime. Same with the following calls to trackBinding

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);
Builder.trackBinding(ParameterToResourceClass(Type), Desc.RegisterSpace,
Desc.ShaderRegister, Desc.ShaderRegister, &Desc);

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) {
Builder.trackBinding(RangeToResourceClass(Range.RangeType),
Range.RegisterSpace, Range.BaseShaderRegister,
Range.NumDescriptors == ~0U
? Range.NumDescriptors
: Range.BaseShaderRegister +
Range.NumDescriptors,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
: Range.BaseShaderRegister +
Range.NumDescriptors,
: Range.BaseShaderRegister +
Range.NumDescriptors - 1,

I believe this is an inclusive range. We should add a test case for this case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably more readable to introduce a UpperBound variable rather than bury the ternary operator in the function call as well.

&Range);
}
break;
}
}
}

for (auto &S : RSD.StaticSamplers) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It's best to only use auto when the type is blatantly obvious like a cast, or sometimes in cases like iterators where the type name is long enough to obscure what's happening. Please spell out the type here. Also, should this be const?

Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace,
S.ShaderRegister, S.ShaderRegister, &S);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
for (auto &S : RSD.StaticSamplers) {
Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace,
S.ShaderRegister, S.ShaderRegister, &S);
}
for (auto &S : RSD.StaticSamplers)
Builder.trackBinding(dxil::ResourceClass::Sampler, S.RegisterSpace,
S.ShaderRegister, S.ShaderRegister, &S);

}

std::optional<mcdxbc::RootSignatureDesc>
getRootSignature(RootSignatureBindingInfo &RSBI,
dxil::ModuleMetadataInfo &MMI) {
if (MMI.EntryPropertyVec.size() == 0)
return std::nullopt;
std::optional<mcdxbc::RootSignatureDesc> RootSigDesc =
RSBI.getDescForFunction(MMI.EntryPropertyVec[0].Entry);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit surprised / worried that this API is returning a std::optional<mcdxbc::RootSignatureDesc> and not a std::optional<mcdxbc::RootSignatureDesc &> - the root signature description object doesn't look cheap to copy (it has multiple vectors in it!) and here we are copying it twice...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

std::optional don't seem to support reference, used a pointer instead.

if (!RootSigDesc)
return std::nullopt;
return RootSigDesc;
}

static void reportErrors(Module &M, DXILResourceMap &DRM,
DXILResourceBindingInfo &DRBI) {
DXILResourceBindingInfo &DRBI,
RootSignatureBindingInfo &RSBI,
dxil::ModuleMetadataInfo &MMI) {
if (DRM.hasInvalidCounterDirection())
reportInvalidDirection(M, DRM);

Expand All @@ -94,14 +238,31 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,

assert(!DRBI.hasImplicitBinding() && "implicit bindings should be handled in "
"DXILResourceImplicitBinding pass");

if (auto RSD = getRootSignature(RSBI, MMI)) {

hlsl::BindingInfoBuilder Builder;
dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile);
trackRootSigDescBinding(Builder, *RSD, Visibility);
hlsl::BindingInfo Info = Builder.calculateBindingInfo(
[&M](const llvm::hlsl::BindingInfoBuilder &Builder,
const llvm::hlsl::BindingInfoBuilder::Binding &ReportedBinding) {
const llvm::hlsl::BindingInfoBuilder::Binding &Overlaping =
Builder.findOverlapping(ReportedBinding);
reportOverlappingRegisters(M, ReportedBinding, Overlaping);
});
}
}
} // namespace

PreservedAnalyses
DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
DXILResourceBindingInfo &DRBI = MAM.getResult<DXILResourceBindingAnalysis>(M);
reportErrors(M, DRM, DRBI);
RootSignatureBindingInfo &RSBI = MAM.getResult<RootSignatureAnalysis>(M);
ModuleMetadataInfo &MMI = MAM.getResult<DXILMetadataAnalysis>(M);

reportErrors(M, DRM, DRBI, RSBI, MMI);
return PreservedAnalyses::all();
}

Expand All @@ -113,7 +274,12 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
getAnalysis<DXILResourceWrapperPass>().getResourceMap();
DXILResourceBindingInfo &DRBI =
getAnalysis<DXILResourceBindingWrapperPass>().getBindingInfo();
reportErrors(M, DRM, DRBI);
RootSignatureBindingInfo &RSBI =
getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
dxil::ModuleMetadataInfo &MMI =
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();

reportErrors(M, DRM, DRBI, RSBI, MMI);
return false;
}
StringRef getPassName() const override {
Expand All @@ -125,10 +291,13 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addRequired<DXILResourceWrapperPass>();
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addRequired<DXILMetadataAnalysisWrapperPass>();
AU.addRequired<RootSignatureAnalysisWrapper>();
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
AU.addPreserved<ShaderFlagsAnalysisWrapper>();
AU.addPreserved<RootSignatureAnalysisWrapper>();
}
};
char DXILPostOptimizationValidationLegacy::ID = 0;
Expand All @@ -139,6 +308,8 @@ INITIALIZE_PASS_BEGIN(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
INITIALIZE_PASS_DEPENDENCY(DXILResourceBindingWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
INITIALIZE_PASS_DEPENDENCY(RootSignatureAnalysisWrapper)
INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
"DXIL Post Optimization Validation", false, false)

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/DirectX/llc-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
; CHECK-NEXT: DXIL Module Metadata analysis
; CHECK-NEXT: DXIL Shader Flag Analysis
; CHECK-NEXT: DXIL Translate Metadata
; CHECK-NEXT: DXIL Root Signature Analysis
; CHECK-NEXT: DXIL Post Optimization Validation
; CHECK-NEXT: DXIL Op Lowering
; CHECK-NEXT: DXIL Root Signature Analysis
; CHECK-NEXT: DXIL Prepare Module

; CHECK-ASM-NEXT: DXIL Metadata Pretty Printer
Expand Down
22 changes: 22 additions & 0 deletions llvm/test/CodeGen/DirectX/rootsignature-validation-constants.ll
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this really adds much value by itself, maybe we can move it to the rootsignature-validation.ll to show it doesn't overlap with a CBV range there.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1
; expected-no-diagnostics
; Root Signature(RootConstants(num32BitConstants=4, b2))

%__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:
; cbuffer CB : register(b2, space0) {
; float a;
; }
%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, i1 false, ptr nonnull @CB.str)
ret void
}

!dx.rootsignatures = !{!0}

!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2}
!2 = !{!"RootConstants", i32 0, i32 2, i32 0, i32 4}
Original file line number Diff line number Diff line change
@@ -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=2) is overlapping with register CBuffer (space=0, register=0), 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}
Original file line number Diff line number Diff line change
@@ -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=10, register=4294967295) is overlapping with register UAV (space=10, register=4294967295), 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 0, !3}
!3 = !{!"UAV", i32 -1, i32 -1, i32 10, i32 -1, i32 2}
!4 = !{!"DescriptorTable", i32 0, !5}
!5 = !{ !"UAV", i32 -1, i32 -1, i32 10, i32 5, i32 2 }
Original file line number Diff line number Diff line change
@@ -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=1, register=3) is overlapping with register UAV (space=1, register=0), verify your root signature definition.
Copy link
Contributor

Choose a reason for hiding this comment

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

This error message would seemingly indicate that they shouldn't have overlapped? Maybe something like:
resource UAV(space=1, registers=[3,3]) is overlapping with resource UAV (space=1,registers=[0,3]), ...?


define void @CSMain() "hlsl.shader"="compute" {
entry:
ret void
}

; DescriptorTable(UAV(u0, numDescriptors=unbounded), visibility = SHADER_VISIBILITY_HULL), UAV(u3, space=1)
!dx.rootsignatures = !{!0}
!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !4}
!2 = !{!"RootUAV", i32 0, i32 3, i32 1, i32 4}
!4 = !{!"DescriptorTable", i32 0, !5}
!5 = !{!"UAV", i32 3, i32 0, i32 1, i32 -1, i32 2}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
; 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
}

!dx.rootsignatures = !{!0}
!0 = !{ptr @CSMain, !1, i32 2}
!1 = !{!2, !3}
!2 = !{ !"StaticSampler", i32 5, i32 4, i32 5, i32 3, float 0x3FF7CCCCC0000000, i32 10, i32 2, i32 1, float -1.270000e+02, float 1.220000e+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 }
Loading