Skip to content

Commit 281c726

Browse files
authored
Support specifying SPIRV extensions via -spirv-ext= flag (#626)
This flag specifies list of allowed/disallowed SPIRV extensions when generating SPIRV. It is a comma-separated list of extensions prefixed with '+' or '-'. Its syntax is exactly the same as `-spirv-ext=` flag of llvm-spirv tool from SPIRV-LLVM-Translator repo. If `-spirv-ext=` is omitted, all SPIRV extensions are enabled (same as previous behavior). (cherry picked from commit 1369172)
1 parent e77121d commit 281c726

3 files changed

Lines changed: 101 additions & 9 deletions

File tree

opencl_clang.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Copyright (c) Intel Corporation (2009-2017).
5555
// in https://github.com/KhronosGroup/OpenCL-Headers/blob/master/CL/cl.h
5656
#define CL_SUCCESS 0
5757
#define CL_COMPILE_PROGRAM_FAILURE -15
58+
#define CL_INVALID_BUILD_OPTIONS -43
5859
#define CL_OUT_OF_HOST_MEMORY -6
5960

6061
#include "assert.h"
@@ -208,7 +209,11 @@ Compile(const char *pszProgramSource, const char **pInputHeaders,
208209
llvm::sys::SmartScopedLock<true> compileGuard{*compileMutex};
209210
#endif
210211
// Parse options
211-
optionsParser.processOptions(pszOptions, pszOptionsEx);
212+
if (optionsParser.processOptions(pszOptions, pszOptionsEx) != 0) {
213+
if (pBinaryResult)
214+
*pBinaryResult = nullptr;
215+
return CL_INVALID_BUILD_OPTIONS;
216+
}
212217

213218
// Prepare our diagnostic client.
214219
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagID(
@@ -313,8 +318,10 @@ Compile(const char *pszProgramSource, const char **pInputHeaders,
313318
SmallVectorBuffer StreamBuf(pResult->getIRBufferRef());
314319
std::ostream OS(&StreamBuf);
315320
std::string Err;
316-
SPIRV::TranslatorOpts SPIRVOpts;
317-
SPIRVOpts.enableAllExtensions();
321+
SPIRV::TranslatorOpts SPIRVOpts(SPIRV::VersionNumber::MaximumVersion,
322+
optionsParser.getSPIRVExtStatusMap());
323+
if (!optionsParser.hasSPIRVExt())
324+
SPIRVOpts.enableAllExtensions();
318325
if (!optionsParser.hasOptDisable()) {
319326
SPIRVOpts.setMemToRegEnabled(true);
320327
}

options.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Copyright (c) Intel Corporation (2009-2017).
2727
#include "llvm/Option/ArgList.h"
2828
#include "llvm/Option/Option.h"
2929
#include "clang/Basic/OpenCLOptions.h"
30+
#include "LLVMSPIRVOpts.h"
3031

3132
#include <list>
3233

@@ -160,7 +161,7 @@ class CompileOptionsParser {
160161
// Validates and prepares the effective options to pass to clang upon
161162
// compilation
162163
//
163-
void processOptions(const char *pszOptions, const char *pszOptionsEx);
164+
int processOptions(const char *pszOptions, const char *pszOptionsEx);
164165

165166
//
166167
// Just validates the user supplied OpenCL compile options
@@ -186,6 +187,13 @@ class CompileOptionsParser {
186187
std::string getEffectiveOptionsAsString() const;
187188

188189
bool hasEmitSPIRV() const { return m_emitSPIRV; }
190+
191+
bool hasSPIRVExt() const { return m_hasSPIRVExt; }
192+
193+
SPIRV::TranslatorOpts::ExtensionsStatusMap getSPIRVExtStatusMap() const {
194+
return m_SPIRVExtStatusMap;
195+
}
196+
189197
bool hasOptDisable() const { return m_optDisable; }
190198

191199
private:
@@ -195,6 +203,8 @@ class CompileOptionsParser {
195203
llvm::SmallVector<const char *, 16> m_effectiveArgsRaw;
196204
std::string m_sourceName;
197205
bool m_emitSPIRV;
206+
bool m_hasSPIRVExt = false;
207+
SPIRV::TranslatorOpts::ExtensionsStatusMap m_SPIRVExtStatusMap = {};
198208
bool m_optDisable;
199209
};
200210

options_compile.cpp

Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,70 @@ OpenCLCompileOptTable::OpenCLCompileOptTable()
6262

6363
int EffectiveOptionsFilter::s_progID = 1;
6464

65+
// This code was adopted from the SPIRV-LLVM-Translator repository.
66+
static int parseSPVExtOption(
67+
llvm::StringRef SPVExt,
68+
SPIRV::TranslatorOpts::ExtensionsStatusMap &ExtensionsStatus) {
69+
// Map name -> id for known extensions
70+
std::map<llvm::StringRef, SPIRV::ExtensionID> ExtensionNamesMap;
71+
#define _STRINGIFY(X) #X
72+
#define STRINGIFY(X) _STRINGIFY(X)
73+
#define EXT(X) ExtensionNamesMap[STRINGIFY(X)] = SPIRV::ExtensionID::X;
74+
#include "LLVMSPIRVExtensions.inc"
75+
#undef EXT
76+
#undef STRINGIFY
77+
#undef _STRINGIFY
78+
79+
// Set the initial state: assume that any known extension is disallowed.
80+
std::optional<bool> DefaultVal;
81+
for (const auto &It : ExtensionNamesMap)
82+
ExtensionsStatus[It.second] = DefaultVal;
83+
84+
llvm::SmallVector<llvm::StringRef, 32> SPVExtList;
85+
llvm::SplitString(SPVExt, SPVExtList, ",");
86+
87+
if (SPVExtList.empty())
88+
return 0; // Nothing to do
89+
90+
for (unsigned i = 0; i < SPVExtList.size(); ++i) {
91+
llvm::StringRef ExtString = SPVExtList[i];
92+
if (ExtString.empty() ||
93+
('+' != ExtString.front() && '-' != ExtString.front())) {
94+
llvm::errs() << "Invalid value of --spirv-ext, expected format is:\n"
95+
<< "\t--spirv-ext=+EXT_NAME,-EXT_NAME\n";
96+
return -1;
97+
}
98+
99+
auto ExtName = ExtString.substr(1);
100+
101+
if (ExtName.empty()) {
102+
llvm::errs() << "Invalid value of --spirv-ext, expected format is:\n"
103+
<< "\t--spirv-ext=+EXT_NAME,-EXT_NAME\n";
104+
return -1;
105+
}
106+
107+
bool ExtStatus = ('+' == ExtString.front());
108+
if ("all" == ExtName) {
109+
// Update status for all known extensions
110+
for (const auto &It : ExtensionNamesMap)
111+
ExtensionsStatus[It.second] = ExtStatus;
112+
} else {
113+
// Reject unknown extensions
114+
const auto &It = ExtensionNamesMap.find(ExtName);
115+
if (ExtensionNamesMap.end() == It) {
116+
llvm::errs() << "Unknown extension '" << ExtName
117+
<< "' was specified via "
118+
<< "--spirv-ext option\n";
119+
return -1;
120+
}
121+
122+
ExtensionsStatus[It->second] = ExtStatus;
123+
}
124+
}
125+
126+
return 0;
127+
}
128+
65129
///
66130
// Options filter that validates the opencl used options
67131
//
@@ -397,8 +461,8 @@ std::string EffectiveOptionsFilter::processOptions(const OpenCLArgList &args,
397461
return sourceName;
398462
}
399463

400-
void CompileOptionsParser::processOptions(const char *pszOptions,
401-
const char *pszOptionsEx) {
464+
int CompileOptionsParser::processOptions(const char *pszOptions,
465+
const char *pszOptionsEx) {
402466
// parse options
403467
unsigned missingArgIndex, missingArgCount;
404468
std::unique_ptr<OpenCLArgList> pArgs(
@@ -412,16 +476,27 @@ void CompileOptionsParser::processOptions(const char *pszOptions,
412476
for (ArgsVector::iterator it = m_effectiveArgs.begin(),
413477
end = m_effectiveArgs.end();
414478
it != end; ++it) {
415-
if (it->compare("-cl-opt-disable") == 0) {
479+
llvm::StringRef arg(*it);
480+
(void)arg.consume_front("-");
481+
// support -- prefix as well.
482+
(void)arg.consume_front("-");
483+
if (arg == "cl-opt-disable") {
416484
m_optDisable = true;
417-
}
418-
else if (it->compare("-emit-spirv") == 0) {
485+
} else if (arg == "emit-spirv") {
419486
m_effectiveArgsRaw.push_back("-emit-llvm-bc");
420487
m_emitSPIRV = true;
421488
continue;
489+
} else if (arg.consume_front("spirv-ext=")) {
490+
m_hasSPIRVExt = true;
491+
// m_SPIRVExtStatusMap will be initialized and updated according to `arg`.
492+
int ret = parseSPVExtOption(arg, m_SPIRVExtStatusMap);
493+
if (0 != ret)
494+
return ret;
495+
continue;
422496
}
423497
m_effectiveArgsRaw.push_back(it->c_str());
424498
}
499+
return 0;
425500
}
426501

427502
bool CompileOptionsParser::checkOptions(const char *pszOptions,

0 commit comments

Comments
 (0)