Skip to content

Conversation

@bogner
Copy link
Contributor

@bogner bogner commented Oct 22, 2025

We were checking for cbuffers where the global was removed, but if the buffer is completely unused the whole thing can be null.

We were checking for cbuffers where the global was removed, but if the
buffer is completely unused the whole thing can be null.
@llvmbot llvmbot added backend:DirectX HLSL HLSL Language Support labels Oct 22, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 22, 2025

@llvm/pr-subscribers-backend-directx

Author: Justin Bogner (bogner)

Changes

We were checking for cbuffers where the global was removed, but if the buffer is completely unused the whole thing can be null.


Full diff: https://github.com/llvm/llvm-project/pull/164557.diff

2 Files Affected:

  • (modified) llvm/lib/Frontend/HLSL/CBuffer.cpp (+7-2)
  • (added) llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll (+13)
diff --git a/llvm/lib/Frontend/HLSL/CBuffer.cpp b/llvm/lib/Frontend/HLSL/CBuffer.cpp
index 407b6ad6d5a7e..1e4a1a5020b0b 100644
--- a/llvm/lib/Frontend/HLSL/CBuffer.cpp
+++ b/llvm/lib/Frontend/HLSL/CBuffer.cpp
@@ -43,8 +43,13 @@ std::optional<CBufferMetadata> CBufferMetadata::get(Module &M) {
   for (const MDNode *MD : CBufMD->operands()) {
     assert(MD->getNumOperands() && "Invalid cbuffer metadata");
 
-    auto *Handle = cast<GlobalVariable>(
-        cast<ValueAsMetadata>(MD->getOperand(0))->getValue());
+    // For an unused cbuffer, the handle may have been optimizzd out
+    Metadata *OpMD = MD->getOperand(0);
+    if (!OpMD)
+      continue;
+
+    auto *Handle =
+        cast<GlobalVariable>(cast<ValueAsMetadata>(OpMD)->getValue());
     CBufferMapping &Mapping = Result->Mappings.emplace_back(Handle);
 
     for (int I = 1, E = MD->getNumOperands(); I < E; ++I) {
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll
new file mode 100644
index 0000000000000..8c0d82e43b4b1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll
@@ -0,0 +1,13 @@
+; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
+; Check that we correctly ignore cbuffers that were nulled out by optimizations.
+
+%__cblayout_CB = type <{ float }>
+@CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
+@x = external local_unnamed_addr addrspace(2) global float, align 4
+
+; CHECK-NOT: !hlsl.cbs =
+!hlsl.cbs = !{!0, !1, !2}
+
+!0 = !{ptr @CB.cb, ptr addrspace(2) @x}
+!1 = !{ptr @CB.cb, null}
+!2 = !{null, null}

@llvmbot
Copy link
Member

llvmbot commented Oct 22, 2025

@llvm/pr-subscribers-hlsl

Author: Justin Bogner (bogner)

Changes

We were checking for cbuffers where the global was removed, but if the buffer is completely unused the whole thing can be null.


Full diff: https://github.com/llvm/llvm-project/pull/164557.diff

2 Files Affected:

  • (modified) llvm/lib/Frontend/HLSL/CBuffer.cpp (+7-2)
  • (added) llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll (+13)
diff --git a/llvm/lib/Frontend/HLSL/CBuffer.cpp b/llvm/lib/Frontend/HLSL/CBuffer.cpp
index 407b6ad6d5a7e..1e4a1a5020b0b 100644
--- a/llvm/lib/Frontend/HLSL/CBuffer.cpp
+++ b/llvm/lib/Frontend/HLSL/CBuffer.cpp
@@ -43,8 +43,13 @@ std::optional<CBufferMetadata> CBufferMetadata::get(Module &M) {
   for (const MDNode *MD : CBufMD->operands()) {
     assert(MD->getNumOperands() && "Invalid cbuffer metadata");
 
-    auto *Handle = cast<GlobalVariable>(
-        cast<ValueAsMetadata>(MD->getOperand(0))->getValue());
+    // For an unused cbuffer, the handle may have been optimizzd out
+    Metadata *OpMD = MD->getOperand(0);
+    if (!OpMD)
+      continue;
+
+    auto *Handle =
+        cast<GlobalVariable>(cast<ValueAsMetadata>(OpMD)->getValue());
     CBufferMapping &Mapping = Result->Mappings.emplace_back(Handle);
 
     for (int I = 1, E = MD->getNumOperands(); I < E; ++I) {
diff --git a/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll b/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll
new file mode 100644
index 0000000000000..8c0d82e43b4b1
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/CBufferAccess/unused.ll
@@ -0,0 +1,13 @@
+; RUN: opt -S -dxil-cbuffer-access -mtriple=dxil--shadermodel6.3-library %s | FileCheck %s
+; Check that we correctly ignore cbuffers that were nulled out by optimizations.
+
+%__cblayout_CB = type <{ float }>
+@CB.cb = local_unnamed_addr global target("dx.CBuffer", %__cblayout_CB) poison
+@x = external local_unnamed_addr addrspace(2) global float, align 4
+
+; CHECK-NOT: !hlsl.cbs =
+!hlsl.cbs = !{!0, !1, !2}
+
+!0 = !{ptr @CB.cb, ptr addrspace(2) @x}
+!1 = !{ptr @CB.cb, null}
+!2 = !{null, null}

Copy link
Contributor

@s-perron s-perron left a comment

Choose a reason for hiding this comment

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

Do you have an HLSL sample that produces this? I want to make sure I have a test for SPIR-V, but I'm not sure how to reproduce it.

@bogner
Copy link
Contributor Author

bogner commented Oct 22, 2025

Do you have an HLSL sample that produces this? I want to make sure I have a test for SPIR-V, but I'm not sure how to reproduce it.

I hit this with a shader who's entry point wasn't "main", but I hadn't specified a -E argument to the compiler - ie, https://hlsl.godbolt.org/z/7xx6qrYsT

Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

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

LGTM!

Co-authored-by: Helena Kotas <hekotas@microsoft.com>
@bogner bogner merged commit 11a24d6 into llvm:main Oct 23, 2025
11 checks passed
mikolaj-pirog pushed a commit to mikolaj-pirog/llvm-project that referenced this pull request Oct 23, 2025
We were checking for cbuffers where the global was removed, but if the
buffer is completely unused the whole thing can be null.

---------

Co-authored-by: Helena Kotas <hekotas@microsoft.com>
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
We were checking for cbuffers where the global was removed, but if the
buffer is completely unused the whole thing can be null.

---------

Co-authored-by: Helena Kotas <hekotas@microsoft.com>
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
We were checking for cbuffers where the global was removed, but if the
buffer is completely unused the whole thing can be null.

---------

Co-authored-by: Helena Kotas <hekotas@microsoft.com>
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
We were checking for cbuffers where the global was removed, but if the
buffer is completely unused the whole thing can be null.

---------

Co-authored-by: Helena Kotas <hekotas@microsoft.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:DirectX HLSL HLSL Language Support

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants