Skip to content

Commit 5c0f748

Browse files
[SYCL] Add SYCL 2020 exceptions support (#4072)
All the new SYCL2020 exception constructors and support functions are now supported. To avoid breaking the API, the error_code is hidden behind the null terminator of the what exception message. Existing exceptions that the runtime throws are not converted SYCL2020 ones Signed-off-by: Chris Perkins <[email protected]>
1 parent f837d17 commit 5c0f748

File tree

5 files changed

+295
-19
lines changed

5 files changed

+295
-19
lines changed

sycl/include/CL/sycl/exception.hpp

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,37 @@ class context;
2828
/// \ingroup sycl_api
2929
class __SYCL_EXPORT exception : public std::exception {
3030
public:
31+
__SYCL2020_DEPRECATED("The version of an exception constructor which takes "
32+
"no arguments is deprecated.")
3133
exception() = default;
3234

33-
exception(std::error_code, const char *Msg)
34-
: exception(Msg, PI_INVALID_VALUE) {}
35+
exception(std::error_code, const char *Msg);
3536

36-
exception(std::error_code, const std::string &Msg)
37-
: exception(Msg, PI_INVALID_VALUE) {}
37+
exception(std::error_code, const std::string &Msg);
38+
39+
// new SYCL 2020 constructors
40+
exception(std::error_code);
41+
exception(int, const std::error_category &, const std::string &);
42+
exception(int, const std::error_category &, const char *);
43+
exception(int, const std::error_category &);
44+
45+
exception(context, std::error_code, const std::string &);
46+
exception(context, std::error_code, const char *);
47+
exception(context, std::error_code);
48+
exception(context, int, const std::error_category &, const std::string &);
49+
exception(context, int, const std::error_category &, const char *);
50+
exception(context, int, const std::error_category &);
51+
52+
const std::error_code &code() const noexcept;
53+
const std::error_category &category() const noexcept;
3854

3955
const char *what() const noexcept final;
4056

4157
bool has_context() const;
4258

4359
context get_context() const;
4460

61+
__SYCL2020_DEPRECATED("use sycl::exception.code() instead.")
4562
cl_int get_cl_code() const;
4663

4764
private:
@@ -59,10 +76,18 @@ class __SYCL_EXPORT exception : public std::exception {
5976
: MMsg(Msg + " " + detail::codeToString(CLErr)), MCLErr(CLErr),
6077
MContext(Context) {}
6178

62-
exception(const std::string &Msg) : MMsg(Msg), MContext(nullptr) {}
79+
exception(const string_class &Msg) : MMsg(Msg), MContext(nullptr) {}
80+
81+
// base constructor for all SYCL 2020 constructors
82+
// exception(context *ctxPtr, std::error_code ec, const std::string
83+
// &what_arg);
84+
exception(std::error_code ec, std::shared_ptr<context> SharedPtrCtx,
85+
const std::string &what_arg);
6386
};
6487

65-
class runtime_error : public exception {
88+
class __SYCL2020_DEPRECATED(
89+
"use sycl::exception with sycl::errc::runtime instead.") runtime_error
90+
: public exception {
6691
public:
6792
runtime_error() = default;
6893

@@ -71,22 +96,34 @@ class runtime_error : public exception {
7196

7297
runtime_error(const std::string &Msg, cl_int Err) : exception(Msg, Err) {}
7398
};
74-
class kernel_error : public runtime_error {
99+
class __SYCL2020_DEPRECATED("use sycl::exception with sycl::errc::kernel or "
100+
"errc::kernel_argument instead.") kernel_error
101+
: public runtime_error {
75102
using runtime_error::runtime_error;
76103
};
77-
class accessor_error : public runtime_error {
104+
class __SYCL2020_DEPRECATED(
105+
"use sycl::exception with sycl::errc::accessor instead.") accessor_error
106+
: public runtime_error {
78107
using runtime_error::runtime_error;
79108
};
80-
class nd_range_error : public runtime_error {
109+
class __SYCL2020_DEPRECATED(
110+
"use sycl::exception with sycl::errc::nd_range instead.") nd_range_error
111+
: public runtime_error {
81112
using runtime_error::runtime_error;
82113
};
83-
class event_error : public runtime_error {
114+
class __SYCL2020_DEPRECATED(
115+
"use sycl::exception with sycl::errc::event instead.") event_error
116+
: public runtime_error {
84117
using runtime_error::runtime_error;
85118
};
86-
class invalid_parameter_error : public runtime_error {
119+
class __SYCL2020_DEPRECATED(
120+
"use sycl::exception with a sycl::errc enum value instead.")
121+
invalid_parameter_error : public runtime_error {
87122
using runtime_error::runtime_error;
88123
};
89-
class device_error : public exception {
124+
class __SYCL2020_DEPRECATED(
125+
"use sycl::exception with a sycl::errc enum value instead.") device_error
126+
: public exception {
90127
public:
91128
device_error() = default;
92129

@@ -95,25 +132,39 @@ class device_error : public exception {
95132

96133
device_error(const std::string &Msg, cl_int Err) : exception(Msg, Err) {}
97134
};
98-
class compile_program_error : public device_error {
135+
class __SYCL2020_DEPRECATED(
136+
"use sycl::exception with a sycl::errc enum value instead.")
137+
compile_program_error : public device_error {
99138
using device_error::device_error;
100139
};
101-
class link_program_error : public device_error {
140+
class __SYCL2020_DEPRECATED(
141+
"use sycl::exception with a sycl::errc enum value instead.")
142+
link_program_error : public device_error {
102143
using device_error::device_error;
103144
};
104-
class invalid_object_error : public device_error {
145+
class __SYCL2020_DEPRECATED(
146+
"use sycl::exception with a sycl::errc enum value instead.")
147+
invalid_object_error : public device_error {
105148
using device_error::device_error;
106149
};
107-
class memory_allocation_error : public device_error {
150+
class __SYCL2020_DEPRECATED(
151+
"use sycl::exception with sycl::errc::memory_allocation instead.")
152+
memory_allocation_error : public device_error {
108153
using device_error::device_error;
109154
};
110-
class platform_error : public device_error {
155+
class __SYCL2020_DEPRECATED(
156+
"use sycl::exception with sycl::errc::platform instead.") platform_error
157+
: public device_error {
111158
using device_error::device_error;
112159
};
113-
class profiling_error : public device_error {
160+
class __SYCL2020_DEPRECATED(
161+
"use sycl::exception with sycl::errc::profiling instead.") profiling_error
162+
: public device_error {
114163
using device_error::device_error;
115164
};
116-
class feature_not_supported : public device_error {
165+
class __SYCL2020_DEPRECATED(
166+
"use sycl::exception with sycl::errc::feature_not_supported instead.")
167+
feature_not_supported : public device_error {
117168
using device_error::device_error;
118169
};
119170

sycl/source/exception.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,96 @@
1010
#include <CL/sycl/context.hpp>
1111
#include <CL/sycl/exception.hpp>
1212

13+
#include <cstring>
14+
1315
__SYCL_INLINE_NAMESPACE(cl) {
1416
namespace sycl {
1517

18+
namespace { // anonymous
19+
constexpr char ReservedForErrorcode[] =
20+
"01234567812345678"; // 17 (string terminator plus error code)
21+
std::error_code SYCL121ProxyErrorcode = make_error_code(sycl::errc::invalid);
22+
} // namespace
23+
24+
exception::exception(std::error_code EC, const char *Msg)
25+
: exception(EC, nullptr, Msg) {}
26+
27+
exception::exception(std::error_code EC, const std::string &Msg)
28+
: exception(EC, nullptr, Msg) {}
29+
30+
// new SYCL 2020 constructors
31+
exception::exception(std::error_code EC) : exception(EC, nullptr, "") {}
32+
33+
exception::exception(int EV, const std::error_category &ECat,
34+
const std::string &WhatArg)
35+
: exception({EV, ECat}, nullptr, WhatArg) {}
36+
37+
exception::exception(int EV, const std::error_category &ECat,
38+
const char *WhatArg)
39+
: exception({EV, ECat}, nullptr, std::string(WhatArg)) {}
40+
41+
exception::exception(int EV, const std::error_category &ECat)
42+
: exception({EV, ECat}, nullptr, "") {}
43+
44+
exception::exception(context Ctx, std::error_code EC,
45+
const std::string &WhatArg)
46+
: exception(EC, std::make_shared<context>(Ctx), WhatArg) {}
47+
48+
exception::exception(context Ctx, std::error_code EC, const char *WhatArg)
49+
: exception(Ctx, EC, std::string(WhatArg)) {}
50+
51+
exception::exception(context Ctx, std::error_code EC)
52+
: exception(Ctx, EC, "") {}
53+
54+
exception::exception(context Ctx, int EV, const std::error_category &ECat,
55+
const char *WhatArg)
56+
: exception(Ctx, {EV, ECat}, std::string(WhatArg)) {}
57+
58+
exception::exception(context Ctx, int EV, const std::error_category &ECat,
59+
const std::string &WhatArg)
60+
: exception(Ctx, {EV, ECat}, WhatArg) {}
61+
62+
exception::exception(context Ctx, int EV, const std::error_category &ECat)
63+
: exception(Ctx, EV, ECat, "") {}
64+
65+
// protected base constructor for all SYCL 2020 constructors
66+
exception::exception(std::error_code EC, std::shared_ptr<context> SharedPtrCtx,
67+
const std::string &WhatArg)
68+
: MMsg(WhatArg + ReservedForErrorcode), MCLErr(PI_INVALID_VALUE),
69+
MContext(SharedPtrCtx) {
70+
// For compatibility with previous implementation, we are "hiding" the
71+
// std::error_code in the MMsg string, behind the null string terminator
72+
const int StringTermPoint = MMsg.length() - strlen(ReservedForErrorcode);
73+
char *ReservedPtr = &MMsg[StringTermPoint];
74+
ReservedPtr[0] = '\0';
75+
ReservedPtr++;
76+
// insert error code
77+
std::error_code *ECPtr = reinterpret_cast<std::error_code *>(ReservedPtr);
78+
memcpy(ECPtr, &EC, sizeof(std::error_code));
79+
}
80+
81+
const std::error_code &exception::code() const noexcept {
82+
const char *WhatStr = MMsg.c_str();
83+
// advance to inner string-terminator
84+
int StringTermPoint = MMsg.length() - strlen(ReservedForErrorcode);
85+
if (StringTermPoint >= 0) {
86+
const char *ReservedPtr = &WhatStr[StringTermPoint];
87+
// check for string terminator, which denotes a SYCL 2020 exception
88+
if (ReservedPtr[0] == '\0') {
89+
ReservedPtr++;
90+
const std::error_code *ECPtr =
91+
reinterpret_cast<const std::error_code *>(ReservedPtr);
92+
return *ECPtr;
93+
}
94+
}
95+
// else the exception originates from some SYCL 1.2.1 source
96+
return SYCL121ProxyErrorcode;
97+
}
98+
99+
const std::error_category &exception::category() const noexcept {
100+
return code().category();
101+
}
102+
16103
const char *exception::what() const noexcept { return MMsg.c_str(); }
17104

18105
bool exception::has_context() const { return (MContext != nullptr); }

sycl/test/abi/sycl_symbols_linux.dump

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3929,6 +3929,32 @@ _ZN2cl4sycl8platformC1Ev
39293929
_ZN2cl4sycl8platformC2EP15_cl_platform_id
39303930
_ZN2cl4sycl8platformC2ERKNS0_15device_selectorE
39313931
_ZN2cl4sycl8platformC2Ev
3932+
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_code
3933+
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_codePKc
3934+
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3935+
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryE
3936+
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryEPKc
3937+
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3938+
_ZN2cl4sycl9exceptionC1ESt10error_code
3939+
_ZN2cl4sycl9exceptionC1ESt10error_codePKc
3940+
_ZN2cl4sycl9exceptionC1ESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3941+
_ZN2cl4sycl9exceptionC1ESt10error_codeSt10shared_ptrINS0_7contextEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3942+
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryE
3943+
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryEPKc
3944+
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3945+
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_code
3946+
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_codePKc
3947+
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3948+
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryE
3949+
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryEPKc
3950+
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3951+
_ZN2cl4sycl9exceptionC2ESt10error_code
3952+
_ZN2cl4sycl9exceptionC2ESt10error_codePKc
3953+
_ZN2cl4sycl9exceptionC2ESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3954+
_ZN2cl4sycl9exceptionC2ESt10error_codeSt10shared_ptrINS0_7contextEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
3955+
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryE
3956+
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryEPKc
3957+
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
39323958
_ZN2cl4sycl9kernel_idC1EPKc
39333959
_ZN2cl4sycl9kernel_idC2EPKc
39343960
_ZNK2cl4sycl12cpu_selectorclERKNS0_6deviceE
@@ -4285,7 +4311,9 @@ _ZNK2cl4sycl8platform9getNativeEv
42854311
_ZNK2cl4sycl9exception11get_cl_codeEv
42864312
_ZNK2cl4sycl9exception11get_contextEv
42874313
_ZNK2cl4sycl9exception11has_contextEv
4314+
_ZNK2cl4sycl9exception4codeEv
42884315
_ZNK2cl4sycl9exception4whatEv
4316+
_ZNK2cl4sycl9exception8categoryEv
42894317
_ZNK2cl4sycl9kernel_id8get_nameEv
42904318
__sycl_register_lib
42914319
__sycl_unregister_lib
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// RUN: %clangxx -fsycl %s -o %t.out
2+
// RUN: %RUN_ON_HOST %t.out
3+
4+
#include <CL/sycl.hpp>
5+
6+
using namespace cl::sycl;
7+
8+
int main() {
9+
// Test new constructors, initially each with empty string messages.
10+
std::string emptyStr;
11+
const char *emptyCharPtr = "";
12+
13+
// Going to set the error code values to each of the enum (0-12).
14+
exception ex1(make_error_code(errc::runtime), emptyStr);
15+
exception ex2(make_error_code(errc::kernel), emptyCharPtr);
16+
exception ex3(make_error_code(errc::accessor));
17+
exception ex4(static_cast<int>(errc::nd_range), sycl_category(), emptyStr);
18+
exception ex5(static_cast<int>(errc::event), sycl_category(), emptyCharPtr);
19+
exception ex6(static_cast<int>(errc::kernel_argument), sycl_category());
20+
21+
queue Q;
22+
context ctx = Q.get_context();
23+
exception ex7(ctx, make_error_code(errc::build), emptyStr);
24+
exception ex8(ctx, make_error_code(errc::invalid), emptyCharPtr);
25+
exception ex9(ctx, make_error_code(errc::memory_allocation));
26+
exception ex10(ctx, static_cast<int>(errc::platform), sycl_category(),
27+
emptyStr);
28+
exception ex11(ctx, static_cast<int>(errc::profiling), sycl_category(),
29+
emptyCharPtr);
30+
exception ex12(ctx, static_cast<int>(errc::feature_not_supported),
31+
sycl_category());
32+
33+
std::vector<exception> v{ex1, ex2, ex3, ex4, ex5, ex6,
34+
ex7, ex8, ex9, ex10, ex11, ex12};
35+
for (int i = 0; i < 12; i++) {
36+
exception ex = v[i];
37+
assert(ex.code().value() == i && "unexpected error_code.value() retrieved");
38+
assert(ex.category() == sycl_category() && "expected SYCL error category");
39+
if (i < 6) {
40+
assert(!ex.has_context() &&
41+
"none of the first six exceptions should have a context");
42+
} else {
43+
assert(ex.has_context() && ex.get_context() == ctx &&
44+
"the second six exceptions should have a context equal to ctx");
45+
}
46+
assert(strlen(ex.what()) == 0 &&
47+
"all these exceptions were initialized with empty strings. We "
48+
"should not have anything in the 'what' message");
49+
}
50+
51+
// Now test constructor with a real string value, including one containing
52+
// null string terminator
53+
std::string testString("this is a test");
54+
exception ex_string1(make_error_code(errc::kernel_not_supported), testString);
55+
assert(testString.compare(ex_string1.what()) == 0);
56+
testString[0] = '\0';
57+
exception ex_early_terminated(make_error_code(errc::kernel_not_supported),
58+
testString);
59+
assert(ex_early_terminated.code().value() ==
60+
static_cast<int>(errc::kernel_not_supported));
61+
char testCharPtr[] = "this is also a test";
62+
exception ex_string2(make_error_code(errc::backend_mismatch), testCharPtr);
63+
assert(strcmp(ex_string2.what(), testCharPtr) == 0);
64+
65+
// Test sycl_category.
66+
assert(std::string("SYCL").compare(sycl_category().name()) == 0 &&
67+
"sycl_category name should be SYCL");
68+
69+
// Test make_error_code.
70+
std::error_code ec = make_error_code(errc::feature_not_supported);
71+
assert(ec.value() == static_cast<int>(errc::feature_not_supported));
72+
assert(std::string("SYCL").compare(ec.category().name()) == 0 &&
73+
"error code category name should be SYCL");
74+
75+
std::cout << "OK" << std::endl;
76+
return 0;
77+
}

0 commit comments

Comments
 (0)