[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