Skip to content

[SYCL] SYCL 2020 exceptions support #4072

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 17 commits into from
Jul 15, 2021
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
89 changes: 70 additions & 19 deletions sycl/include/CL/sycl/exception.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,37 @@ class context;
/// \ingroup sycl_api
class __SYCL_EXPORT exception : public std::exception {
public:
__SYCL2020_DEPRECATED("The version of an exception constructor which takes "
"no arguments is deprecated.")
exception() = default;

exception(std::error_code, const char *Msg)
: exception(Msg, PI_INVALID_VALUE) {}
exception(std::error_code, const char *Msg);

exception(std::error_code, const std::string &Msg)
: exception(Msg, PI_INVALID_VALUE) {}
exception(std::error_code, const std::string &Msg);

// new SYCL 2020 constructors
exception(std::error_code);
exception(int, const std::error_category &, const std::string &);
exception(int, const std::error_category &, const char *);
exception(int, const std::error_category &);

exception(context, std::error_code, const std::string &);
exception(context, std::error_code, const char *);
exception(context, std::error_code);
exception(context, int, const std::error_category &, const std::string &);
exception(context, int, const std::error_category &, const char *);
exception(context, int, const std::error_category &);

const std::error_code &code() const noexcept;
const std::error_category &category() const noexcept;

const char *what() const noexcept final;

bool has_context() const;

context get_context() const;

__SYCL2020_DEPRECATED("use sycl::exception.code() instead.")
cl_int get_cl_code() const;

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

exception(const std::string &Msg) : MMsg(Msg), MContext(nullptr) {}
exception(const string_class &Msg) : MMsg(Msg), MContext(nullptr) {}

// base constructor for all SYCL 2020 constructors
// exception(context *ctxPtr, std::error_code ec, const std::string
// &what_arg);
exception(std::error_code ec, std::shared_ptr<context> SharedPtrCtx,
const std::string &what_arg);
};

class runtime_error : public exception {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::runtime instead.") runtime_error
: public exception {
public:
runtime_error() = default;

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

runtime_error(const std::string &Msg, cl_int Err) : exception(Msg, Err) {}
};
class kernel_error : public runtime_error {
class __SYCL2020_DEPRECATED("use sycl::exception with sycl::errc::kernel or "
"errc::kernel_argument instead.") kernel_error
: public runtime_error {
using runtime_error::runtime_error;
};
class accessor_error : public runtime_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::accessor instead.") accessor_error
: public runtime_error {
using runtime_error::runtime_error;
};
class nd_range_error : public runtime_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::nd_range instead.") nd_range_error
: public runtime_error {
using runtime_error::runtime_error;
};
class event_error : public runtime_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::event instead.") event_error
: public runtime_error {
using runtime_error::runtime_error;
};
class invalid_parameter_error : public runtime_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with a sycl::errc enum value instead.")
invalid_parameter_error : public runtime_error {
using runtime_error::runtime_error;
};
class device_error : public exception {
class __SYCL2020_DEPRECATED(
"use sycl::exception with a sycl::errc enum value instead.") device_error
: public exception {
public:
device_error() = default;

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

device_error(const std::string &Msg, cl_int Err) : exception(Msg, Err) {}
};
class compile_program_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with a sycl::errc enum value instead.")
compile_program_error : public device_error {
using device_error::device_error;
};
class link_program_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with a sycl::errc enum value instead.")
link_program_error : public device_error {
using device_error::device_error;
};
class invalid_object_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with a sycl::errc enum value instead.")
invalid_object_error : public device_error {
using device_error::device_error;
};
class memory_allocation_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::memory_allocation instead.")
memory_allocation_error : public device_error {
using device_error::device_error;
};
class platform_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::platform instead.") platform_error
: public device_error {
using device_error::device_error;
};
class profiling_error : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::profiling instead.") profiling_error
: public device_error {
using device_error::device_error;
};
class feature_not_supported : public device_error {
class __SYCL2020_DEPRECATED(
"use sycl::exception with sycl::errc::feature_not_supported instead.")
feature_not_supported : public device_error {
using device_error::device_error;
};

Expand Down
87 changes: 87 additions & 0 deletions sycl/source/exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,96 @@
#include <CL/sycl/context.hpp>
#include <CL/sycl/exception.hpp>

#include <cstring>

__SYCL_INLINE_NAMESPACE(cl) {
namespace sycl {

namespace { // anonymous
constexpr char ReservedForErrorcode[] =
"01234567812345678"; // 17 (string terminator plus error code)
std::error_code SYCL121ProxyErrorcode = make_error_code(sycl::errc::invalid);
} // namespace

exception::exception(std::error_code EC, const char *Msg)
: exception(EC, nullptr, Msg) {}

exception::exception(std::error_code EC, const std::string &Msg)
: exception(EC, nullptr, Msg) {}

// new SYCL 2020 constructors
exception::exception(std::error_code EC) : exception(EC, nullptr, "") {}

exception::exception(int EV, const std::error_category &ECat,
const std::string &WhatArg)
: exception({EV, ECat}, nullptr, WhatArg) {}

exception::exception(int EV, const std::error_category &ECat,
const char *WhatArg)
: exception({EV, ECat}, nullptr, std::string(WhatArg)) {}

exception::exception(int EV, const std::error_category &ECat)
: exception({EV, ECat}, nullptr, "") {}

exception::exception(context Ctx, std::error_code EC,
const std::string &WhatArg)
: exception(EC, std::make_shared<context>(Ctx), WhatArg) {}

exception::exception(context Ctx, std::error_code EC, const char *WhatArg)
: exception(Ctx, EC, std::string(WhatArg)) {}

exception::exception(context Ctx, std::error_code EC)
: exception(Ctx, EC, "") {}

exception::exception(context Ctx, int EV, const std::error_category &ECat,
const char *WhatArg)
: exception(Ctx, {EV, ECat}, std::string(WhatArg)) {}

exception::exception(context Ctx, int EV, const std::error_category &ECat,
const std::string &WhatArg)
: exception(Ctx, {EV, ECat}, WhatArg) {}

exception::exception(context Ctx, int EV, const std::error_category &ECat)
: exception(Ctx, EV, ECat, "") {}

// protected base constructor for all SYCL 2020 constructors
exception::exception(std::error_code EC, std::shared_ptr<context> SharedPtrCtx,
const std::string &WhatArg)
: MMsg(WhatArg + ReservedForErrorcode), MCLErr(PI_INVALID_VALUE),
MContext(SharedPtrCtx) {
// For compatibility with previous implementation, we are "hiding" the
// std::error_code in the MMsg string, behind the null string terminator
const int StringTermPoint = MMsg.length() - strlen(ReservedForErrorcode);
char *ReservedPtr = &MMsg[StringTermPoint];
ReservedPtr[0] = '\0';
ReservedPtr++;
// insert error code
std::error_code *ECPtr = reinterpret_cast<std::error_code *>(ReservedPtr);
memcpy(ECPtr, &EC, sizeof(std::error_code));
}

const std::error_code &exception::code() const noexcept {
const char *WhatStr = MMsg.c_str();
// advance to inner string-terminator
int StringTermPoint = MMsg.length() - strlen(ReservedForErrorcode);
if (StringTermPoint >= 0) {
const char *ReservedPtr = &WhatStr[StringTermPoint];
// check for string terminator, which denotes a SYCL 2020 exception
if (ReservedPtr[0] == '\0') {
ReservedPtr++;
const std::error_code *ECPtr =
reinterpret_cast<const std::error_code *>(ReservedPtr);
return *ECPtr;
}
}
// else the exception originates from some SYCL 1.2.1 source
return SYCL121ProxyErrorcode;
}

const std::error_category &exception::category() const noexcept {
return code().category();
}

const char *exception::what() const noexcept { return MMsg.c_str(); }

bool exception::has_context() const { return (MContext != nullptr); }
Expand Down
28 changes: 28 additions & 0 deletions sycl/test/abi/sycl_symbols_linux.dump
Original file line number Diff line number Diff line change
Expand Up @@ -3928,6 +3928,32 @@ _ZN2cl4sycl8platformC1Ev
_ZN2cl4sycl8platformC2EP15_cl_platform_id
_ZN2cl4sycl8platformC2ERKNS0_15device_selectorE
_ZN2cl4sycl8platformC2Ev
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_code
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_codePKc
_ZN2cl4sycl9exceptionC1ENS0_7contextESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryE
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryEPKc
_ZN2cl4sycl9exceptionC1ENS0_7contextEiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC1ESt10error_code
_ZN2cl4sycl9exceptionC1ESt10error_codePKc
_ZN2cl4sycl9exceptionC1ESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC1ESt10error_codeSt10shared_ptrINS0_7contextEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryE
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryEPKc
_ZN2cl4sycl9exceptionC1EiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_code
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_codePKc
_ZN2cl4sycl9exceptionC2ENS0_7contextESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryE
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryEPKc
_ZN2cl4sycl9exceptionC2ENS0_7contextEiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC2ESt10error_code
_ZN2cl4sycl9exceptionC2ESt10error_codePKc
_ZN2cl4sycl9exceptionC2ESt10error_codeRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC2ESt10error_codeSt10shared_ptrINS0_7contextEERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryE
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryEPKc
_ZN2cl4sycl9exceptionC2EiRKNSt3_V214error_categoryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
_ZN2cl4sycl9kernel_idC1EPKc
_ZN2cl4sycl9kernel_idC2EPKc
_ZNK2cl4sycl12cpu_selectorclERKNS0_6deviceE
Expand Down Expand Up @@ -4284,7 +4310,9 @@ _ZNK2cl4sycl8platform9getNativeEv
_ZNK2cl4sycl9exception11get_cl_codeEv
_ZNK2cl4sycl9exception11get_contextEv
_ZNK2cl4sycl9exception11has_contextEv
_ZNK2cl4sycl9exception4codeEv
_ZNK2cl4sycl9exception4whatEv
_ZNK2cl4sycl9exception8categoryEv
_ZNK2cl4sycl9kernel_id8get_nameEv
__sycl_register_lib
__sycl_unregister_lib
77 changes: 77 additions & 0 deletions sycl/test/basic_tests/exceptions-SYCL-2020.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// RUN: %clangxx -fsycl %s -o %t.out
// RUN: %RUN_ON_HOST %t.out

#include <CL/sycl.hpp>

using namespace cl::sycl;

int main() {
// Test new constructors, initially each with empty string messages.
std::string emptyStr;
const char *emptyCharPtr = "";

// Going to set the error code values to each of the enum (0-12).
exception ex1(make_error_code(errc::runtime), emptyStr);
exception ex2(make_error_code(errc::kernel), emptyCharPtr);
exception ex3(make_error_code(errc::accessor));
exception ex4(static_cast<int>(errc::nd_range), sycl_category(), emptyStr);
exception ex5(static_cast<int>(errc::event), sycl_category(), emptyCharPtr);
exception ex6(static_cast<int>(errc::kernel_argument), sycl_category());

queue Q;
context ctx = Q.get_context();
exception ex7(ctx, make_error_code(errc::build), emptyStr);
exception ex8(ctx, make_error_code(errc::invalid), emptyCharPtr);
exception ex9(ctx, make_error_code(errc::memory_allocation));
exception ex10(ctx, static_cast<int>(errc::platform), sycl_category(),
emptyStr);
exception ex11(ctx, static_cast<int>(errc::profiling), sycl_category(),
emptyCharPtr);
exception ex12(ctx, static_cast<int>(errc::feature_not_supported),
sycl_category());

std::vector<exception> v{ex1, ex2, ex3, ex4, ex5, ex6,
ex7, ex8, ex9, ex10, ex11, ex12};
for (int i = 0; i < 12; i++) {
exception ex = v[i];
assert(ex.code().value() == i && "unexpected error_code.value() retrieved");
assert(ex.category() == sycl_category() && "expected SYCL error category");
if (i < 6) {
assert(!ex.has_context() &&
"none of the first six exceptions should have a context");
} else {
assert(ex.has_context() && ex.get_context() == ctx &&
"the second six exceptions should have a context equal to ctx");
}
assert(strlen(ex.what()) == 0 &&
"all these exceptions were initialized with empty strings. We "
"should not have anything in the 'what' message");
}

// Now test constructor with a real string value, including one containing
// null string terminator
std::string testString("this is a test");
exception ex_string1(make_error_code(errc::kernel_not_supported), testString);
assert(testString.compare(ex_string1.what()) == 0);
testString[0] = '\0';
exception ex_early_terminated(make_error_code(errc::kernel_not_supported),
testString);
assert(ex_early_terminated.code().value() ==
static_cast<int>(errc::kernel_not_supported));
char testCharPtr[] = "this is also a test";
exception ex_string2(make_error_code(errc::backend_mismatch), testCharPtr);
assert(strcmp(ex_string2.what(), testCharPtr) == 0);

// Test sycl_category.
assert(std::string("SYCL").compare(sycl_category().name()) == 0 &&
"sycl_category name should be SYCL");

// Test make_error_code.
std::error_code ec = make_error_code(errc::feature_not_supported);
assert(ec.value() == static_cast<int>(errc::feature_not_supported));
assert(std::string("SYCL").compare(ec.category().name()) == 0 &&
"error code category name should be SYCL");

std::cout << "OK" << std::endl;
return 0;
}
Loading