Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 36 additions & 47 deletions llvm/lib/Target/SPIRV/SPIRVAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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, []() {
Expand All @@ -75,50 +57,26 @@ 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);
if (!UnknownExt.empty()) {
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);
Expand All @@ -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());

Expand Down Expand Up @@ -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
5 changes: 5 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 17 additions & 9 deletions llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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(
const std::set<SPIRV::Extension::Extension> &AllowedExtIds) {
AvailableExtensions.clear();
AvailableExtensions.insert(AllowedExtIds.begin(), AllowedExtIds.end());

accountForAMDShaderTrinaryMinmax();
}
5 changes: 4 additions & 1 deletion llvm/lib/Target/SPIRV/SPIRVSubtarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {

// TODO: Initialise the available extensions, extended instruction sets
// based on the environment settings.
void initAvailableExtensions();
void initAvailableExtInstSets();
void accountForAMDShaderTrinaryMinmax();

public:
// This constructor initializes the data members to match that
Expand All @@ -69,6 +69,9 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
const std::string &FS, const SPIRVTargetMachine &TM);
SPIRVSubtarget &initSubtargetDependencies(StringRef CPU, StringRef FS);

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.
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/Target/SPIRV/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
SPIRVCodeGen
SPIRVAnalysis
Support
TargetParser
)

add_llvm_target_unittest(SPIRVTests
Expand Down
Loading