Skip to content

Commit df122fc

Browse files
[SPIR-V] Change a way SPIR-V Backend API works with user facing options (#124745)
This PR fixes #124703: * added a new API call `SPIRVTranslate` that is to replace entirely old `SPIRVTranslateModule` after existing clients switch into the new function; * the new `SPIRVTranslate` doesn't require option parsing, replacing the `Opts` argument with explicit `CodeGenOptLevel` and `Triple` arguments; * the old `SPIRVTranslateModule` call is a wrapper for `SPIRVTranslate`, it doesn't require option parsing either and doesn't hold any logic inside except for converting string options into `CodeGenOptLevel` and `Triple` arguments; * usage of the extensions list is reworked to avoid writes to the global cl::opt variable `lib/Target/SPIRV/SPIRVSubtarget.cpp::Extensions` -- instead a new class member in SPIRVSubtarget.cpp is implemented that allows to replace supported extensions after SPIRVSubtarget.cpp is created; * both API calls don't require option parsing and don't write to global cl::opt variables. Other related/required changes: * SPIRV::Capability::Shader is marked as an capability of lesser priority for OpenCL environment (to remediate absence of the "avoid-spirv-capabilities" command line option in API calls); * unit tests are updated and extended to cover testing of a newer API call; * old API call is marked with TODO to remove it after existing clients switch into the new function.
1 parent a58e774 commit df122fc

File tree

7 files changed

+207
-111
lines changed

7 files changed

+207
-111
lines changed

llvm/lib/Target/SPIRV/SPIRVAPI.cpp

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "SPIRVCommandLine.h"
1010
#include "SPIRVSubtarget.h"
11+
#include "SPIRVTargetMachine.h"
1112
#include "llvm/Analysis/TargetLibraryInfo.h"
1213
#include "llvm/CodeGen/CommandFlags.h"
1314
#include "llvm/CodeGen/MachineFunctionPass.h"
@@ -40,25 +41,6 @@ using namespace llvm;
4041

4142
namespace {
4243

43-
// Mimic limited number of command line flags from llc to provide a better
44-
// user experience when passing options into the translate API call.
45-
static cl::opt<char> SpirvOptLevel("spirv-O", cl::Hidden, cl::Prefix,
46-
cl::init('0'));
47-
static cl::opt<std::string> SpirvTargetTriple("spirv-mtriple", cl::Hidden,
48-
cl::init(""));
49-
50-
// Utility to accept options in a command line style.
51-
void parseSPIRVCommandLineOptions(const std::vector<std::string> &Options,
52-
raw_ostream *Errs) {
53-
static constexpr const char *Origin = "SPIRVTranslateModule";
54-
if (!Options.empty()) {
55-
std::vector<const char *> Argv(1, Origin);
56-
for (const auto &Arg : Options)
57-
Argv.push_back(Arg.c_str());
58-
cl::ParseCommandLineOptions(Argv.size(), Argv.data(), Origin, Errs);
59-
}
60-
}
61-
6244
std::once_flag InitOnceFlag;
6345
void InitializeSPIRVTarget() {
6446
std::call_once(InitOnceFlag, []() {
@@ -75,50 +57,26 @@ namespace llvm {
7557
// The goal of this function is to facilitate integration of SPIRV Backend into
7658
// tools and libraries by means of exposing an API call that translate LLVM
7759
// module to SPIR-V and write results into a string as binary SPIR-V output,
78-
// providing diagnostics on fail and means of configuring translation in a style
79-
// of command line options.
60+
// providing diagnostics on fail and means of configuring translation.
8061
extern "C" LLVM_EXTERNAL_VISIBILITY bool
81-
SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
82-
const std::vector<std::string> &AllowExtNames,
83-
const std::vector<std::string> &Opts) {
62+
SPIRVTranslate(Module *M, std::string &SpirvObj, std::string &ErrMsg,
63+
const std::vector<std::string> &AllowExtNames,
64+
llvm::CodeGenOptLevel OLevel, Triple TargetTriple) {
8465
// Fallbacks for option values.
8566
static const std::string DefaultTriple = "spirv64-unknown-unknown";
8667
static const std::string DefaultMArch = "";
8768

88-
// Parse Opts as if it'd be command line arguments.
89-
std::string Errors;
90-
raw_string_ostream ErrorStream(Errors);
91-
parseSPIRVCommandLineOptions(Opts, &ErrorStream);
92-
if (!Errors.empty()) {
93-
ErrMsg = Errors;
94-
return false;
95-
}
96-
97-
llvm::CodeGenOptLevel OLevel;
98-
if (auto Level = CodeGenOpt::parseLevel(SpirvOptLevel)) {
99-
OLevel = *Level;
100-
} else {
101-
ErrMsg = "Invalid optimization level!";
102-
return false;
103-
}
104-
105-
// Overrides/ammends `-spirv-ext` command line switch (if present) by the
106-
// explicit list of allowed SPIR-V extensions.
10769
std::set<SPIRV::Extension::Extension> AllowedExtIds;
10870
StringRef UnknownExt =
10971
SPIRVExtensionsParser::checkExtensions(AllowExtNames, AllowedExtIds);
11072
if (!UnknownExt.empty()) {
11173
ErrMsg = "Unknown SPIR-V extension: " + UnknownExt.str();
11274
return false;
11375
}
114-
SPIRVSubtarget::addExtensionsToClOpt(AllowedExtIds);
11576

11677
// SPIR-V-specific target initialization.
11778
InitializeSPIRVTarget();
11879

119-
Triple TargetTriple(SpirvTargetTriple.empty()
120-
? M->getTargetTriple()
121-
: Triple::normalize(SpirvTargetTriple));
12280
if (TargetTriple.getTriple().empty()) {
12381
TargetTriple.setTriple(DefaultTriple);
12482
M->setTargetTriple(DefaultTriple);
@@ -142,6 +100,11 @@ SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
142100
return false;
143101
}
144102

103+
// Set available extensions.
104+
SPIRVTargetMachine *STM = static_cast<SPIRVTargetMachine *>(Target.get());
105+
const_cast<SPIRVSubtarget *>(STM->getSubtargetImpl())
106+
->initAvailableExtensions(AllowedExtIds);
107+
145108
if (M->getCodeModel())
146109
Target->setCodeModel(*M->getCodeModel());
147110

@@ -177,4 +140,30 @@ SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
177140
return true;
178141
}
179142

143+
// TODO: Remove this wrapper after existing clients switch into a newer
144+
// implementation of SPIRVTranslate().
145+
extern "C" LLVM_EXTERNAL_VISIBILITY bool
146+
SPIRVTranslateModule(Module *M, std::string &SpirvObj, std::string &ErrMsg,
147+
const std::vector<std::string> &AllowExtNames,
148+
const std::vector<std::string> &Opts) {
149+
// optional: Opts[0] is a string representation of Triple,
150+
// take Module triple otherwise
151+
Triple TargetTriple(Opts.empty() || Opts[0].empty()
152+
? M->getTargetTriple()
153+
: Triple::normalize(Opts[0]));
154+
// optional: Opts[1] is a string representation of CodeGenOptLevel,
155+
// no optimization otherwise
156+
llvm::CodeGenOptLevel OLevel = CodeGenOptLevel::None;
157+
if (Opts.size() > 1 && !Opts[1].empty()) {
158+
if (auto Level = CodeGenOpt::parseLevel(Opts[1][0])) {
159+
OLevel = *Level;
160+
} else {
161+
ErrMsg = "Invalid optimization level!";
162+
return false;
163+
}
164+
}
165+
return SPIRVTranslate(M, SpirvObj, ErrMsg, AllowExtNames, OLevel,
166+
TargetTriple);
167+
}
168+
180169
} // namespace llvm

llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ llvm::StringRef SPIRVExtensionsParser::checkExtensions(
133133
const std::vector<std::string> &ExtNames,
134134
std::set<SPIRV::Extension::Extension> &AllowedExtensions) {
135135
for (const auto &Ext : ExtNames) {
136+
if (Ext == "all") {
137+
for (const auto &[ExtensionName, ExtensionEnum] : SPIRVExtensionMap)
138+
AllowedExtensions.insert(ExtensionEnum);
139+
break;
140+
}
136141
auto It = SPIRVExtensionMap.find(Ext);
137142
if (It == SPIRVExtensionMap.end())
138143
return Ext;

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,10 @@ static SPIRV::Requirements
7373
getSymbolicOperandRequirements(SPIRV::OperandCategory::OperandCategory Category,
7474
unsigned i, const SPIRVSubtarget &ST,
7575
SPIRV::RequirementHandler &Reqs) {
76-
static AvoidCapabilitiesSet
77-
AvoidCaps; // contains capabilities to avoid if there is another option
76+
// A set of capabilities to avoid if there is another option.
77+
AvoidCapabilitiesSet AvoidCaps;
78+
if (ST.isOpenCLEnv())
79+
AvoidCaps.S.insert(SPIRV::Capability::Shader);
7880

7981
VersionTuple ReqMinVer = getSymbolicOperandMinVersion(Category, i);
8082
VersionTuple ReqMaxVer = getSymbolicOperandMaxVersion(Category, i);

llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU,
8484
OpenCLVersion = VersionTuple(2, 2);
8585

8686
// The order of initialization is important.
87-
initAvailableExtensions();
87+
initAvailableExtensions(Extensions);
8888
initAvailableExtInstSets();
8989

9090
GR = std::make_unique<SPIRVGlobalRegistry>(PointerSize);
@@ -135,9 +135,12 @@ bool SPIRVSubtarget::canDirectlyComparePointers() const {
135135
return !SPVTranslatorCompat && isAtLeastVer(SPIRVVersion, VersionTuple(1, 4));
136136
}
137137

138-
void SPIRVSubtarget::initAvailableExtensions() {
139-
AvailableExtensions.clear();
140-
AvailableExtensions.insert(Extensions.begin(), Extensions.end());
138+
void SPIRVSubtarget::accountForAMDShaderTrinaryMinmax() {
139+
if (canUseExtension(
140+
SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) {
141+
AvailableExtInstSets.insert(
142+
SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax);
143+
}
141144
}
142145

143146
// TODO: use command line args for this rather than just defaults.
@@ -150,9 +153,14 @@ void SPIRVSubtarget::initAvailableExtInstSets() {
150153
AvailableExtInstSets.insert(SPIRV::InstructionSet::OpenCL_std);
151154

152155
// Handle extended instruction sets from extensions.
153-
if (canUseExtension(
154-
SPIRV::Extension::SPV_AMD_shader_trinary_minmax_extension)) {
155-
AvailableExtInstSets.insert(
156-
SPIRV::InstructionSet::SPV_AMD_shader_trinary_minmax);
157-
}
156+
accountForAMDShaderTrinaryMinmax();
157+
}
158+
159+
// Set available extensions after SPIRVSubtarget is created.
160+
void SPIRVSubtarget::initAvailableExtensions(
161+
const std::set<SPIRV::Extension::Extension> &AllowedExtIds) {
162+
AvailableExtensions.clear();
163+
AvailableExtensions.insert(AllowedExtIds.begin(), AllowedExtIds.end());
164+
165+
accountForAMDShaderTrinaryMinmax();
158166
}

llvm/lib/Target/SPIRV/SPIRVSubtarget.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ class SPIRVSubtarget : public SPIRVGenSubtargetInfo {
5959

6060
// TODO: Initialise the available extensions, extended instruction sets
6161
// based on the environment settings.
62-
void initAvailableExtensions();
6362
void initAvailableExtInstSets();
63+
void accountForAMDShaderTrinaryMinmax();
6464

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

72+
void initAvailableExtensions(
73+
const std::set<SPIRV::Extension::Extension> &AllowedExtIds);
74+
7275
// Parses features string setting specified subtarget options.
7376
// The definition of this function is auto generated by tblgen.
7477
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);

llvm/unittests/Target/SPIRV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
1111
SPIRVCodeGen
1212
SPIRVAnalysis
1313
Support
14+
TargetParser
1415
)
1516

1617
add_llvm_target_unittest(SPIRVTests

0 commit comments

Comments
 (0)