[llvm] bca2b6d - [SPIR-V] Expose an API call to initialize SPIRV target and translate input LLVM IR module to SPIR-V (#107216)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 10 06:51:27 PDT 2024
Author: Vyacheslav Levytskyy
Date: 2024-09-10T15:51:20+02:00
New Revision: bca2b6d23f69c21d933f461ea69a2add9ae6a623
URL: https://github.com/llvm/llvm-project/commit/bca2b6d23f69c21d933f461ea69a2add9ae6a623
DIFF: https://github.com/llvm/llvm-project/commit/bca2b6d23f69c21d933f461ea69a2add9ae6a623.diff
LOG: [SPIR-V] Expose an API call to initialize SPIRV target and translate input LLVM IR module to SPIR-V (#107216)
The goal of this PR is to facilitate integration of SPIRV Backend into
misc 3rd party 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.
An example of a use case may be Khronos Translator that provides
bidirectional translation LLVM IR <=> SPIR-V, where LLVM IR => SPIR-V
step may be substituted by the call to SPIR-V Backend API, implemented
by this PR.
Added:
llvm/lib/Target/SPIRV/SPIRVAPI.cpp
llvm/lib/Target/SPIRV/SPIRVAPI.h
llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
Modified:
llvm/lib/Target/SPIRV/CMakeLists.txt
llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
llvm/lib/Target/SPIRV/SPIRVCommandLine.h
llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
llvm/lib/Target/SPIRV/SPIRVSubtarget.h
llvm/unittests/Target/SPIRV/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt
index 5f8aea5fc8d84d..df7869b1552caa 100644
--- a/llvm/lib/Target/SPIRV/CMakeLists.txt
+++ b/llvm/lib/Target/SPIRV/CMakeLists.txt
@@ -14,6 +14,7 @@ tablegen(LLVM SPIRVGenTables.inc -gen-searchable-tables)
add_public_tablegen_target(SPIRVCommonTableGen)
add_llvm_target(SPIRVCodeGen
+ SPIRVAPI.cpp
SPIRVAsmPrinter.cpp
SPIRVBuiltins.cpp
SPIRVCallLowering.cpp
diff --git a/llvm/lib/Target/SPIRV/SPIRVAPI.cpp b/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
new file mode 100644
index 00000000000000..a6720d63c63b88
--- /dev/null
+++ b/llvm/lib/Target/SPIRV/SPIRVAPI.cpp
@@ -0,0 +1,181 @@
+//===-- SPIRVAPI.cpp - SPIR-V Backend API ---------------------*- C++ -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SPIRVCommandLine.h"
+#include "SPIRVSubtarget.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+#include "llvm/TargetParser/Triple.h"
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+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> SpvOptLevel(" O", cl::Hidden, cl::Prefix, cl::init('0'));
+static cl::opt<std::string> SpvTargetTriple(" 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, []() {
+ LLVMInitializeSPIRVTargetInfo();
+ LLVMInitializeSPIRVTarget();
+ LLVMInitializeSPIRVTargetMC();
+ LLVMInitializeSPIRVAsmPrinter();
+ });
+}
+} // namespace
+
+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.
+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) {
+ // 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(SpvOptLevel)) {
+ 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);
+ if (!UnknownExt.empty()) {
+ ErrMsg = "Unknown SPIR-V extension: " + UnknownExt.str();
+ return false;
+ }
+ SPIRVSubtarget::addExtensionsToClOpt(AllowedExtIds);
+
+ // SPIR-V-specific target initialization.
+ InitializeSPIRVTarget();
+
+ Triple TargetTriple(SpvTargetTriple.empty()
+ ? M->getTargetTriple()
+ : Triple::normalize(SpvTargetTriple));
+ if (TargetTriple.getTriple().empty()) {
+ TargetTriple.setTriple(DefaultTriple);
+ M->setTargetTriple(DefaultTriple);
+ }
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(DefaultMArch, TargetTriple, ErrMsg);
+ if (!TheTarget)
+ return false;
+
+ // A call to codegen::InitTargetOptionsFromCodeGenFlags(TargetTriple)
+ // hits the following assertion: llvm/lib/CodeGen/CommandFlags.cpp:78:
+ // llvm::FPOpFusion::FPOpFusionMode llvm::codegen::getFuseFPOps(): Assertion
+ // `FuseFPOpsView && "RegisterCodeGenFlags not created."' failed.
+ TargetOptions Options;
+ std::optional<Reloc::Model> RM;
+ std::optional<CodeModel::Model> CM;
+ std::unique_ptr<TargetMachine> Target =
+ std::unique_ptr<TargetMachine>(TheTarget->createTargetMachine(
+ TargetTriple.getTriple(), "", "", Options, RM, CM, OLevel));
+ if (!Target) {
+ ErrMsg = "Could not allocate target machine!";
+ return false;
+ }
+
+ if (M->getCodeModel())
+ Target->setCodeModel(*M->getCodeModel());
+
+ std::string DLStr = M->getDataLayoutStr();
+ Expected<DataLayout> MaybeDL = DataLayout::parse(
+ DLStr.empty() ? Target->createDataLayout().getStringRepresentation()
+ : DLStr);
+ if (!MaybeDL) {
+ ErrMsg = toString(MaybeDL.takeError());
+ return false;
+ }
+ M->setDataLayout(MaybeDL.get());
+
+ TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
+ legacy::PassManager PM;
+ PM.add(new TargetLibraryInfoWrapperPass(TLII));
+ LLVMTargetMachine &LLVMTM = static_cast<LLVMTargetMachine &>(*Target);
+ MachineModuleInfoWrapperPass *MMIWP =
+ new MachineModuleInfoWrapperPass(&LLVMTM);
+ const_cast<TargetLoweringObjectFile *>(LLVMTM.getObjFileLowering())
+ ->Initialize(MMIWP->getMMI().getContext(), *Target);
+
+ SmallString<4096> OutBuffer;
+ raw_svector_ostream OutStream(OutBuffer);
+ if (Target->addPassesToEmitFile(PM, OutStream, nullptr,
+ CodeGenFileType::ObjectFile)) {
+ ErrMsg = "Target machine cannot emit a file of this type";
+ return false;
+ }
+
+ PM.run(*M);
+ SpirvObj = OutBuffer.str();
+
+ return true;
+}
+
+} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVAPI.h b/llvm/lib/Target/SPIRV/SPIRVAPI.h
new file mode 100644
index 00000000000000..cd41b8e595a654
--- /dev/null
+++ b/llvm/lib/Target/SPIRV/SPIRVAPI.h
@@ -0,0 +1,24 @@
+//===-- SPIRVAPI.h - SPIR-V Backend API interface ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVAPI_H
+#define LLVM_LIB_TARGET_SPIRV_SPIRVAPI_H
+
+#include <string>
+#include <vector>
+
+namespace llvm {
+class Module;
+
+extern "C" bool
+SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
+ const std::vector<std::string> &AllowExtNames,
+ const std::vector<std::string> &Opts);
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_SPIRV_SPIRVAPI_H
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
index 90a9ab1d33ced4..127585f85915fb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
@@ -113,3 +113,15 @@ bool SPIRVExtensionsParser::parse(cl::Option &O, llvm::StringRef ArgName,
Vals = std::move(EnabledExtensions);
return false;
}
+
+llvm::StringRef SPIRVExtensionsParser::checkExtensions(
+ const std::vector<std::string> &ExtNames,
+ std::set<SPIRV::Extension::Extension> &AllowedExtensions) {
+ for (const auto &Ext : ExtNames) {
+ auto It = SPIRVExtensionMap.find(Ext);
+ if (It == SPIRVExtensionMap.end())
+ return Ext;
+ AllowedExtensions.insert(It->second);
+ }
+ return StringRef();
+}
diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.h b/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
index 741d829b2ab8f9..8df2968eb6fe12 100644
--- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
+++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.h
@@ -17,8 +17,10 @@
#include "MCTargetDesc/SPIRVBaseInfo.h"
#include "llvm/Support/CommandLine.h"
#include <set>
+#include <string>
namespace llvm {
+class StringRef;
/// Command line parser for toggling SPIR-V extensions.
struct SPIRVExtensionsParser
@@ -32,6 +34,14 @@ struct SPIRVExtensionsParser
/// \return Returns true on error.
bool parse(cl::Option &O, StringRef ArgName, StringRef ArgValue,
std::set<SPIRV::Extension::Extension> &Vals);
+
+ /// Validates and converts extension names into internal enum values.
+ ///
+ /// \return Returns a reference to the unknown SPIR-V extension name from the
+ /// list if present, or an empty StringRef on success.
+ static llvm::StringRef
+ checkExtensions(const std::vector<std::string> &ExtNames,
+ std::set<SPIRV::Extension::Extension> &AllowedExtensions);
};
} // namespace llvm
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
index 27472923ee08c8..d31673bff5947c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
@@ -38,6 +38,13 @@ static cl::opt<std::set<SPIRV::Extension::Extension>, false,
Extensions("spirv-ext",
cl::desc("Specify list of enabled SPIR-V extensions"));
+// Provides access to the cl::opt<...> `Extensions` variable from outside of the
+// module.
+void SPIRVSubtarget::addExtensionsToClOpt(
+ const std::set<SPIRV::Extension::Extension> &AllowList) {
+ Extensions.insert(AllowList.begin(), AllowList.end());
+}
+
// Compare version numbers, but allow 0 to mean unspecified.
static bool isAtLeastVer(VersionTuple Target, VersionTuple VerToCompareTo) {
return Target.empty() || Target >= VerToCompareTo;
diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
index 82ec3cc95cdd3f..984ba953e874f5 100644
--- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
+++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h
@@ -130,6 +130,12 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
}
static constexpr unsigned MaxLegalAddressSpace = 6;
+
+ // Adds known SPIR-V extensions to the global list of allowed extensions that
+ // SPIRVSubtarget module owns as
+ // cl::opt<std::set<SPIRV::Extension::Extension>, ...> global variable.
+ static void
+ addExtensionsToClOpt(const std::set<SPIRV::Extension::Extension> &AllowList);
};
} // namespace llvm
diff --git a/llvm/unittests/Target/SPIRV/CMakeLists.txt b/llvm/unittests/Target/SPIRV/CMakeLists.txt
index 83ae215c512ca2..e9fe4883e5b024 100644
--- a/llvm/unittests/Target/SPIRV/CMakeLists.txt
+++ b/llvm/unittests/Target/SPIRV/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories(
set(LLVM_LINK_COMPONENTS
Analysis
AsmParser
+ BinaryFormat
Core
SPIRVCodeGen
SPIRVAnalysis
@@ -14,5 +15,6 @@ set(LLVM_LINK_COMPONENTS
add_llvm_target_unittest(SPIRVTests
SPIRVConvergenceRegionAnalysisTests.cpp
+ SPIRVAPITest.cpp
)
diff --git a/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp b/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
new file mode 100644
index 00000000000000..27ea8b8cf06e8d
--- /dev/null
+++ b/llvm/unittests/Target/SPIRV/SPIRVAPITest.cpp
@@ -0,0 +1,191 @@
+//===- llvm/unittest/CodeGen/SPIRVAPITest.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Test that SPIR-V Backend provides an API call that translates LLVM IR Module
+/// into SPIR-V.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+#include <gmock/gmock.h>
+#include <string>
+#include <utility>
+
+using ::testing::StartsWith;
+
+namespace llvm {
+
+extern "C" bool
+SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
+ const std::vector<std::string> &AllowExtNames,
+ const std::vector<std::string> &Opts);
+
+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) {
+ SMDiagnostic ParseError;
+ M = parseAssemblyString(Assembly, ParseError, Context);
+ if (!M) {
+ ParseError.print("IR parsing failed: ", errs());
+ report_fatal_error("Can't parse input assembly.");
+ }
+ bool Status =
+ SPIRVTranslateModule(M.get(), Result, ErrMsg, AllowExtNames, Opts);
+ if (!Status)
+ errs() << ErrMsg;
+ return Status;
+ }
+
+ LLVMContext Context;
+ std::unique_ptr<Module> M;
+
+ static constexpr StringRef ExtensionAssembly = R"(
+ define dso_local spir_func void @test1() {
+ entry:
+ %res1 = tail call spir_func i32 @_Z26__spirv_GroupBitwiseAndKHR(i32 2, i32 0, i32 0)
+ ret void
+ }
+
+ declare dso_local spir_func i32 @_Z26__spirv_GroupBitwiseAndKHR(i32, i32, i32)
+ )";
+ static constexpr StringRef OkAssembly = R"(
+ %struct = type { [1 x i64] }
+
+ define spir_kernel void @foo(ptr noundef byval(%struct) %arg) {
+ entry:
+ call spir_func void @bar(<2 x i32> noundef <i32 0, i32 1>)
+ ret void
+ }
+
+ define spir_func void @bar(<2 x i32> noundef) {
+ entry:
+ ret void
+ }
+ )";
+};
+
+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[] = {
+ {}, {"- 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);
+ }
+ }
+}
+
+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, {}, {"- 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, {});
+ EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+ EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+}
+
+TEST_F(SPIRVAPITest, checkTranslateSupportExtensionByArgList) {
+ std::string Result, Error;
+ 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, {});
+ 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);
+ EXPECT_TRUE(Status && Error.empty() && !Result.empty());
+ EXPECT_EQ(identify_magic(Result), file_magic::spirv_object);
+}
+
+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, {});
+ 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, checkTranslateExtensionError) {
+ std::string Result, Error;
+ std::vector<std::string> Opts;
+ EXPECT_DEATH_IF_SUPPORTED(
+ { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
+ "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
+ "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
+}
+
+TEST_F(SPIRVAPITest, checkTranslateUnknownExtensionByOpts) {
+ std::string Result, Error;
+ std::vector<std::string> Opts{"--spirv-ext=+SPV_XYZ_my_unknown_extension"};
+ EXPECT_DEATH_IF_SUPPORTED(
+ { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
+ "SPIRVTranslateModule: for the --spirv-ext option: Unknown SPIR-V");
+}
+
+TEST_F(SPIRVAPITest, checkTranslateWrongExtensionByOpts) {
+ std::string Result, Error;
+ std::vector<std::string> Opts{"--spirv-ext=+SPV_KHR_subgroup_rotate"};
+ EXPECT_DEATH_IF_SUPPORTED(
+ { toSpirv(ExtensionAssembly, Result, Error, {}, Opts); },
+ "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
+ "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
+}
+
+TEST_F(SPIRVAPITest, checkTranslateWrongExtensionByArg) {
+ std::string Result, Error;
+ std::vector<std::string> ExtNames{"SPV_KHR_subgroup_rotate"};
+ EXPECT_DEATH_IF_SUPPORTED(
+ { toSpirv(ExtensionAssembly, Result, Error, ExtNames, {}); },
+ "LLVM ERROR: __spirv_GroupBitwiseAndKHR: the builtin requires the "
+ "following SPIR-V extension: SPV_KHR_uniform_group_instructions");
+}
+#endif
+
+} // end namespace llvm
More information about the llvm-commits
mailing list