[llvm] [SPIRV] Emit RuntimeDescriptorArrayEXT capability for all unbounded array types (PR #222819)
Helena Kotas via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 14 11:01:19 PDT 2026
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/222819
>From a0a6fb8d590d0b67bb011f225373dde64264586e Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 10 Sep 2026 17:05:35 -0700
Subject: [PATCH 1/2] [SPIRV] Emit RuntimeDescriptorArrayEXT capability for all
unbounded array types
Previously, the `RuntimeDescriptorArrayEXT` capability was emitted only for images.
This change sets RuntimeDescriptorArrayEXT whenever ArraySize == 0. This covers images,
structured buffers, samplers, and counter descriptor arrays.
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 +-
.../hlsl-resources/unbounded-struct-arr.ll | 28 +++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 41e4dc290c099..2d38332b0e48e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -7639,7 +7639,7 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
SC = GR.getPointerStorageClass(ResType);
}
- if (ResType->getOpcode() == SPIRV::OpTypeImage && ArraySize == 0)
+ if (ArraySize == 0)
MIRBuilder.buildInstr(SPIRV::OpCapability)
.addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
new file mode 100644
index 0000000000000..1fe90f3e05809
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
@@ -0,0 +1,28 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %}
+
+; Verify that unbounded arrays of structured buffers and their associated
+; counters enable RuntimeDescriptorArrayEXT.
+
+; CHECK-DAG: OpCapability RuntimeDescriptorArrayEXT
+; CHECK-DAG: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
+; CHECK-DAG: %[[UINT:[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: %[[DATA_ARRAY:[0-9]+]] = OpTypeRuntimeArray %[[FLOAT]]
+; CHECK-DAG: %[[BUFFER:[0-9]+]] = OpTypeStruct %[[DATA_ARRAY]]
+; CHECK-DAG: OpTypeRuntimeArray %[[BUFFER]]
+; CHECK-DAG: %[[COUNTER:[0-9]+]] = OpTypeStruct %[[UINT]]
+; CHECK-DAG: OpTypeRuntimeArray %[[COUNTER]]
+
+ at Bufs.str = private unnamed_addr constant [5 x i8] c"Bufs\00", align 1
+
+define void @main() #0 {
+entry:
+ %handle = call target("spirv.VulkanBuffer", [0 x float], 12, 1) @llvm.spv.resource.handlefrombinding(i32 0, i32 0, i32 0, i32 0, ptr @Bufs.str)
+ %counter.handle = call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefrombinding(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 0, i32 1)
+ %counter = call i32 @llvm.spv.resource.updatecounter(target("spirv.VulkanBuffer", i32, 12, 1) %counter.handle, i8 1)
+ %pointer = call ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 %counter)
+ store float 0.000000e+00, ptr addrspace(11) %pointer, align 4
+ ret void
+}
+
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
>From 29ca86c770fff819f39c07a84dae9c9362884bb6 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 14 Sep 2026 11:00:52 -0700
Subject: [PATCH 2/2] add comment and update new lines
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 2 +
.../hlsl-resources/unbounded-struct-arr.ll | 56 +++++++++----------
2 files changed, 30 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 2d38332b0e48e..1d821c5aec993 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -7639,6 +7639,8 @@ bool SPIRVInstructionSelector::loadHandleBeforePosition(
SC = GR.getPointerStorageClass(ResType);
}
+ // ArraySize 0 means an unbounded array and we need to set to required
+ // capability.
if (ArraySize == 0)
MIRBuilder.buildInstr(SPIRV::OpCapability)
.addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
index 1fe90f3e05809..ad42bacc8bc3d 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/unbounded-struct-arr.ll
@@ -1,28 +1,28 @@
-; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s
-; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %}
-
-; Verify that unbounded arrays of structured buffers and their associated
-; counters enable RuntimeDescriptorArrayEXT.
-
-; CHECK-DAG: OpCapability RuntimeDescriptorArrayEXT
-; CHECK-DAG: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
-; CHECK-DAG: %[[UINT:[0-9]+]] = OpTypeInt 32 0
-; CHECK-DAG: %[[DATA_ARRAY:[0-9]+]] = OpTypeRuntimeArray %[[FLOAT]]
-; CHECK-DAG: %[[BUFFER:[0-9]+]] = OpTypeStruct %[[DATA_ARRAY]]
-; CHECK-DAG: OpTypeRuntimeArray %[[BUFFER]]
-; CHECK-DAG: %[[COUNTER:[0-9]+]] = OpTypeStruct %[[UINT]]
-; CHECK-DAG: OpTypeRuntimeArray %[[COUNTER]]
-
- at Bufs.str = private unnamed_addr constant [5 x i8] c"Bufs\00", align 1
-
-define void @main() #0 {
-entry:
- %handle = call target("spirv.VulkanBuffer", [0 x float], 12, 1) @llvm.spv.resource.handlefrombinding(i32 0, i32 0, i32 0, i32 0, ptr @Bufs.str)
- %counter.handle = call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefrombinding(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 0, i32 1)
- %counter = call i32 @llvm.spv.resource.updatecounter(target("spirv.VulkanBuffer", i32, 12, 1) %counter.handle, i8 1)
- %pointer = call ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 %counter)
- store float 0.000000e+00, ptr addrspace(11) %pointer, align 4
- ret void
-}
-
-attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %}
+
+; Verify that unbounded arrays of structured buffers and their associated
+; counters enable RuntimeDescriptorArrayEXT.
+
+; CHECK-DAG: OpCapability RuntimeDescriptorArrayEXT
+; CHECK-DAG: %[[FLOAT:[0-9]+]] = OpTypeFloat 32
+; CHECK-DAG: %[[UINT:[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: %[[DATA_ARRAY:[0-9]+]] = OpTypeRuntimeArray %[[FLOAT]]
+; CHECK-DAG: %[[BUFFER:[0-9]+]] = OpTypeStruct %[[DATA_ARRAY]]
+; CHECK-DAG: OpTypeRuntimeArray %[[BUFFER]]
+; CHECK-DAG: %[[COUNTER:[0-9]+]] = OpTypeStruct %[[UINT]]
+; CHECK-DAG: OpTypeRuntimeArray %[[COUNTER]]
+
+ at Bufs.str = private unnamed_addr constant [5 x i8] c"Bufs\00", align 1
+
+define void @main() #0 {
+entry:
+ %handle = call target("spirv.VulkanBuffer", [0 x float], 12, 1) @llvm.spv.resource.handlefrombinding(i32 0, i32 0, i32 0, i32 0, ptr @Bufs.str)
+ %counter.handle = call target("spirv.VulkanBuffer", i32, 12, 1) @llvm.spv.resource.counterhandlefrombinding(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 0, i32 1)
+ %counter = call i32 @llvm.spv.resource.updatecounter(target("spirv.VulkanBuffer", i32, 12, 1) %counter.handle, i8 1)
+ %pointer = call ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x float], 12, 1) %handle, i32 %counter)
+ store float 0.000000e+00, ptr addrspace(11) %pointer, align 4
+ ret void
+}
+
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
More information about the llvm-commits
mailing list