Skip to content

Commit 3a589a1

Browse files
authored
[SYCL][RTC] Rework handling of build_options (#17405)
Reject user-supplied arguments a bit more coarsely based on their kind or relation to an unsupported feature. --------- Signed-off-by: Julian Oppermann <[email protected]>
1 parent 0d5266b commit 3a589a1

File tree

6 files changed

+68
-102
lines changed

6 files changed

+68
-102
lines changed

sycl-jit/jit-compiler/include/KernelFusion.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,32 +86,37 @@ class RTCHashResult {
8686
sycl::detail::string HashOrLog;
8787
};
8888

89+
enum class RTCErrorCode { SUCCESS, BUILD, INVALID };
90+
8991
class RTCResult {
9092
public:
91-
explicit RTCResult(const char *BuildLog)
92-
: Failed{true}, BundleInfo{}, BuildLog{BuildLog} {}
93+
explicit RTCResult(const char *BuildLog,
94+
RTCErrorCode ErrorCode = RTCErrorCode::BUILD)
95+
: ErrorCode{ErrorCode}, BundleInfo{}, BuildLog{BuildLog} {
96+
assert(ErrorCode != RTCErrorCode::SUCCESS);
97+
}
9398

9499
RTCResult(RTCBundleInfo &&BundleInfo, RTCDeviceCodeIR &&DeviceCodeIR,
95100
const char *BuildLog)
96-
: Failed{false}, BundleInfo{std::move(BundleInfo)},
101+
: ErrorCode{RTCErrorCode::SUCCESS}, BundleInfo{std::move(BundleInfo)},
97102
DeviceCodeIR(std::move(DeviceCodeIR)), BuildLog{BuildLog} {}
98103

99-
bool failed() const { return Failed; }
104+
RTCErrorCode getErrorCode() const { return ErrorCode; }
100105

101106
const char *getBuildLog() const { return BuildLog.c_str(); }
102107

103108
const RTCBundleInfo &getBundleInfo() const {
104-
assert(!failed() && "No bundle info");
109+
assert(ErrorCode == RTCErrorCode::SUCCESS && "No bundle info");
105110
return BundleInfo;
106111
}
107112

108113
const RTCDeviceCodeIR &getDeviceCodeIR() const {
109-
assert(!failed() && "No device code IR");
114+
assert(ErrorCode == RTCErrorCode::SUCCESS && "No device code IR");
110115
return DeviceCodeIR;
111116
}
112117

113118
private:
114-
bool Failed;
119+
RTCErrorCode ErrorCode;
115120
RTCBundleInfo BundleInfo;
116121
RTCDeviceCodeIR DeviceCodeIR;
117122
sycl::detail::string BuildLog;

sycl-jit/jit-compiler/lib/KernelFusion.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ static std::string formatError(llvm::Error &&Err, const std::string &Msg) {
4545
return ErrMsg.str();
4646
}
4747

48-
template <typename ResultType>
49-
static ResultType errorTo(llvm::Error &&Err, const std::string &Msg) {
48+
template <typename ResultType, typename... ExtraArgTypes>
49+
static ResultType errorTo(llvm::Error &&Err, const std::string &Msg,
50+
ExtraArgTypes... ExtraArgs) {
5051
// Cannot throw an exception here if LLVM itself is compiled without exception
5152
// support.
52-
return ResultType{formatError(std::move(Err), Msg).c_str()};
53+
return ResultType{formatError(std::move(Err), Msg).c_str(), ExtraArgs...};
5354
}
5455

5556
static std::vector<jit_compiler::NDRange>
@@ -288,7 +289,8 @@ compileSYCL(InMemoryFile SourceFile, View<InMemoryFile> IncludeFiles,
288289
auto UserArgListOrErr = parseUserArgs(UserArgs);
289290
if (!UserArgListOrErr) {
290291
return errorTo<RTCResult>(UserArgListOrErr.takeError(),
291-
"Parsing of user arguments failed");
292+
"Parsing of user arguments failed",
293+
RTCErrorCode::INVALID);
292294
}
293295
llvm::opt::InputArgList UserArgList = std::move(*UserArgListOrErr);
294296

sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp

Lines changed: 27 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -321,20 +321,15 @@ static void adjustArgs(const InputArgList &UserArgList,
321321
DAL.AddJoinedArg(
322322
nullptr, OptTable.getOption(OPT_resource_dir_EQ),
323323
(DPCPPRoot + "/lib/clang/" + Twine(CLANG_VERSION_MAJOR)).str());
324-
for (auto *Arg : UserArgList) {
325-
DAL.append(Arg);
326-
}
327-
// Remove args that will trigger an unused command line argument warning for
328-
// the FrontendAction invocation, but are handled later (e.g. during device
329-
// linking).
330-
DAL.eraseArg(OPT_fsycl_device_lib_EQ);
331-
DAL.eraseArg(OPT_fno_sycl_device_lib_EQ);
332-
DAL.eraseArg(OPT_ftime_trace_EQ);
333-
DAL.eraseArg(OPT_ftime_trace_granularity_EQ);
334-
DAL.eraseArg(OPT_ftime_trace_verbose);
324+
// User args may contain options not intended for the frontend, but we can't
325+
// claim them here to tell the driver they're used later. Hence, suppress the
326+
// unused argument warning.
327+
DAL.AddFlagArg(nullptr, OptTable.getOption(OPT_Qunused_arguments));
335328

336329
ArgStringList ASL;
337330
for_each(DAL, [&DAL, &ASL](Arg *A) { A->render(DAL, ASL); });
331+
for_each(UserArgList,
332+
[&UserArgList, &ASL](Arg *A) { A->render(UserArgList, ASL); });
338333
transform(ASL, std::back_inserter(CommandLine),
339334
[](const char *AS) { return std::string{AS}; });
340335
}
@@ -811,51 +806,21 @@ jit_compiler::parseUserArgs(View<const char *> UserArgs) {
811806
UserArgsRef[MissingArgIndex], MissingArgIndex);
812807
}
813808

814-
// Check for unsupported options.
815-
// TODO: There are probably more, e.g. requesting non-SPIR-V targets.
816-
{
817-
// -fsanitize=address
818-
bool IsDeviceAsanEnabled = false;
819-
if (Arg *A = AL.getLastArg(OPT_fsanitize_EQ, OPT_fno_sanitize_EQ)) {
820-
if (A->getOption().matches(OPT_fsanitize_EQ) &&
821-
A->getValues().size() == 1) {
822-
std::string SanitizeVal = A->getValue();
823-
IsDeviceAsanEnabled = SanitizeVal == "address";
824-
}
825-
} else {
826-
// User can pass -fsanitize=address to device compiler via
827-
// -Xsycl-target-frontend.
828-
auto SyclFEArg = AL.getAllArgValues(OPT_Xsycl_frontend);
829-
IsDeviceAsanEnabled = (std::count(SyclFEArg.begin(), SyclFEArg.end(),
830-
"-fsanitize=address") > 0);
831-
if (!IsDeviceAsanEnabled) {
832-
auto SyclFEArgEq = AL.getAllArgValues(OPT_Xsycl_frontend_EQ);
833-
IsDeviceAsanEnabled =
834-
(std::count(SyclFEArgEq.begin(), SyclFEArgEq.end(),
835-
"-fsanitize=address") > 0);
836-
}
837-
838-
// User can also enable asan for SYCL device via -Xarch_device option.
839-
if (!IsDeviceAsanEnabled) {
840-
auto DeviceArchVals = AL.getAllArgValues(OPT_Xarch_device);
841-
for (auto DArchVal : DeviceArchVals) {
842-
if (DArchVal.find("-fsanitize=address") != std::string::npos) {
843-
IsDeviceAsanEnabled = true;
844-
break;
845-
}
846-
}
847-
}
848-
}
849-
850-
if (IsDeviceAsanEnabled) {
851-
return createStringError(
852-
"Device ASAN is not supported for runtime compilation");
853-
}
854-
}
855-
856-
if (!AL.hasFlag(OPT_fsycl_device_code_split_esimd,
857-
OPT_fno_sycl_device_code_split_esimd, true)) {
858-
return createStringError("ESIMD device code split cannot be deactivated");
809+
// Check for options that are unsupported because they would interfere with
810+
// the in-memory pipeline.
811+
Arg *UnsupportedArg =
812+
AL.getLastArg(OPT_Action_Group, // Actions like -c or -S
813+
OPT_Link_Group, // Linker flags
814+
OPT_o, // Output file
815+
OPT_fsycl_targets_EQ, // AoT compilation
816+
OPT_fsycl_link_EQ, // SYCL linker
817+
OPT_fno_sycl_device_code_split_esimd, // invoke_simd
818+
OPT_fsanitize_EQ // Sanitizer
819+
);
820+
if (UnsupportedArg) {
821+
return createStringError(
822+
"Option '%s' is not supported for SYCL runtime compilation",
823+
UnsupportedArg->getAsString(AL).c_str());
859824
}
860825

861826
return std::move(AL);
@@ -866,20 +831,14 @@ void jit_compiler::encodeBuildOptions(RTCBundleInfo &BundleInfo,
866831
std::string CompileOptions;
867832
raw_string_ostream COSOS{CompileOptions};
868833

869-
for (Arg *A : UserArgList.getArgs()) {
870-
if (!(A->getOption().matches(OPT_Xs) ||
871-
A->getOption().matches(OPT_Xs_separate))) {
872-
continue;
834+
for (Arg *A : UserArgList.filtered(OPT_Xs, OPT_Xs_separate)) {
835+
if (!CompileOptions.empty()) {
836+
COSOS << ' ';
873837
}
874-
875-
// Trim first and last quote if they exist, but no others.
876-
StringRef AV{A->getValue()};
877-
AV = AV.trim();
878-
if (AV.front() == AV.back() && (AV.front() == '\'' || AV.front() == '"')) {
879-
AV = AV.drop_front().drop_back();
838+
if (A->getOption().matches(OPT_Xs)) {
839+
COSOS << '-';
880840
}
881-
882-
COSOS << (CompileOptions.empty() ? "" : " ") << AV;
841+
COSOS << A->getValue();
883842
}
884843

885844
if (!CompileOptions.empty()) {

sycl/source/detail/jit_compiler.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,9 +1306,16 @@ std::pair<sycl_device_binaries, std::string> jit_compiler::compileSYCL(
13061306
auto Result = CompileSYCLHandle(SourceFile, IncludeFilesView, UserArgsView,
13071307
CachedIR, /*SaveIR=*/!CacheKey.empty());
13081308

1309-
appendToLog(Result.getBuildLog());
1310-
if (Result.failed()) {
1311-
throw sycl::exception(sycl::errc::build, Result.getBuildLog());
1309+
const char *BuildLog = Result.getBuildLog();
1310+
appendToLog(BuildLog);
1311+
switch (Result.getErrorCode()) {
1312+
using RTCErrC = ::jit_compiler::RTCErrorCode;
1313+
case RTCErrC::BUILD:
1314+
throw sycl::exception(sycl::errc::build, BuildLog);
1315+
case RTCErrC::INVALID:
1316+
throw sycl::exception(sycl::errc::invalid, BuildLog);
1317+
default: // RTCErrC::SUCCESS
1318+
break;
13121319
}
13131320

13141321
const auto &IR = Result.getDeviceCodeIR();

sycl/test-e2e/KernelCompiler/sycl.cpp

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -454,23 +454,17 @@ int test_unsupported_options(sycl::queue q) {
454454
ctx, syclex::source_language::sycl, "");
455455
std::vector<sycl::device> devs = kbSrc.get_devices();
456456

457-
auto CheckUnsupported = [&](const std::vector<std::string> &flags) {
458-
try {
459-
syclex::build(kbSrc, devs,
460-
syclex::properties{syclex::build_options{flags}});
461-
assert(false && "unsupported option not detected");
462-
} catch (sycl::exception &e) {
463-
assert(e.code() == sycl::errc::build);
464-
assert(std::string(e.what()).find("Parsing of user arguments failed") !=
465-
std::string::npos);
466-
}
467-
};
468-
469-
CheckUnsupported({"-fsanitize=address"});
470-
CheckUnsupported({"-Xsycl-target-frontend", "-fsanitize=address"});
471-
CheckUnsupported({"-Xsycl-target-frontend=spir64", "-fsanitize=address"});
472-
CheckUnsupported({"-Xarch_device", "-fsanitize=address"});
473-
CheckUnsupported({"-fno-sycl-device-code-split-esimd"});
457+
try {
458+
// Don't attempt to test exhaustively here...
459+
syclex::build(kbSrc, devs,
460+
syclex::properties{
461+
syclex::build_options{"-fsycl-targets=intel_gpu_pvc"}});
462+
assert(false && "unsupported option not detected");
463+
} catch (sycl::exception &e) {
464+
assert(e.code() == sycl::errc::invalid);
465+
assert(std::string(e.what()).find("Parsing of user arguments failed") !=
466+
std::string::npos);
467+
}
474468

475469
return 0;
476470
}

sycl/test-e2e/KernelCompiler/sycl_device_flags.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,8 @@ int main(int argc, char *argv[]) {
129129
source_kb kbSrc = syclex::create_kernel_bundle_from_source(
130130
ctx, syclex::source_language::sycl, SYCLSource);
131131

132-
// Flags with and without space, inner quotes.
133-
std::vector<std::string> flags{"-Xs '-doubleGRF'",
134-
"-Xs'-Xfinalizer \"-printregusage\"'"};
132+
std::vector<std::string> flags{"-Xs", "-doubleGRF",
133+
"-XsXfinalizer \"-printregusage\""};
135134
exe_kb kbExe =
136135
syclex::build(kbSrc, syclex::properties{syclex::build_options{flags}});
137136

0 commit comments

Comments
 (0)