[llvm] [SPIR-V] Change a way SPIR-V Backend API works with user facing options (PR #124745)

Vyacheslav Levytskyy via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 28 06:35:53 PST 2025


https://github.com/VyacheslavLevytskyy updated https://github.com/llvm/llvm-project/pull/124745

>From 6f121f221596c57c35e924f423647b1a9173b011 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Tue, 28 Jan 2025 05:31:28 -0800
Subject: [PATCH 1/2] Change a way SPIR-V Backend API works with user facing
 options

---
 llvm/lib/Target/SPIRV/SPIRVAPI.cpp            |  83 ++++----
 llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp    |   5 +
 llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp |   6 +-
 llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp      |  26 ++-
 llvm/lib/Target/SPIRV/SPIRVSubtarget.h        |   4 +
 llvm/unittests/Target/SPIRV/CMakeLists.txt    |   1 +
 llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp  | 192 +++++++++++++-----
 7 files changed, 207 insertions(+), 110 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVAPI.cpp b/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
index 95c9b0e5200608..a19384d4e279ca 100644
--- a/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
@@ -8,6 +8,7 @@
 
 #include "SPIRVCommandLine.h"
 #include "SPIRVSubtarget.h"
+#include "SPIRVTargetMachine.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/CodeGen/CommandFlags.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
@@ -40,25 +41,6 @@ using namespace llvm;
 
 namespace {
 
-// Mimic limited number of command line flags from llc to provide a better
-// user experience when passing options into the translate API call.
-static cl::opt<char> SpirvOptLevel("spirv-O", cl::Hidden, cl::Prefix,
-                                   cl::init('0'));
-static cl::opt<std::string> SpirvTargetTriple("spirv-mtriple", cl::Hidden,
-                                              cl::init(""));
-
-// Utility to accept options in a command line style.
-void parseSPIRVCommandLineOptions(const std::vector<std::string> &Options,
-                                  raw_ostream *Errs) {
-  static constexpr const char *Origin = "SPIRVTranslateModule";
-  if (!Options.empty()) {
-    std::vector<const char *> Argv(1, Origin);
-    for (const auto &Arg : Options)
-      Argv.push_back(Arg.c_str());
-    cl::ParseCommandLineOptions(Argv.size(), Argv.data(), Origin, Errs);
-  }
-}
-
 std::once_flag InitOnceFlag;
 void InitializeSPIRVTarget() {
   std::call_once(InitOnceFlag, []() {
@@ -75,35 +57,15 @@ namespace llvm {
 // The goal of this function is to facilitate integration of SPIRV Backend into
 // tools and libraries by means of exposing an API call that translate LLVM
 // module to SPIR-V and write results into a string as binary SPIR-V output,
-// providing diagnostics on fail and means of configuring translation in a style
-// of command line options.
+// providing diagnostics on fail and means of configuring translation.
 extern "C" LLVM_EXTERNAL_VISIBILITY bool
-SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
-                     const std::vector<std::string> &AllowExtNames,
-                     const std::vector<std::string> &Opts) {
+SPIRVTranslate(Module *M, std::string &SpirvObj, std::string &ErrMsg,
+               const std::vector<std::string> &AllowExtNames,
+               llvm::CodeGenOptLevel OLevel, Triple TargetTriple) {
   // Fallbacks for option values.
   static const std::string DefaultTriple = "spirv64-unknown-unknown";
   static const std::string DefaultMArch = "";
 
-  // Parse Opts as if it'd be command line arguments.
-  std::string Errors;
-  raw_string_ostream ErrorStream(Errors);
-  parseSPIRVCommandLineOptions(Opts, &ErrorStream);
-  if (!Errors.empty()) {
-    ErrMsg = Errors;
-    return false;
-  }
-
-  llvm::CodeGenOptLevel OLevel;
-  if (auto Level = CodeGenOpt::parseLevel(SpirvOptLevel)) {
-    OLevel = *Level;
-  } else {
-    ErrMsg = "Invalid optimization level!";
-    return false;
-  }
-
-  // Overrides/ammends `-spirv-ext` command line switch (if present) by the
-  // explicit list of allowed SPIR-V extensions.
   std::set<SPIRV::Extension::Extension> AllowedExtIds;
   StringRef UnknownExt =
       SPIRVExtensionsParser::checkExtensions(AllowExtNames, AllowedExtIds);
@@ -111,14 +73,10 @@ SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
     ErrMsg = "Unknown SPIR-V extension: " + UnknownExt.str();
     return false;
   }
-  SPIRVSubtarget::addExtensionsToClOpt(AllowedExtIds);
 
   // SPIR-V-specific target initialization.
   InitializeSPIRVTarget();
 
-  Triple TargetTriple(SpirvTargetTriple.empty()
-                          ? M->getTargetTriple()
-                          : Triple::normalize(SpirvTargetTriple));
   if (TargetTriple.getTriple().empty()) {
     TargetTriple.setTriple(DefaultTriple);
     M->setTargetTriple(DefaultTriple);
@@ -142,6 +100,11 @@ SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
     return false;
   }
 
+  // Set available extensions.
+  SPIRVTargetMachine *STM = static_cast<SPIRVTargetMachine *>(Target.get());
+  const_cast<SPIRVSubtarget *>(STM->getSubtargetImpl())
+      ->initAvailableExtensions(AllowedExtIds);
+
   if (M->getCodeModel())
     Target->setCodeModel(*M->getCodeModel());
 
@@ -177,4 +140,30 @@ SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
   return true;
 }
 
+// TODO: Remove this wrapper after existing clients switch into a newer
+// implementation of SPIRVTranslate().
+extern "C" LLVM_EXTERNAL_VISIBILITY bool
+SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
+                     const std::vector<std::string> &AllowExtNames,
+                     const std::vector<std::string> &Opts) {
+  // optional: Opts[0] is a string representation of Triple,
+  // take Module triple otherwise
+  Triple TargetTriple(Opts.empty() || Opts[0].empty()
+                          ? M->getTargetTriple()
+                          : Triple::normalize(Opts[0]));
+  // optional: Opts[1] is a string representation of CodeGenOptLevel,
+  // no optimization otherwise
+  llvm::CodeGenOptLevel OLevel = CodeGenOptLevel::None;
+  if (Opts.size() > 1 && !Opts[1].empty()) {
+    if (auto Level = CodeGenOpt::parseLevel(Opts[1][0])) {
+      OLevel = *Level;
+    } else {
+      ErrMsg = "Invalid optimization level!";
+      return false;
+    }
+  }
+  return SPIRVTranslate(M, SpirvObj, ErrMsg, AllowExtNames, OLevel,
+                        TargetTriple);
+}
+
 } // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 45b39c51164795..13683fd9a266d0 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -133,6 +133,11 @@ llvm::StringRef SPIRVExtensionsParser::checkExtensions(
     const std::vector<std::string> &ExtNames,
     std::set<SPIRV::Extension::Extension> &AllowedExtensions) {
   for (const auto &Ext : ExtNames) {
+    if (Ext == "all") {
+      for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
+        AllowedExtensions.insert(ExtensionEnum);
+      break;
+    }
     auto It = SPIRVExtensionMap.find(Ext);
     if (It == SPIRVExtensionMap.end())
       return Ext;
diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
index bc00d5032544fd..d3afaf42e05b73 100644
--- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
@@ -73,8 +73,10 @@ static SPIRV::Requirements
 getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
                                unsigned i, const SPIRVSubtarget &ST,
                                SPIRV::RequirementHandler &Reqs) {
-  static AvoidCapabilitiesSet
-      AvoidCaps; // contains capabilities to avoid if there is another option
+  // A set of capabilities to avoid if there is another option.
+  AvoidCapabilitiesSet AvoidCaps;
+  if (ST.isOpenCLEnv())
+    AvoidCaps.S.insert(SPIRV::Capability::Shader);
 
   VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
   VersionTuple ReqMaxVer = getSymbolicOperandMaxVersion(Category, i);
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
index a476b51c3120af..fc31bbd06387c3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
@@ -84,7 +84,7 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU,
   OpenCLVersion = VersionTuple(2, 2);
 
   // The order of initialization is important.
-  initAvailableExtensions();
+  initAvailableExtensions(Extensions);
   initAvailableExtInstSets();
 
   GR = std::make_unique<SPIRVGlobalRegistry>(PointerSize);
@@ -135,9 +135,12 @@ bool SPIRVSubtarget::canDirectlyComparePointers() const {
   return !SPVTranslatorCompat && isAtLeastVer(SPIRVVersion, VersionTuple(1, 4));
 }
 
-void SPIRVSubtarget::initAvailableExtensions() {
-  AvailableExtensions.clear();
-  AvailableExtensions.insert(Extensions.begin(), Extensions.end());
+void SPIRVSubtarget::accountForAMDShaderTrinaryMinmax() {
+  if (canUseExtension(
+          SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) {
+    AvailableExtInstSets.insert(
+        SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax);
+  }
 }
 
 // TODO: use command line args for this rather than just defaults.
@@ -150,9 +153,14 @@ void SPIRVSubtarget::initAvailableExtInstSets() {
     AvailableExtInstSets.insert(SPIRV::InstructionSet::OpenCL_std);
 
   // Handle extended instruction sets from extensions.
-  if (canUseExtension(
-          SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) {
-    AvailableExtInstSets.insert(
-        SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax);
-  }
+  accountForAMDShaderTrinaryMinmax();
+}
+
+// Set available extensions after SPIRVSubtarget is created.
+void SPIRVSubtarget::initAvailableExtensions(
+    std::set<SPIRV::Extension::Extension> AllowedExtIds) {
+  AvailableExtensions.clear();
+  AvailableExtensions.insert(AllowedExtIds.begin(), AllowedExtIds.end());
+
+  accountForAMDShaderTrinaryMinmax();
 }
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index e587739a7636fb..eb289b7aa38f3e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -61,6 +61,7 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
   // based on the environment settings.
   void initAvailableExtensions();
   void initAvailableExtInstSets();
+  void accountForAMDShaderTrinaryMinmax();
 
 public:
   // This constructor initializes the data members to match that
@@ -69,6 +70,9 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
                  const std::string &FS, const SPIRVTargetMachine &TM);
   SPIRVSubtarget &initSubtargetDependencies(StringRef CPU, StringRef FS);
 
+  void
+  initAvailableExtensions(std::set<SPIRV::Extension::Extension> AllowedExtIds);
+
   // Parses features string setting specified subtarget options.
   // The definition of this function is auto generated by tblgen.
   void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
diff --git a/llvm/unittests/Target/SPIRV/CMakeLists.txt b/llvm/unittests/Target/SPIRV/CMakeLists.txt
index af7d9395605d04..d7f0290089c4cf 100644
--- a/llvm/unittests/Target/SPIRV/CMakeLists.txt
+++ b/llvm/unittests/Target/SPIRV/CMakeLists.txt
@@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
   SPIRVCodeGen
   SPIRVAnalysis
   Support
+  TargetParser
   )
 
 add_llvm_target_unittest(SPIRVTests
diff --git a/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp b/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
index f0b4a2f55c1519..5eae9277c4438b 100644
--- a/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
+++ b/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
@@ -16,6 +16,7 @@
 #include "llvm/BinaryFormat/Magic.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/SourceMgr.h"
+#include "llvm/TargetParser/Triple.h"
 #include "gtest/gtest.h"
 #include <gmock/gmock.h>
 #include <string>
@@ -25,6 +26,11 @@ using ::testing::StartsWith;
 
 namespace llvm {
 
+extern "C" LLVM_EXTERNAL_VISIBILITY bool
+SPIRVTranslate(Module *M, std::string &SpirvObj, std::string &ErrMsg,
+               const std::vector<std::string> &AllowExtNames,
+               llvm::CodeGenOptLevel OLevel, Triple TargetTriple);
+
 extern "C" bool
 SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
                      const std::vector<std::string> &AllowExtNames,
@@ -34,7 +40,27 @@ class SPIRVAPITest : public testing::Test {
 protected:
   bool toSpirv(StringRef Assembly, std::string &Result, std::string &ErrMsg,
                const std::vector<std::string> &AllowExtNames,
-               const std::vector<std::string> &Opts) {
+               llvm::CodeGenOptLevel OLevel, Triple TargetTriple) {
+    SMDiagnostic ParseError;
+    LLVMContext Context;
+    std::unique_ptr<Module> M =
+        parseAssemblyString(Assembly, ParseError, Context);
+    if (!M) {
+      ParseError.print("IR parsing failed: ", errs());
+      report_fatal_error("Can't parse input assembly.");
+    }
+    bool Status = SPIRVTranslate(M.get(), Result, ErrMsg, AllowExtNames, OLevel,
+                                 TargetTriple);
+    if (!Status)
+      errs() << ErrMsg;
+    return Status;
+  }
+  // TODO: Remove toSpirvLegacy() and related tests after existing clients
+  // switch into a newer implementation of SPIRVTranslate().
+  bool toSpirvLegacy(StringRef Assembly, std::string &Result,
+                     std::string &ErrMsg,
+                     const std::vector<std::string> &AllowExtNames,
+                     const std::vector<std::string> &Opts) {
     SMDiagnostic ParseError;
     LLVMContext Context;
     std::unique_ptr<Module> M =
@@ -77,48 +103,21 @@ class SPIRVAPITest : public testing::Test {
 
 TEST_F(SPIRVAPITest, checkTranslateOk) {
   StringRef Assemblies[] = {"", OkAssembly};
-  // Those command line arguments that overlap with registered by llc/codegen
-  // are to be started with the ' ' symbol.
-  std::vector<std::string> SetOfOpts[] = {
-      {}, {"--spirv-mtriple=spirv32-unknown-unknown"}};
-  for (const auto &Opts : SetOfOpts) {
-    for (StringRef &Assembly : Assemblies) {
-      std::string Result, Error;
-      bool Status = toSpirv(Assembly, Result, Error, {}, Opts);
-      EXPECT_TRUE(Status && Error.empty() && !Result.empty());
-      EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
-    }
+  for (StringRef &Assembly : Assemblies) {
+    std::string Result, Error;
+    bool Status = toSpirv(Assembly, Result, Error, {}, CodeGenOptLevel::Default,
+                          Triple("spirv32-unknown-unknown"));
+    EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+    EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
   }
 }
 
-TEST_F(SPIRVAPITest, checkTranslateError) {
-  std::string Result, Error;
-  bool Status = toSpirv(OkAssembly, Result, Error, {},
-                        {"-mtriple=spirv32-unknown-unknown"});
-  EXPECT_FALSE(Status);
-  EXPECT_TRUE(Result.empty());
-  EXPECT_THAT(Error,
-              StartsWith("SPIRVTranslateModule: Unknown command line argument "
-                         "'-mtriple=spirv32-unknown-unknown'"));
-  Status = toSpirv(OkAssembly, Result, Error, {}, {"--spirv-O 5"});
-  EXPECT_FALSE(Status);
-  EXPECT_TRUE(Result.empty());
-  EXPECT_EQ(Error, "Invalid optimization level!");
-}
-
-TEST_F(SPIRVAPITest, checkTranslateSupportExtensionByOpts) {
-  std::string Result, Error;
-  std::vector<std::string> Opts{
-      "--spirv-ext=+SPV_KHR_uniform_group_instructions"};
-  bool Status = toSpirv(ExtensionAssembly, Result, Error, {}, Opts);
-  EXPECT_TRUE(Status && Error.empty() && !Result.empty());
-  EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
-}
-
 TEST_F(SPIRVAPITest, checkTranslateSupportExtensionByArg) {
   std::string Result, Error;
   std::vector<std::string> ExtNames{"SPV_KHR_uniform_group_instructions"};
-  bool Status = toSpirv(ExtensionAssembly, Result, Error, ExtNames, {});
+  bool Status =
+      toSpirv(ExtensionAssembly, Result, Error, ExtNames,
+              CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
   EXPECT_TRUE(Status && Error.empty() && !Result.empty());
   EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
 }
@@ -128,15 +127,19 @@ TEST_F(SPIRVAPITest, checkTranslateSupportExtensionByArgList) {
   std::vector<std::string> ExtNames{"SPV_KHR_subgroup_rotate",
                                     "SPV_KHR_uniform_group_instructions",
                                     "SPV_KHR_subgroup_rotate"};
-  bool Status = toSpirv(ExtensionAssembly, Result, Error, ExtNames, {});
+  bool Status =
+      toSpirv(ExtensionAssembly, Result, Error, ExtNames,
+              CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
   EXPECT_TRUE(Status && Error.empty() && !Result.empty());
   EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
 }
 
 TEST_F(SPIRVAPITest, checkTranslateAllExtensions) {
   std::string Result, Error;
-  std::vector<std::string> Opts{"--spirv-ext=all"};
-  bool Status = toSpirv(ExtensionAssembly, Result, Error, {}, Opts);
+  std::vector<std::string> ExtNames{"all"};
+  bool Status =
+      toSpirv(ExtensionAssembly, Result, Error, ExtNames,
+              CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
   EXPECT_TRUE(Status && Error.empty() && !Result.empty());
   EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
 }
@@ -144,7 +147,9 @@ TEST_F(SPIRVAPITest, checkTranslateAllExtensions) {
 TEST_F(SPIRVAPITest, checkTranslateUnknownExtensionByArg) {
   std::string Result, Error;
   std::vector<std::string> ExtNames{"SPV_XYZ_my_unknown_extension"};
-  bool Status = toSpirv(ExtensionAssembly, Result, Error, ExtNames, {});
+  bool Status =
+      toSpirv(ExtensionAssembly, Result, Error, ExtNames,
+              CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
   EXPECT_FALSE(Status);
   EXPECT_TRUE(Result.empty());
   EXPECT_EQ(Error, "Unknown SPIR-V extension: SPV_XYZ_my_unknown_extension");
@@ -153,35 +158,118 @@ TEST_F(SPIRVAPITest, checkTranslateUnknownExtensionByArg) {
 #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
 TEST_F(SPIRVAPITest, checkTranslateExtensionError) {
   std::string Result, Error;
-  std::vector<std::string> Opts;
   EXPECT_DEATH_IF_SUPPORTED(
-      { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
+      {
+        toSpirv(ExtensionAssembly, Result, Error, {},
+                CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
+      },
       "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
       "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
 }
 
-TEST_F(SPIRVAPITest, checkTranslateUnknownExtensionByOpts) {
+TEST_F(SPIRVAPITest, checkTranslateWrongExtensionByArg) {
   std::string Result, Error;
-  std::vector<std::string> Opts{"--spirv-ext=+SPV_XYZ_my_unknown_extension"};
+  std::vector<std::string> ExtNames{"SPV_KHR_subgroup_rotate"};
   EXPECT_DEATH_IF_SUPPORTED(
-      { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
-      "SPIRVTranslateModule: for the --spirv-ext option: Unknown SPIR-V");
+      {
+        toSpirv(ExtensionAssembly, Result, Error, ExtNames,
+                CodeGenOptLevel::Aggressive, Triple("spirv64-unknown-unknown"));
+      },
+      "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
+      "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
 }
+#endif
 
-TEST_F(SPIRVAPITest, checkTranslateWrongExtensionByOpts) {
+// Legacy API calls. TODO: Remove after transition into a newer API.
+TEST_F(SPIRVAPITest, checkTranslateStringOptsOk) {
+  StringRef Assemblies[] = {"", OkAssembly};
+  std::vector<std::string> SetOfOpts[] = {{}, {"spirv32-unknown-unknown"}};
+  for (const auto &Opts : SetOfOpts) {
+    for (StringRef &Assembly : Assemblies) {
+      std::string Result, Error;
+      bool Status = toSpirvLegacy(Assembly, Result, Error, {}, Opts);
+      EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+      EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+    }
+  }
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsError) {
+  std::string Result, Error;
+  bool Status = toSpirvLegacy(OkAssembly, Result, Error, {},
+                              {"spirv64v1.6-unknown-unknown", "5"});
+  EXPECT_FALSE(Status);
+  EXPECT_TRUE(Result.empty());
+  EXPECT_EQ(Error, "Invalid optimization level!");
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsErrorOk) {
+  {
+    std::string Result, Error;
+    bool Status = toSpirvLegacy(OkAssembly, Result, Error, {},
+                                {"spirv64v1.6-unknown-unknown", "5"});
+    EXPECT_FALSE(Status);
+    EXPECT_TRUE(Result.empty());
+    EXPECT_EQ(Error, "Invalid optimization level!");
+  }
+  {
+    std::string Result, Error;
+    bool Status = toSpirvLegacy(OkAssembly, Result, Error, {},
+                                {"spirv64v1.6-unknown-unknown", "3"});
+    EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+    EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+  }
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsSupportExtensionByArg) {
+  std::string Result, Error;
+  std::vector<std::string> ExtNames{"SPV_KHR_uniform_group_instructions"};
+  bool Status = toSpirvLegacy(ExtensionAssembly, Result, Error, ExtNames, {});
+  EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+  EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsSupportExtensionByArgList) {
+  std::string Result, Error;
+  std::vector<std::string> ExtNames{"SPV_KHR_subgroup_rotate",
+                                    "SPV_KHR_uniform_group_instructions",
+                                    "SPV_KHR_subgroup_rotate"};
+  bool Status = toSpirvLegacy(ExtensionAssembly, Result, Error, ExtNames, {});
+  EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+  EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsAllExtensions) {
+  std::string Result, Error;
+  std::vector<std::string> ExtNames{"all"};
+  bool Status = toSpirvLegacy(ExtensionAssembly, Result, Error, ExtNames, {});
+  EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+  EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+}
+
+TEST_F(SPIRVAPITest, checkTranslateStringOptsUnknownExtensionByArg) {
+  std::string Result, Error;
+  std::vector<std::string> ExtNames{"SPV_XYZ_my_unknown_extension"};
+  bool Status = toSpirvLegacy(ExtensionAssembly, Result, Error, ExtNames, {});
+  EXPECT_FALSE(Status);
+  EXPECT_TRUE(Result.empty());
+  EXPECT_EQ(Error, "Unknown SPIR-V extension: SPV_XYZ_my_unknown_extension");
+}
+
+#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
+TEST_F(SPIRVAPITest, checkTranslateStringOptsExtensionError) {
   std::string Result, Error;
-  std::vector<std::string> Opts{"--spirv-ext=+SPV_KHR_subgroup_rotate"};
   EXPECT_DEATH_IF_SUPPORTED(
-      { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
+      { toSpirvLegacy(ExtensionAssembly, Result, Error, {}, {}); },
       "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
       "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
 }
 
-TEST_F(SPIRVAPITest, checkTranslateWrongExtensionByArg) {
+TEST_F(SPIRVAPITest, checkTranslateStringOptsWrongExtensionByArg) {
   std::string Result, Error;
   std::vector<std::string> ExtNames{"SPV_KHR_subgroup_rotate"};
   EXPECT_DEATH_IF_SUPPORTED(
-      { toSpirv(ExtensionAssembly, Result, Error, ExtNames, {}); },
+      { toSpirvLegacy(ExtensionAssembly, Result, Error, ExtNames, {}); },
       "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
       "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
 }

>From 2bdceba062fc030f471682f6b0f78e912502df27 Mon Sep 17 00:00:00 2001
From: "Levytskyy, Vyacheslav" <vyacheslav.levytskyy at intel.com>
Date: Tue, 28 Jan 2025 06:34:01 -0800
Subject: [PATCH 2/2] apply code review suggestions

---
 llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp | 2 +-
 llvm/lib/Target/SPIRV/SPIRVSubtarget.h   | 5 ++---
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
index fc31bbd06387c3..3587570931541e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
@@ -158,7 +158,7 @@ void SPIRVSubtarget::initAvailableExtInstSets() {
 
 // Set available extensions after SPIRVSubtarget is created.
 void SPIRVSubtarget::initAvailableExtensions(
-    std::set<SPIRV::Extension::Extension> AllowedExtIds) {
+    const std::set<SPIRV::Extension::Extension> &AllowedExtIds) {
   AvailableExtensions.clear();
   AvailableExtensions.insert(AllowedExtIds.begin(), AllowedExtIds.end());
 
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index eb289b7aa38f3e..e4484f6508b6b9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -59,7 +59,6 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
 
   // TODO: Initialise the available extensions, extended instruction sets
   // based on the environment settings.
-  void initAvailableExtensions();
   void initAvailableExtInstSets();
   void accountForAMDShaderTrinaryMinmax();
 
@@ -70,8 +69,8 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
                  const std::string &FS, const SPIRVTargetMachine &TM);
   SPIRVSubtarget &initSubtargetDependencies(StringRef CPU, StringRef FS);
 
-  void
-  initAvailableExtensions(std::set<SPIRV::Extension::Extension> AllowedExtIds);
+  void initAvailableExtensions(
+      const std::set<SPIRV::Extension::Extension> &AllowedExtIds);
 
   // Parses features string setting specified subtarget options.
   // The definition of this function is auto generated by tblgen.



More information about the llvm-commits mailing list