[llvm] [SPIRV] Filter the out disallows extensions for env (PR #150051)

Steven Perron via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 22 09:19:20 PDT 2025


https://github.com/s-perron created https://github.com/llvm/llvm-project/pull/150051

Not all SPIR-V extensions are allows in every environment. When we use
the `-spirv-ext=all` option, the backend currently believes that all
extensions can be used.

This commit filters out the extensions on the command line to remove
those that are not known to be allowed for the current environment.

Alternatives considered: I considered modifying the
SPIRVExtensionsParser::parse to use a different list of extensions for
"all" depending on the target triple. However that does not work because
the target triple is not available, and cannot be made available in a
reasonable way.

Fixes #147717


>From 1bb22a24c921114a0d0565e1cc645570bd0203b2 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at google.com>
Date: Tue, 22 Jul 2025 10:28:13 -0400
Subject: [PATCH] [SPIRV] Filter the out disallows extensions for env

Not all SPIR-V extensions are allows in every environment. When we use
the `-spirv-ext=all` option, the backend currently believes that all
extensions can be used.

This commit filters out the extensions on the command line to remove
those that are not known to be allowed for the current environment.

Alternatives considered: I considered modifying the
SPIRVExtensionsParser::parse to use a different list of extensions for
"all" depending on the target triple. However that does not work because
the target triple is not available, and cannot be made available in a
reasonable way.

Fixes #147717
---
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    | 92 ++++++++++++++++++-
 llvm/lib/Target/SPIRV/SPIRVCommandLine.h      |  6 ++
 llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp      |  8 +-
 .../enable-all-extensions-avoid-invalid.ll    | 16 ++++
 4 files changed, 120 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions-avoid-invalid.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 2726203d253ad..be3a6a93a5a51 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SPIRVCommandLine.h"
-#include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/Triple.h"
 #include <algorithm>
 #include <map>
 
@@ -20,6 +20,69 @@
 
 using namespace llvm;
 
+// List of extensions allowed for Vulkan environment.
+// This should not contain an extension that is not listed in
+// https://github.com/KhronosGroup/Vulkan-Headers/blob/main/registry/vk.xml.
+static const std::set<SPIRV::Extension::Extension> ValidVulkanExtensions = {
+    SPIRV::Extension::SPV_EXT_demote_to_helper_invocation,
+    SPIRV::Extension::SPV_EXT_shader_atomic_float_add,
+    SPIRV::Extension::SPV_EXT_shader_atomic_float16_add,
+    SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max,
+    SPIRV::Extension::SPV_KHR_cooperative_matrix,
+    SPIRV::Extension::SPV_KHR_expect_assume,
+    SPIRV::Extension::SPV_KHR_float_controls,
+    SPIRV::Extension::SPV_KHR_float_controls2,
+    SPIRV::Extension::SPV_KHR_integer_dot_product,
+    SPIRV::Extension::SPV_KHR_non_semantic_info,
+    SPIRV::Extension::SPV_KHR_shader_clock,
+    SPIRV::Extension::SPV_KHR_subgroup_rotate};
+
+// List of extensions allowed for OpenCL environment.
+// TODO: Remove extension not used by OpenCL. I do not know how to get that
+// information.
+static const std::set<SPIRV::Extension::Extension> ValidOpenCLExtensions = {
+    SPIRV::Extension::SPV_EXT_shader_atomic_float_add,
+    SPIRV::Extension::SPV_EXT_shader_atomic_float16_add,
+    SPIRV::Extension::SPV_EXT_shader_atomic_float_min_max,
+    SPIRV::Extension::SPV_EXT_arithmetic_fence,
+    SPIRV::Extension::SPV_EXT_demote_to_helper_invocation,
+    SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers,
+    SPIRV::Extension::SPV_INTEL_cache_controls,
+    SPIRV::Extension::SPV_INTEL_float_controls2,
+    SPIRV::Extension::SPV_INTEL_global_variable_fpga_decorations,
+    SPIRV::Extension::SPV_INTEL_global_variable_host_access,
+    SPIRV::Extension::SPV_INTEL_optnone,
+    SPIRV::Extension::SPV_EXT_optnone,
+    SPIRV::Extension::SPV_INTEL_usm_storage_classes,
+    SPIRV::Extension::SPV_INTEL_split_barrier,
+    SPIRV::Extension::SPV_INTEL_subgroups,
+    SPIRV::Extension::SPV_INTEL_media_block_io,
+    SPIRV::Extension::SPV_INTEL_memory_access_aliasing,
+    SPIRV::Extension::SPV_INTEL_joint_matrix,
+    SPIRV::Extension::SPV_KHR_uniform_group_instructions,
+    SPIRV::Extension::SPV_KHR_no_integer_wrap_decoration,
+    SPIRV::Extension::SPV_KHR_float_controls,
+    SPIRV::Extension::SPV_KHR_expect_assume,
+    SPIRV::Extension::SPV_KHR_bit_instructions,
+    SPIRV::Extension::SPV_KHR_integer_dot_product,
+    SPIRV::Extension::SPV_KHR_linkonce_odr,
+    SPIRV::Extension::SPV_INTEL_inline_assembly,
+    SPIRV::Extension::SPV_INTEL_bindless_images,
+    SPIRV::Extension::SPV_INTEL_bfloat16_conversion,
+    SPIRV::Extension::SPV_KHR_subgroup_rotate,
+    SPIRV::Extension::SPV_INTEL_variable_length_array,
+    SPIRV::Extension::SPV_INTEL_function_pointers,
+    SPIRV::Extension::SPV_KHR_shader_clock,
+    SPIRV::Extension::SPV_KHR_cooperative_matrix,
+    SPIRV::Extension::SPV_KHR_non_semantic_info,
+    SPIRV::Extension::SPV_INTEL_long_composites,
+    SPIRV::Extension::SPV_INTEL_fp_max_error,
+    SPIRV::Extension::SPV_INTEL_subgroup_matrix_multiply_accumulate,
+    SPIRV::Extension::SPV_INTEL_ternary_bitwise_function,
+    SPIRV::Extension::SPV_INTEL_2d_block_io,
+    SPIRV::Extension::SPV_INTEL_int4,
+    SPIRV::Extension::SPV_KHR_float_controls2};
+
 static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
     SPIRVExtensionMap = {
         {"SPV_EXT_shader_atomic_float_add",
@@ -104,6 +167,26 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
         {"SPV_KHR_float_controls2",
          SPIRV::Extension::Extension::SPV_KHR_float_controls2}};
 
+/*
+
+TODO: std::set_union is not constexpr in c++17. I would still like a way to make
+sure the environment lists are added.
+
+// Check that every extension is in at least one of the two lists.
+constexpr bool AreAllExtensionsInAnEnvList() noexcept {
+      SPIRV::Extension::Extension ExtensionsInEnvList[100] = {};
+      constexpr auto* end = std::set_union(ValidVulkanExtensions.begin(),
+ValidVulkanExtensions.end(), ValidOpenCLExtensions.begin(),
+ValidOpenCLExtensions.end(), ExtensionsInEnvList); return
+(end-ExtensionsInEnvList) == SPIRVExtensionMap.size();
+}
+
+static_assert(
+    AreAllExtensionsInAnEnvList(),
+    "Not all extensions are in ValidVulkanExtensions or "
+    "ValidOpenCLExtensions");
+*/
+
 bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
                                   StringRef ArgValue,
                                   std::set<SPIRV::Extension::Extension> &Vals) {
@@ -169,3 +252,10 @@ StringRef SPIRVExtensionsParser::checkExtensions(
   }
   return StringRef();
 }
+
+const std::set<SPIRV::Extension::Extension> &
+SPIRVExtensionsParser::getValidExtensions(const Triple &TT) {
+  if (TT.getOS() == Triple::Vulkan)
+    return ValidVulkanExtensions;
+  return ValidOpenCLExtensions;
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.h b/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
index 3e3b22bde8603..dbde2397ab214 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
@@ -21,6 +21,7 @@
 
 namespace llvm {
 class StringRef;
+class Triple;
 
 /// Command line parser for toggling SPIR-V extensions.
 struct SPIRVExtensionsParser
@@ -42,6 +43,11 @@ struct SPIRVExtensionsParser
   static StringRef
   checkExtensions(const std::vector<std::string> &ExtNames,
                   std::set<SPIRV::Extension::Extension> &AllowedExtensions);
+
+  /// Returns the list of extensions that are valid for a particular
+  /// target environment (i.e., OpenCL or Vulkan).
+  static const std::set<SPIRV::Extension::Extension> &
+  getValidExtensions(const Triple &TT);
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
index cdf3c6224d4c8..690493fb426bc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
@@ -166,7 +166,13 @@ void SPIRVSubtarget::initAvailableExtInstSets() {
 void SPIRVSubtarget::initAvailableExtensions(
     const std::set<SPIRV::Extension::Extension> &AllowedExtIds) {
   AvailableExtensions.clear();
-  AvailableExtensions.insert_range(AllowedExtIds);
+  const std::set<SPIRV::Extension::Extension> &ValidExtensions =
+      SPIRVExtensionsParser::getValidExtensions(TargetTriple);
+
+  for (const auto &Ext : AllowedExtIds) {
+    if (ValidExtensions.count(Ext))
+      AvailableExtensions.insert(Ext);
+  }
 
   accountForAMDShaderTrinaryMinmax();
 }
diff --git a/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions-avoid-invalid.ll b/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions-avoid-invalid.ll
new file mode 100644
index 0000000000000..2de7fff0bc900
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/enable-all-extensions-avoid-invalid.ll
@@ -0,0 +1,16 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv1.6-vulkan1.3-compute --spirv-ext=all %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-compute --spirv-ext=all %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %}
+
+; CHECK-NOT: OpExtension "SPV_KHR_no_integer_wrap_decoration"
+
+define internal void @foo(i32 %i) local_unnamed_addr {
+  %sub.i = sub nsw i32 0, %i
+  ret void
+}
+
+define internal void @main() local_unnamed_addr #0 {
+entry:
+  ret void
+}
+
+attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
\ No newline at end of file



More information about the llvm-commits mailing list