[llvm] [SPIRV] Add StorageImageExtendedFormats to available list for Vulkan (PR #192512)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 16 11:48:00 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Steven Perron (s-perron)

<details>
<summary>Changes</summary>

Some image formats used in OpTypeImage require the
StorageImageExtendedFormats capability. When it is not in the available
list, it is not emitted, causing invalid SPIR-V.

The solution is to add it to the list. It is available for all versions
of Vulkan.

Fixes #<!-- -->192486


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


7 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp (+2-1) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatR11fG11fB10f.ll (+23) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32f.ll (+23) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32i.ll (+23) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32ui.ll (+23) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32f.ll (+25) 
- (added) llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32ui.ll (+24) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index 2eb84dec2cf29..c5d5af3bad238 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -965,7 +965,8 @@ void RequirementHandler::initAvailableCapabilitiesForVulkan(
                     Capability::StorageImageArrayDynamicIndexing,
                     Capability::DerivativeControl, Capability::MinLod,
                     Capability::ImageQuery, Capability::ImageGatherExtended,
-                    Capability::Addresses, Capability::VulkanMemoryModelKHR});
+                    Capability::Addresses, Capability::VulkanMemoryModelKHR,
+                    Capability::StorageImageExtendedFormats});
 
   // Became core in Vulkan 1.2
   if (ST.isAtLeastSPIRVVer(VersionTuple(1, 5))) {
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatR11fG11fB10f.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatR11fG11fB10f.ll
new file mode 100644
index 0000000000000..261097256c8f9
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatR11fG11fB10f.ll
@@ -0,0 +1,23 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#float]] Buffer 2 0 0 2 R11fG11fB10f
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.Image", float, 5, 2, 0, 0, 2, 8)
+      @llvm.spv.resource.handlefrombinding.tspirv.Image_f32_5_2_0_0_2_8(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x float> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.Image", float, 5, 2, 0, 0, 2, 8) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x float> @llvm.spv.resource.load.typedbuffer(target("spirv.Image", float, 5, 2, 0, 0, 2, 8), i32)
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32f.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32f.ll
new file mode 100644
index 0000000000000..94e53e1f53844
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32f.ll
@@ -0,0 +1,23 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#float]] Buffer 2 0 0 2 Rg32f
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.Image", float, 5, 2, 0, 0, 2, 6)
+      @llvm.spv.resource.handlefrombinding.tspirv.Image_f32_5_2_0_0_2_6(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x float> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.Image", float, 5, 2, 0, 0, 2, 6) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x float> @llvm.spv.resource.load.typedbuffer(target("spirv.Image", float, 5, 2, 0, 0, 2, 6), i32)
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32i.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32i.ll
new file mode 100644
index 0000000000000..60b19062c09e8
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32i.ll
@@ -0,0 +1,23 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#int:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#int]] Buffer 2 0 0 2 Rg32i
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 25)
+      @llvm.spv.resource.handlefrombinding.tspirv.SignedImage_i32_5_2_0_0_2_25(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x i32> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 25) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x i32> @llvm.spv.resource.load.typedbuffer(target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 25), i32)
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32ui.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32ui.ll
new file mode 100644
index 0000000000000..7255992230c40
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRg32ui.ll
@@ -0,0 +1,23 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#uint]] Buffer 2 0 0 2 Rg32ui
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.Image", i32, 5, 2, 0, 0, 2, 35)
+      @llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_35(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x i32> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.Image", i32, 5, 2, 0, 0, 2, 35) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x i32> @llvm.spv.resource.load.typedbuffer(target("spirv.Image", i32, 5, 2, 0, 0, 2, 35), i32)
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32f.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32f.ll
new file mode 100644
index 0000000000000..4ad877f450f78
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32f.ll
@@ -0,0 +1,25 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability Shader
+; CHECK-NOT: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#float:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#float]] Buffer 2 0 0 2 Rgba32f
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.Image", float, 5, 2, 0, 0, 2, 1)
+      @llvm.spv.resource.handlefrombinding.tspirv.Image_f32_5_2_0_0_2_1(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x float> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.Image", float, 5, 2, 0, 0, 2, 1) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x float> @llvm.spv.resource.load.typedbuffer(target("spirv.Image", float, 5, 2, 0, 0, 2, 1), i32)
+
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32ui.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32ui.ll
new file mode 100644
index 0000000000000..24c6a58a49197
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/ImageFormatRgba32ui.ll
@@ -0,0 +1,24 @@
+; 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 --target-env vulkan1.3 %}
+
+; CHECK-DAG: OpCapability Shader
+; CHECK-NOT: OpCapability StorageImageExtendedFormats
+; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#image:]] = OpTypeImage %[[#uint]] Buffer 2 0 0 2 Rgba32ui
+; CHECK-DAG: %[[#ptr:]] = OpTypePointer UniformConstant %[[#image]]
+; CHECK-DAG: %[[#var:]] = OpVariable %[[#ptr]] UniformConstant
+
+ at .str = private unnamed_addr constant [2 x i8] c"B\00", align 1
+
+define void @main() #0 {
+  %buffer = call target("spirv.Image", i32, 5, 2, 0, 0, 2, 30)
+      @llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_30(
+          i32 16, i32 7, i32 1, i32 0, ptr nonnull @.str)
+  %data = call <4 x i32> @llvm.spv.resource.load.typedbuffer(
+      target("spirv.Image", i32, 5, 2, 0, 0, 2, 30) %buffer, i32 0)
+  ret void
+}
+
+declare <4 x i32> @llvm.spv.resource.load.typedbuffer(target("spirv.Image", i32, 5, 2, 0, 0, 2, 30), i32)
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }

``````````

</details>


https://github.com/llvm/llvm-project/pull/192512


More information about the llvm-commits mailing list