[llvm] 36ebd17 - [DirectX] Validate registers are bound to root signature (#146785)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 28 14:10:15 PDT 2025
Author: joaosaffran
Date: 2025-08-28T17:10:10-04:00
New Revision: 36ebd1797203de0d38ccb5cacee39f1fec7a0c5a
URL: https://github.com/llvm/llvm-project/commit/36ebd1797203de0d38ccb5cacee39f1fec7a0c5a
DIFF: https://github.com/llvm/llvm-project/commit/36ebd1797203de0d38ccb5cacee39f1fec7a0c5a.diff
LOG: [DirectX] Validate registers are bound to root signature (#146785)
DXC checks if registers are correctly bound to root signature
descriptors. This implements the same check.
closes: #[126645](https://github.com/llvm/llvm-project/issues/126645)
---------
Co-authored-by: joaosaffran <joao.saffran at microsoft.com>
Co-authored-by: Joao Saffran <jderezende at microsoft.com>
Added:
llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits-upperbound.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbv-binding.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-fail-consecutive-ranges.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-binding.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-fail-srv-binding.ll
llvm/test/CodeGen/DirectX/rootsignature-validation-fail-uav-binding.ll
Modified:
clang/lib/Sema/SemaHLSL.cpp
llvm/include/llvm/Frontend/HLSL/HLSLBinding.h
llvm/lib/Frontend/HLSL/HLSLBinding.cpp
llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6a68fa2ed7a8b..1e5ec952c1ecf 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1159,15 +1159,14 @@ struct PerVisibilityBindingChecker {
bool HadOverlap = false;
using llvm::hlsl::BindingInfoBuilder;
- auto ReportOverlap = [this, &HadOverlap](
- const BindingInfoBuilder &Builder,
- const BindingInfoBuilder::Binding &Reported) {
+ auto ReportOverlap = [this,
+ &HadOverlap](const BindingInfoBuilder &Builder,
+ const llvm::hlsl::Binding &Reported) {
HadOverlap = true;
const auto *Elem =
static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie);
- const BindingInfoBuilder::Binding &Previous =
- Builder.findOverlapping(Reported);
+ const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported);
const auto *PrevElem =
static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie);
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLBinding.h b/llvm/include/llvm/Frontend/HLSL/HLSLBinding.h
index f4f46b35cf83d..5e0175a58e0fb 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLBinding.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLBinding.h
@@ -13,6 +13,7 @@
#ifndef LLVM_FRONTEND_HLSL_HLSLBINDING_H
#define LLVM_FRONTEND_HLSL_HLSLBINDING_H
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
@@ -99,36 +100,55 @@ class BindingInfo {
friend class BindingInfoBuilder;
};
-/// Builder class for creating a /c BindingInfo.
-class BindingInfoBuilder {
-public:
- struct Binding {
- dxil::ResourceClass RC;
- uint32_t Space;
- uint32_t LowerBound;
- uint32_t UpperBound;
- const void *Cookie;
+struct Binding {
+ dxil::ResourceClass RC;
+ uint32_t Space;
+ uint32_t LowerBound;
+ uint32_t UpperBound;
+ const void *Cookie;
- Binding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound,
- uint32_t UpperBound, const void *Cookie)
- : RC(RC), Space(Space), LowerBound(LowerBound), UpperBound(UpperBound),
- Cookie(Cookie) {}
+ Binding(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound,
+ uint32_t UpperBound, const void *Cookie)
+ : RC(RC), Space(Space), LowerBound(LowerBound), UpperBound(UpperBound),
+ Cookie(Cookie) {}
- bool isUnbounded() const { return UpperBound == ~0U; }
+ bool isUnbounded() const { return UpperBound == ~0U; }
- bool operator==(const Binding &RHS) const {
- return std::tie(RC, Space, LowerBound, UpperBound, Cookie) ==
- std::tie(RHS.RC, RHS.Space, RHS.LowerBound, RHS.UpperBound,
- RHS.Cookie);
- }
- bool operator!=(const Binding &RHS) const { return !(*this == RHS); }
+ bool operator==(const Binding &RHS) const {
+ return std::tie(RC, Space, LowerBound, UpperBound, Cookie) ==
+ std::tie(RHS.RC, RHS.Space, RHS.LowerBound, RHS.UpperBound,
+ RHS.Cookie);
+ }
+ bool operator!=(const Binding &RHS) const { return !(*this == RHS); }
- bool operator<(const Binding &RHS) const {
- return std::tie(RC, Space, LowerBound) <
- std::tie(RHS.RC, RHS.Space, RHS.LowerBound);
- }
- };
+ bool operator<(const Binding &RHS) const {
+ return std::tie(RC, Space, LowerBound) <
+ std::tie(RHS.RC, RHS.Space, RHS.LowerBound);
+ }
+};
+
+class BoundRegs {
+ SmallVector<Binding> Bindings;
+public:
+ BoundRegs(SmallVector<Binding> &&Bindings) : Bindings(std::move(Bindings)) {}
+
+ bool isBound(dxil::ResourceClass RC, uint32_t Space, uint32_t LowerBound,
+ uint32_t UpperBound) const {
+ // UpperBound and Cookie are given dummy values, since they aren't
+ // interesting for operator<
+ const Binding *It =
+ llvm::upper_bound(Bindings, Binding{RC, Space, LowerBound, 0, nullptr});
+ if (It == Bindings.begin())
+ return false;
+ --It;
+ return It->RC == RC && It->Space == Space && It->LowerBound <= LowerBound &&
+ It->UpperBound >= UpperBound;
+ }
+};
+
+/// Builder class for creating a /c BindingInfo.
+class BindingInfoBuilder {
private:
SmallVector<Binding> Bindings;
@@ -152,6 +172,12 @@ class BindingInfoBuilder {
[&HasOverlap](auto, auto) { HasOverlap = true; });
}
+ LLVM_ABI BoundRegs takeBoundRegs() {
+ assert(std::is_sorted(Bindings.begin(), Bindings.end()) &&
+ "takeBoundRegs should only be called after calculateBindingInfo");
+ return BoundRegs(std::move(Bindings));
+ }
+
/// For use in the \c ReportOverlap callback of \c calculateBindingInfo -
/// finds a binding that the \c ReportedBinding overlaps with.
LLVM_ABI const Binding &findOverlapping(const Binding &ReportedBinding) const;
diff --git a/llvm/lib/Frontend/HLSL/HLSLBinding.cpp b/llvm/lib/Frontend/HLSL/HLSLBinding.cpp
index 45391460354d0..401402fb5a7ba 100644
--- a/llvm/lib/Frontend/HLSL/HLSLBinding.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLBinding.cpp
@@ -131,9 +131,9 @@ BindingInfo BindingInfoBuilder::calculateBindingInfo(
return Info;
}
-const BindingInfoBuilder::Binding &BindingInfoBuilder::findOverlapping(
- const BindingInfoBuilder::Binding &ReportedBinding) const {
- for (const BindingInfoBuilder::Binding &Other : Bindings)
+const Binding &
+BindingInfoBuilder::findOverlapping(const Binding &ReportedBinding) const {
+ for (const Binding &Other : Bindings)
if (ReportedBinding.LowerBound <= Other.UpperBound &&
Other.LowerBound <= ReportedBinding.UpperBound)
return Other;
diff --git a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
index 9b41e28ab3e19..e2bc9be191fb9 100644
--- a/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
+++ b/llvm/lib/Target/DirectX/DXILPostOptimizationValidation.cpp
@@ -118,10 +118,8 @@ static void reportOverlappingBinding(Module &M, DXILResourceMap &DRM) {
"true, yet no overlapping binding was found");
}
-static void
-reportOverlappingRegisters(Module &M,
- const llvm::hlsl::BindingInfoBuilder::Binding &R1,
- const llvm::hlsl::BindingInfoBuilder::Binding &R2) {
+static void reportOverlappingRegisters(Module &M, const llvm::hlsl::Binding &R1,
+ const llvm::hlsl::Binding &R2) {
SmallString<128> Message;
raw_svector_ostream OS(Message);
@@ -133,6 +131,17 @@ reportOverlappingRegisters(Module &M,
M.getContext().diagnose(DiagnosticInfoGeneric(Message));
}
+static void
+reportRegNotBound(Module &M, ResourceClass Class,
+ const llvm::dxil::ResourceInfo::ResourceBinding &Unbound) {
+ SmallString<128> Message;
+ raw_svector_ostream OS(Message);
+ OS << getResourceClassName(Class) << " register " << Unbound.LowerBound
+ << " in space " << Unbound.Space
+ << " does not have a binding in the Root Signature";
+ M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+}
+
static dxbc::ShaderVisibility
tripleToVisibility(llvm::Triple::EnvironmentType ET) {
switch (ET) {
@@ -157,7 +166,9 @@ tripleToVisibility(llvm::Triple::EnvironmentType ET) {
static void validateRootSignature(Module &M,
const mcdxbc::RootSignatureDesc &RSD,
- dxil::ModuleMetadataInfo &MMI) {
+ dxil::ModuleMetadataInfo &MMI,
+ DXILResourceMap &DRM,
+ DXILResourceTypeMap &DRTM) {
hlsl::BindingInfoBuilder Builder;
dxbc::ShaderVisibility Visibility = tripleToVisibility(MMI.ShaderProfile);
@@ -216,11 +227,19 @@ static void validateRootSignature(Module &M,
Builder.calculateBindingInfo(
[&M](const llvm::hlsl::BindingInfoBuilder &Builder,
- const llvm::hlsl::BindingInfoBuilder::Binding &ReportedBinding) {
- const llvm::hlsl::BindingInfoBuilder::Binding &Overlaping =
+ const llvm::hlsl::Binding &ReportedBinding) {
+ const llvm::hlsl::Binding &Overlaping =
Builder.findOverlapping(ReportedBinding);
reportOverlappingRegisters(M, ReportedBinding, Overlaping);
});
+ const hlsl::BoundRegs &BoundRegs = Builder.takeBoundRegs();
+ for (const ResourceInfo &RI : DRM) {
+ const ResourceInfo::ResourceBinding &Binding = RI.getBinding();
+ ResourceClass RC = DRTM[RI.getHandleTy()].getResourceClass();
+ if (!BoundRegs.isBound(RC, Binding.Space, Binding.LowerBound,
+ Binding.LowerBound + Binding.Size - 1))
+ reportRegNotBound(M, RC, Binding);
+ }
}
static mcdxbc::RootSignatureDesc *
@@ -234,7 +253,8 @@ getRootSignature(RootSignatureBindingInfo &RSBI,
static void reportErrors(Module &M, DXILResourceMap &DRM,
DXILResourceBindingInfo &DRBI,
RootSignatureBindingInfo &RSBI,
- dxil::ModuleMetadataInfo &MMI) {
+ dxil::ModuleMetadataInfo &MMI,
+ DXILResourceTypeMap &DRTM) {
if (DRM.hasInvalidCounterDirection())
reportInvalidDirection(M, DRM);
@@ -245,7 +265,7 @@ static void reportErrors(Module &M, DXILResourceMap &DRM,
"DXILResourceImplicitBinding pass");
if (mcdxbc::RootSignatureDesc *RSD = getRootSignature(RSBI, MMI))
- validateRootSignature(M, *RSD, MMI);
+ validateRootSignature(M, *RSD, MMI, DRM, DRTM);
}
PreservedAnalyses
@@ -254,8 +274,9 @@ DXILPostOptimizationValidation::run(Module &M, ModuleAnalysisManager &MAM) {
DXILResourceBindingInfo &DRBI = MAM.getResult<DXILResourceBindingAnalysis>(M);
RootSignatureBindingInfo &RSBI = MAM.getResult<RootSignatureAnalysis>(M);
ModuleMetadataInfo &MMI = MAM.getResult<DXILMetadataAnalysis>(M);
+ DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
- reportErrors(M, DRM, DRBI, RSBI, MMI);
+ reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
return PreservedAnalyses::all();
}
@@ -271,8 +292,10 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
getAnalysis<RootSignatureAnalysisWrapper>().getRSInfo();
dxil::ModuleMetadataInfo &MMI =
getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
+ DXILResourceTypeMap &DRTM =
+ getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
- reportErrors(M, DRM, DRBI, RSBI, MMI);
+ reportErrors(M, DRM, DRBI, RSBI, MMI, DRTM);
return false;
}
StringRef getPassName() const override {
@@ -286,6 +309,7 @@ class DXILPostOptimizationValidationLegacy : public ModulePass {
AU.addRequired<DXILResourceBindingWrapperPass>();
AU.addRequired<DXILMetadataAnalysisWrapperPass>();
AU.addRequired<RootSignatureAnalysisWrapper>();
+ AU.addRequired<DXILResourceTypeWrapperPass>();
AU.addPreserved<DXILResourceWrapperPass>();
AU.addPreserved<DXILResourceBindingWrapperPass>();
AU.addPreserved<DXILMetadataAnalysisWrapperPass>();
@@ -303,6 +327,7 @@ INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILMetadataAnalysisWrapperPass)
INITIALIZE_PASS_DEPENDENCY(RootSignatureAnalysisWrapper)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceTypeWrapperPass)
INITIALIZE_PASS_END(DXILPostOptimizationValidationLegacy, DEBUG_TYPE,
"DXIL Post Optimization Validation", false, false)
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits-upperbound.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits-upperbound.ll
new file mode 100644
index 0000000000000..37c60b5ea6753
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits-upperbound.ll
@@ -0,0 +1,20 @@
+; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; This is a valid code, it checks the limits of a binding space
+; CHECK-NOT: error:
+
+%__cblayout_CB = type <{ float }>
+
+ at 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 0, i32 5, i32 0, ptr nonnull @CB.str)
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2}
+!2 = !{!"DescriptorTable", i32 0, !3}
+!3 = !{!"CBV", i32 5, i32 0, i32 0, i32 0, i32 4}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits.ll
new file mode 100644
index 0000000000000..edef06b6472d4
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-binding-limits.ll
@@ -0,0 +1,22 @@
+; RUN: opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; This is a valid code, it checks the limits of a binding space
+
+; CHECK-NOT: error:
+
+%__cblayout_CB = type <{ float }>
+
+ at 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 4294967294, i32 1, i32 0, ptr nonnull @CB.str)
+ %CB1 = tail call target("dx.CBuffer", target("dx.Layout", %__cblayout_CB, 4, 0)) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @CB.str)
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2, !3}
+!2 = !{!"RootCBV", i32 0, i32 4294967294, i32 0, i32 4}
+!3 = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbv-binding.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbv-binding.ll
new file mode 100644
index 0000000000000..de8552531ae38
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-cbv-binding.ll
@@ -0,0 +1,18 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: CBV register 2 in space 666 does not have a binding in the Root Signature
+
+%__cblayout_CB = type <{ float }>
+
+ at 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 666, i32 2, i32 1, i32 0, 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}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-consecutive-ranges.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-consecutive-ranges.ll
new file mode 100644
index 0000000000000..71d70386dcad8
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-consecutive-ranges.ll
@@ -0,0 +1,19 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: CBV register 3 in space 0 does not have a binding in the Root Signature
+%__cblayout_CB = type <{ float }>
+
+ at 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 3, i32 6, i32 0, ptr nonnull @CB.str)
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2}
+!2 = !{!"DescriptorTable", i32 0, !3, !4}
+!3 = !{!"CBV", i32 5, i32 2, i32 0, i32 0, i32 4}
+!4 = !{!"CBV", i32 4, i32 7, i32 0, i32 10, i32 4}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-binding.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-binding.ll
new file mode 100644
index 0000000000000..9b5c5d61dbbb6
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-sampler-binding.ll
@@ -0,0 +1,18 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: Sampler register 3 in space 2 does not have a binding in the Root Signature
+
+ at Smp.str = private unnamed_addr constant [4 x i8] c"Smp\00", align 1
+
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+ %Sampler = call target("dx.Sampler", 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 3, i32 1, i32 0, ptr nonnull @Smp.str)
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2}
+!2 = !{!"DescriptorTable", i32 0, !3}
+!3 = !{!"Sampler", i32 1, i32 42, i32 0, i32 -1, i32 0}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-srv-binding.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-srv-binding.ll
new file mode 100644
index 0000000000000..87a48a30be320
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-srv-binding.ll
@@ -0,0 +1,23 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: SRV register 0 in space 0 does not have a binding in the Root Signature
+
+ at SB.str = private unnamed_addr constant [3 x i8] c"SB\00", align 1
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+; StructuredBuffer<int> In : register(t0, space0);
+ %SB = tail call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(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, !5, !7}
+!2 = !{!"RootCBV", i32 0, i32 3, i32 666, i32 4}
+!3 = !{!"DescriptorTable", i32 1, !4}
+!4 = !{!"SRV", i32 1, i32 0, i32 0, i32 -1, i32 4}
+!5 = !{!"DescriptorTable", i32 0, !6}
+!6 = !{!"Sampler", i32 2, i32 0, i32 0, i32 -1, i32 0}
+!7 = !{!"DescriptorTable", i32 0, !8}
+!8 = !{!"UAV", i32 -1, i32 0, i32 0, i32 -1, i32 2}
diff --git a/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-uav-binding.ll b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-uav-binding.ll
new file mode 100644
index 0000000000000..a74766d37d2ed
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/rootsignature-validation-fail-uav-binding.ll
@@ -0,0 +1,23 @@
+; RUN: not opt -S -passes='dxil-post-optimization-validation' -mtriple=dxil-pc-shadermodel6.6-compute %s 2>&1 | FileCheck %s
+; CHECK: error: UAV register 4294967294 in space 0 does not have a binding in the Root Signature
+
+ at RWB.str = private unnamed_addr constant [4 x i8] c"RWB\00", align 1
+
+define void @CSMain() "hlsl.shader"="compute" {
+entry:
+; RWBuffer<float> UAV : register(4294967294);
+ %RWB = tail call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 0, i32 4294967294, i32 1, i32 0, ptr nonnull @RWB.str)
+ ret void
+}
+
+!dx.rootsignatures = !{!0}
+
+!0 = !{ptr @CSMain, !1, i32 2}
+!1 = !{!2, !3, !5, !7}
+!2 = !{!"RootCBV", i32 0, i32 3, i32 666, i32 4}
+!3 = !{!"DescriptorTable", i32 1, !4}
+!4 = !{!"SRV", i32 1, i32 0, i32 0, i32 -1, i32 4}
+!5 = !{!"DescriptorTable", i32 0, !6}
+!6 = !{!"Sampler", i32 2, i32 0, i32 0, i32 -1, i32 0}
+!7 = !{!"DescriptorTable", i32 0, !8}
+!8 = !{!"UAV", i32 10, i32 0, i32 0, i32 -1, i32 2}
More information about the llvm-commits
mailing list