[llvm] [libsycl] Add constructors for context (PR #214538)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 8 15:55:39 PDT 2026
https://github.com/Robertkq updated https://github.com/llvm/llvm-project/pull/214538
>From 19ace57f105d0f9c0752f0a02a0a27481080bd65 Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Thu, 6 Aug 2026 20:17:40 +0300
Subject: [PATCH 1/6] Add public ctors for context
---
libsycl/docs/index.md | 2 +-
libsycl/include/sycl/__impl/context.hpp | 76 +++++++++++++++++++++++++
libsycl/src/context.cpp | 55 ++++++++++++++++++
libsycl/src/detail/context_impl.cpp | 4 +-
libsycl/src/detail/context_impl.hpp | 1 +
5 files changed, 134 insertions(+), 4 deletions(-)
diff --git a/libsycl/docs/index.md b/libsycl/docs/index.md
index 189120782366b..d75b912ef502f 100644
--- a/libsycl/docs/index.md
+++ b/libsycl/docs/index.md
@@ -102,7 +102,7 @@ which doesn't currently support Windows.
- device selection: to add compatibility with old SYCL 1.2.1 device selectors, still part of SYCL 2020 specification
-- `context`: to implement get_info, properties & public constructors once context support is added to liboffload
+- `context`: to implement get_info, properties once context support is added to liboffload
- `queue`:
diff --git a/libsycl/include/sycl/__impl/context.hpp b/libsycl/include/sycl/__impl/context.hpp
index 3acc91fad9647..9c7c72b85a06a 100644
--- a/libsycl/include/sycl/__impl/context.hpp
+++ b/libsycl/include/sycl/__impl/context.hpp
@@ -16,8 +16,10 @@
#ifndef _LIBSYCL___IMPL_CONTEXT_HPP
#define _LIBSYCL___IMPL_CONTEXT_HPP
+#include <sycl/__impl/async_handler.hpp>
#include <sycl/__impl/backend.hpp>
#include <sycl/__impl/info/desc_base.hpp>
+#include <sycl/__impl/property_list.hpp>
#include <sycl/__impl/detail/config.hpp>
#include <sycl/__impl/detail/obj_utils.hpp>
@@ -40,6 +42,80 @@ using is_context_info_desc_t = typename is_info_desc<T, context>::return_type;
// SYCL 2020 4.6.3. Context class
class _LIBSYCL_EXPORT context {
public:
+ /// @brief Constructs a SYCL context instance using an instance of
+ /// default_selector.
+ ///
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using an instance of
+ /// device_selector.
+ ///
+ /// @param asyncHandler Async handler to be used for asynchronous error
+ /// reporting.
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(async_handler asyncHandler,
+ const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided device.
+ /// The context will be associated with the platform of the provided device.
+ ///
+ /// @param dev is an instance of SYCL device
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const device &dev, const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided device.
+ /// The context will be associated with the platform of the provided device.
+ ///
+ /// @param dev is an instance of SYCL device
+ /// @param asyncHandler Async handler to be used for asynchronous error
+ /// reporting.
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const device &dev, async_handler asyncHandler,
+ const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided platform.
+ /// The context will be associated with the provided platform and with each
+ /// SYCL device that is associated with the Platform.
+ ///
+ /// @param plt is an instance of SYCL platform
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const platform &plt, const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided platform.
+ /// The context will be associated with the provided platform and with each
+ /// SYCL device that is associated with the Platform.
+ ///
+ /// @param plt is an instance of SYCL platform
+ /// @param asyncHandler Async handler to be used for asynchronous error
+ /// reporting.
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const platform &plt, async_handler asyncHandler,
+ const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided list of
+ /// devices. The context will be associated with each SYCL device in the
+ /// deviceList. This requires that all devices in the deviceList are
+ /// associated with the same platform.
+ ///
+ /// @param deviceList is a vector of SYCL devices
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const std::vector<device> &deviceList,
+ const property_list &propList = {});
+
+ /// @brief Constructs a SYCL context instance using the provided list of
+ /// devices. The context will be associated with each SYCL device in the
+ /// deviceList. This requires that all devices in the deviceList are
+ /// associated with the same platform.
+ ///
+ /// @param deviceList is a vector of SYCL devices
+ /// @param asyncHandler Async handler to be used for asynchronous error
+ /// reporting.
+ /// @param propList SYCL properties to be associated with the context.
+ explicit context(const std::vector<device> &deviceList,
+ async_handler asyncHandler,
+ const property_list &propList = {});
+
context(const context &rhs) = default;
context(context &&rhs) = default;
diff --git a/libsycl/src/context.cpp b/libsycl/src/context.cpp
index 3241d6fd47b67..b9c6d8a7b0da5 100644
--- a/libsycl/src/context.cpp
+++ b/libsycl/src/context.cpp
@@ -6,15 +6,70 @@
//
//===----------------------------------------------------------------------===//
+#include <sycl/__impl/context.hpp>
#include <sycl/__impl/device.hpp>
+#include <sycl/__impl/exception.hpp>
#include <detail/context_impl.hpp>
#include <detail/platform_impl.hpp>
+#include <algorithm>
#include <cassert>
+#include <vector>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
+context::context(const property_list &propList) : context(device{}, propList) {}
+
+context::context(async_handler asyncHandler, const property_list &propList)
+ : context(device{}, asyncHandler, propList) {}
+
+context::context(const device &dev, const property_list &propList)
+ : context(std::vector<device>{dev}, propList) {}
+
+context::context(const device &dev, async_handler asyncHandler,
+ const property_list &propList)
+ : context(std::vector<device>{dev}, asyncHandler, propList) {}
+
+context::context(const platform &plt, const property_list &propList)
+ : context(plt.get_devices(), propList) {}
+
+context::context(const platform &plt, async_handler asyncHandler,
+ const property_list &propList)
+ : context(plt.get_devices(), asyncHandler, propList) {}
+
+context::context(const std::vector<device> &deviceList,
+ const property_list &propList)
+ : context(deviceList, detail::defaultAsyncHandler, propList) {}
+
+context::context(const std::vector<device> &deviceList,
+ async_handler asyncHandler, const property_list &propList)
+ : impl() {
+ if (deviceList.empty()) {
+ throw exception(make_error_code(errc::invalid),
+ "Device list must not be empty");
+ }
+
+ const auto &platform = deviceList[0].get_platform();
+ if (std::any_of(deviceList.begin(), deviceList.end(),
+ [&platform](const device &dev) {
+ return dev.get_platform() != platform;
+ })) {
+ throw exception(make_error_code(errc::invalid),
+ "All devices must be associated with the same platform");
+ }
+
+ std::vector<detail::DeviceImpl *> deviceImpls;
+ deviceImpls.reserve(deviceList.size());
+ for (const device &dev : deviceList) {
+ deviceImpls.push_back(detail::ImplUtils::getSyclObjImpl(dev));
+ }
+
+ impl = detail::ContextImpl::create(std::move(deviceImpls), asyncHandler,
+ propList);
+ assert(impl && "ContextImpl creation failed");
+}
+
backend context::get_backend() const noexcept { return impl->getBackend(); }
platform context::get_platform() const {
diff --git a/libsycl/src/detail/context_impl.cpp b/libsycl/src/detail/context_impl.cpp
index 66a63131b49bb..9f05250cc283c 100644
--- a/libsycl/src/detail/context_impl.cpp
+++ b/libsycl/src/detail/context_impl.cpp
@@ -16,9 +16,7 @@ namespace detail {
ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
const async_handler &AsyncHandler,
const property_list &PropList, Private)
- : MAsyncHandler(AsyncHandler), MDevices(DeviceList) {
- (void)PropList;
-
+ : MAsyncHandler(AsyncHandler), MDevices(DeviceList), MPropList(PropList) {
assert(!MDevices.empty() && "Device list must not be empty");
std::vector<ol_device_handle_t> DeviceIds;
diff --git a/libsycl/src/detail/context_impl.hpp b/libsycl/src/detail/context_impl.hpp
index ec9c8d10aca7e..99caed18e42d7 100644
--- a/libsycl/src/detail/context_impl.hpp
+++ b/libsycl/src/detail/context_impl.hpp
@@ -86,6 +86,7 @@ class ContextImpl : public std::enable_shared_from_this<ContextImpl> {
const async_handler MAsyncHandler;
const std::vector<DeviceImpl *> MDevices;
ol_context_handle_t MOffloadContext{};
+ property_list MPropList;
};
} // namespace detail
>From 04440d0c24a20962d853bf635ffdb1caed6d76ab Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Sun, 16 Aug 2026 15:17:43 +0300
Subject: [PATCH 2/6] Add E2E & unit tests for context ctors
---
libsycl/src/detail/context_impl.cpp | 3 +-
libsycl/test/basic/context.cpp | 62 ++++++++++++++++++
libsycl/unittests/CMakeLists.txt | 1 +
libsycl/unittests/context/CMakeLists.txt | 3 +
libsycl/unittests/context/context_ctors.cpp | 71 +++++++++++++++++++++
5 files changed, 139 insertions(+), 1 deletion(-)
create mode 100644 libsycl/test/basic/context.cpp
create mode 100644 libsycl/unittests/context/CMakeLists.txt
create mode 100644 libsycl/unittests/context/context_ctors.cpp
diff --git a/libsycl/src/detail/context_impl.cpp b/libsycl/src/detail/context_impl.cpp
index 9f05250cc283c..b0618d2a5ab0e 100644
--- a/libsycl/src/detail/context_impl.cpp
+++ b/libsycl/src/detail/context_impl.cpp
@@ -16,7 +16,8 @@ namespace detail {
ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
const async_handler &AsyncHandler,
const property_list &PropList, Private)
- : MAsyncHandler(AsyncHandler), MDevices(DeviceList), MPropList(PropList) {
+ : MAsyncHandler(AsyncHandler), MDevices(std::move(DeviceList)),
+ MPropList(PropList) {
assert(!MDevices.empty() && "Device list must not be empty");
std::vector<ol_device_handle_t> DeviceIds;
diff --git a/libsycl/test/basic/context.cpp b/libsycl/test/basic/context.cpp
new file mode 100644
index 0000000000000..cfb3ac471542e
--- /dev/null
+++ b/libsycl/test/basic/context.cpp
@@ -0,0 +1,62 @@
+// REQUIRES: any-device
+// RUN: %clangxx -fsycl %s -o %t.out
+// RUN: %t.out
+
+#include <iostream>
+
+#include <sycl/sycl.hpp>
+
+using namespace sycl;
+
+void return_fail() {
+ std::cout << "Failed" << std::endl;
+ exit(1);
+}
+
+void dummyAsyncHandler(sycl::exception_list) {}
+
+void check(const context &ctx) {
+ auto devices = ctx.get_devices();
+ if (devices.empty()) {
+ std::cout << "Context has no devices" << std::endl;
+ return_fail();
+ }
+
+ auto plt = ctx.get_platform();
+ for (const auto &dev : devices) {
+ if (dev.get_platform() != plt) {
+ std::cout << "Device platform does not match context platform"
+ << std::endl;
+ return_fail();
+ }
+ }
+ auto backend = ctx.get_backend();
+ for (const auto &dev : devices) {
+ if (dev.get_backend() != backend) {
+ std::cout << "Device backend does not match context backend" << std::endl;
+ return_fail();
+ }
+ }
+}
+
+int main() {
+ context ctx;
+ check(ctx);
+
+ device dev;
+ context ctx2(dev);
+ check(ctx2);
+
+ device dev2;
+
+ platform plt = dev.get_platform();
+ context ctx3(plt);
+ check(ctx3);
+
+ context ctx4({dev, dev2}, dummyAsyncHandler,
+ {/* explicit properties list */});
+ check(ctx4);
+
+ std::cout << "Passed" << std::endl;
+ return 0;
+}
diff --git a/libsycl/unittests/CMakeLists.txt b/libsycl/unittests/CMakeLists.txt
index 349818cedb597..02e89b714abdb 100644
--- a/libsycl/unittests/CMakeLists.txt
+++ b/libsycl/unittests/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(event)
add_subdirectory(platform)
add_subdirectory(program_manager)
add_subdirectory(queue)
+add_subdirectory(context)
# The unit test executables are GoogleTest binaries that are discovered and run
# by lit, mirroring how liboffload runs its unit tests.
diff --git a/libsycl/unittests/context/CMakeLists.txt b/libsycl/unittests/context/CMakeLists.txt
new file mode 100644
index 0000000000000..9e599e3bcd589
--- /dev/null
+++ b/libsycl/unittests/context/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_sycl_unittest(ContextTests
+ context_ctors.cpp
+)
diff --git a/libsycl/unittests/context/context_ctors.cpp b/libsycl/unittests/context/context_ctors.cpp
new file mode 100644
index 0000000000000..8cb97efcb9124
--- /dev/null
+++ b/libsycl/unittests/context/context_ctors.cpp
@@ -0,0 +1,71 @@
+#include <mock/helpers.hpp>
+
+#include <sycl/__impl/context.hpp>
+#include <sycl/__impl/device.hpp>
+#include <sycl/__impl/exception.hpp>
+#include <sycl/__impl/platform.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utility>
+
+using namespace sycl;
+using namespace ::testing;
+
+void dummyAsyncHandler(exception_list) {}
+
+TEST(Context, DefaultConstructor) {
+ mock::MockWrapper Mock;
+
+ std::ignore = device{};
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
+
+ context Ctx;
+}
+
+TEST(Context, DeviceConstructor) {
+ mock::MockWrapper Mock;
+ device Dev;
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
+
+ context Ctx(Dev);
+}
+
+TEST(Context, DeviceConstructorWithAsyncHandler) {
+ mock::MockWrapper Mock;
+ device Dev;
+ async_handler AsyncHandler = dummyAsyncHandler;
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
+
+ context Ctx(Dev, AsyncHandler);
+}
+
+TEST(Context, PlatformConstructor) {
+ mock::MockWrapper Mock;
+ device Dev;
+ platform Plt = Dev.get_platform();
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
+
+ context Ctx(Plt);
+}
+
+TEST(Context, DeviceListConstructor) {
+ mock::MockWrapper Mock;
+ device Dev1;
+ device Dev2;
+ async_handler AsyncHandler = dummyAsyncHandler;
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
+ EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
+
+ context Ctx({Dev1, Dev2}, AsyncHandler);
+}
\ No newline at end of file
>From 623500902d914af86c682b070d60ab5beff1024a Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Sun, 16 Aug 2026 15:21:24 +0300
Subject: [PATCH 3/6] add missing eof in unittests
---
libsycl/unittests/context/context_ctors.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libsycl/unittests/context/context_ctors.cpp b/libsycl/unittests/context/context_ctors.cpp
index 8cb97efcb9124..19f6a515733eb 100644
--- a/libsycl/unittests/context/context_ctors.cpp
+++ b/libsycl/unittests/context/context_ctors.cpp
@@ -68,4 +68,4 @@ TEST(Context, DeviceListConstructor) {
EXPECT_CALL(Mock.get(), olDestroyContext(_)).Times(1);
context Ctx({Dev1, Dev2}, AsyncHandler);
-}
\ No newline at end of file
+}
>From 56ec0c5cc39d1b20dab1d4b83184d15114037f4f Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Wed, 2 Sep 2026 20:54:02 +0300
Subject: [PATCH 4/6] Better documentation, cleanup & addressing reviews
---
libsycl/include/sycl/__impl/context.hpp | 100 ++++++++++++--------
libsycl/include/sycl/__impl/platform.hpp | 2 +-
libsycl/src/context.cpp | 33 +------
libsycl/src/detail/context_impl.cpp | 5 +-
libsycl/src/detail/context_impl.hpp | 1 -
libsycl/src/platform.cpp | 1 +
libsycl/test/basic/context.cpp | 4 -
libsycl/unittests/context/context_ctors.cpp | 15 +++
8 files changed, 81 insertions(+), 80 deletions(-)
diff --git a/libsycl/include/sycl/__impl/context.hpp b/libsycl/include/sycl/__impl/context.hpp
index 9c7c72b85a06a..5c4a463197d95 100644
--- a/libsycl/include/sycl/__impl/context.hpp
+++ b/libsycl/include/sycl/__impl/context.hpp
@@ -18,7 +18,10 @@
#include <sycl/__impl/async_handler.hpp>
#include <sycl/__impl/backend.hpp>
+#include <sycl/__impl/device.hpp>
+#include <sycl/__impl/exception.hpp>
#include <sycl/__impl/info/desc_base.hpp>
+#include <sycl/__impl/platform.hpp>
#include <sycl/__impl/property_list.hpp>
#include <sycl/__impl/detail/config.hpp>
@@ -30,8 +33,6 @@
_LIBSYCL_BEGIN_NAMESPACE_SYCL
class context;
-class device;
-class platform;
namespace detail {
class ContextImpl;
@@ -42,76 +43,91 @@ using is_context_info_desc_t = typename is_info_desc<T, context>::return_type;
// SYCL 2020 4.6.3. Context class
class _LIBSYCL_EXPORT context {
public:
- /// @brief Constructs a SYCL context instance using an instance of
- /// default_selector.
+ /// Constructs a SYCL context instance using the device selected by
+ /// default_selector_v.
///
- /// @param propList SYCL properties to be associated with the context.
- explicit context(const property_list &propList = {});
+ /// \param propList SYCL properties to be associated with the context.
+ explicit context(const property_list &propList = {})
+ : context(device{}, propList) {}
- /// @brief Constructs a SYCL context instance using an instance of
- /// device_selector.
+ /// Constructs a SYCL context instance using the device selected by
+ /// default_selector_v.
///
- /// @param asyncHandler Async handler to be used for asynchronous error
+ /// \param asyncHandler Async handler to be used for asynchronous error
/// reporting.
- /// @param propList SYCL properties to be associated with the context.
+ /// \param propList SYCL properties to be associated with the context.
explicit context(async_handler asyncHandler,
- const property_list &propList = {});
+ const property_list &propList = {})
+ : context(device{}, asyncHandler, propList) {}
- /// @brief Constructs a SYCL context instance using the provided device.
+ /// Constructs a SYCL context instance using the provided device.
/// The context will be associated with the platform of the provided device.
///
- /// @param dev is an instance of SYCL device
- /// @param propList SYCL properties to be associated with the context.
- explicit context(const device &dev, const property_list &propList = {});
+ /// \param dev is an instance of SYCL device
+ /// \param propList SYCL properties to be associated with the context.
+ explicit context(const device &dev, const property_list &propList = {})
+ : context(std::vector<device>{dev}, propList) {}
- /// @brief Constructs a SYCL context instance using the provided device.
+ /// Constructs a SYCL context instance using the provided device.
/// The context will be associated with the platform of the provided device.
///
- /// @param dev is an instance of SYCL device
- /// @param asyncHandler Async handler to be used for asynchronous error
+ /// \param dev is an instance of SYCL device
+ /// \param asyncHandler Async handler to be used for asynchronous error
/// reporting.
- /// @param propList SYCL properties to be associated with the context.
+ /// \param propList SYCL properties to be associated with the context.
explicit context(const device &dev, async_handler asyncHandler,
- const property_list &propList = {});
+ const property_list &propList = {})
+ : context(std::vector<device>{dev}, asyncHandler, propList) {}
- /// @brief Constructs a SYCL context instance using the provided platform.
- /// The context will be associated with the provided platform and with each
- /// SYCL device that is associated with the Platform.
+ /// Constructs a SYCL context instance that contains all of the devices
+ /// in the platform plt.
+ ///
+ /// \param plt is an instance of SYCL platform
+ /// \param propList SYCL properties to be associated with the context.
///
- /// @param plt is an instance of SYCL platform
- /// @param propList SYCL properties to be associated with the context.
- explicit context(const platform &plt, const property_list &propList = {});
+ /// \throws an exception with code errc::invalid if the platform plt has no
+ /// devices.
+ explicit context(const platform &plt, const property_list &propList = {})
+ : context(plt.get_devices(), propList) {}
- /// @brief Constructs a SYCL context instance using the provided platform.
- /// The context will be associated with the provided platform and with each
- /// SYCL device that is associated with the Platform.
+ /// Constructs a SYCL context instance that contains all of the devices
+ /// in the platform plt.
///
- /// @param plt is an instance of SYCL platform
- /// @param asyncHandler Async handler to be used for asynchronous error
+ /// \param plt is an instance of SYCL platform
+ /// \param asyncHandler Async handler to be used for asynchronous error
/// reporting.
- /// @param propList SYCL properties to be associated with the context.
+ /// \param propList SYCL properties to be associated with the context.
+ ///
+ /// \throws an exception with code errc::invalid if the platform plt has no
+ /// devices.
explicit context(const platform &plt, async_handler asyncHandler,
- const property_list &propList = {});
+ const property_list &propList = {})
+ : context(plt.get_devices(), asyncHandler, propList) {}
- /// @brief Constructs a SYCL context instance using the provided list of
+ /// Constructs a SYCL context instance using the provided list of
/// devices. The context will be associated with each SYCL device in the
/// deviceList. This requires that all devices in the deviceList are
/// associated with the same platform.
///
- /// @param deviceList is a vector of SYCL devices
- /// @param propList SYCL properties to be associated with the context.
+ /// \param deviceList is a vector of SYCL devices
+ /// \param propList SYCL properties to be associated with the context.
+ ///
+ /// \throws an exception with code errc::invalid if the deviceList is empty.
explicit context(const std::vector<device> &deviceList,
- const property_list &propList = {});
+ const property_list &propList = {})
+ : context(deviceList, detail::defaultAsyncHandler, propList) {}
- /// @brief Constructs a SYCL context instance using the provided list of
+ /// Constructs a SYCL context instance using the provided list of
/// devices. The context will be associated with each SYCL device in the
/// deviceList. This requires that all devices in the deviceList are
/// associated with the same platform.
///
- /// @param deviceList is a vector of SYCL devices
- /// @param asyncHandler Async handler to be used for asynchronous error
+ /// \param deviceList is a vector of SYCL devices
+ /// \param asyncHandler Async handler to be used for asynchronous error
/// reporting.
- /// @param propList SYCL properties to be associated with the context.
+ /// \param propList SYCL properties to be associated with the context.
+ ///
+ /// \throws an exception with code errc::invalid if the deviceList is empty.
explicit context(const std::vector<device> &deviceList,
async_handler asyncHandler,
const property_list &propList = {});
@@ -124,6 +140,8 @@ class _LIBSYCL_EXPORT context {
context &operator=(context &&rhs) = default;
+ ~context() = default;
+
friend bool operator==(const context &lhs, const context &rhs) {
return lhs.impl == rhs.impl;
}
diff --git a/libsycl/include/sycl/__impl/platform.hpp b/libsycl/include/sycl/__impl/platform.hpp
index 991380025c236..8512e53a11385 100644
--- a/libsycl/include/sycl/__impl/platform.hpp
+++ b/libsycl/include/sycl/__impl/platform.hpp
@@ -17,7 +17,6 @@
#include <sycl/__impl/aspect.hpp>
#include <sycl/__impl/backend.hpp>
-#include <sycl/__impl/context.hpp>
#include <sycl/__impl/detail/config.hpp>
#include <sycl/__impl/detail/obj_utils.hpp>
#include <sycl/__impl/info/device_type.hpp>
@@ -30,6 +29,7 @@
_LIBSYCL_BEGIN_NAMESPACE_SYCL
+class context;
class device;
namespace detail {
diff --git a/libsycl/src/context.cpp b/libsycl/src/context.cpp
index b9c6d8a7b0da5..c8bf75c9140e6 100644
--- a/libsycl/src/context.cpp
+++ b/libsycl/src/context.cpp
@@ -19,32 +19,8 @@
_LIBSYCL_BEGIN_NAMESPACE_SYCL
-context::context(const property_list &propList) : context(device{}, propList) {}
-
-context::context(async_handler asyncHandler, const property_list &propList)
- : context(device{}, asyncHandler, propList) {}
-
-context::context(const device &dev, const property_list &propList)
- : context(std::vector<device>{dev}, propList) {}
-
-context::context(const device &dev, async_handler asyncHandler,
- const property_list &propList)
- : context(std::vector<device>{dev}, asyncHandler, propList) {}
-
-context::context(const platform &plt, const property_list &propList)
- : context(plt.get_devices(), propList) {}
-
-context::context(const platform &plt, async_handler asyncHandler,
- const property_list &propList)
- : context(plt.get_devices(), asyncHandler, propList) {}
-
-context::context(const std::vector<device> &deviceList,
- const property_list &propList)
- : context(deviceList, detail::defaultAsyncHandler, propList) {}
-
context::context(const std::vector<device> &deviceList,
- async_handler asyncHandler, const property_list &propList)
- : impl() {
+ async_handler asyncHandler, const property_list &propList) {
if (deviceList.empty()) {
throw exception(make_error_code(errc::invalid),
"Device list must not be empty");
@@ -59,15 +35,10 @@ context::context(const std::vector<device> &deviceList,
"All devices must be associated with the same platform");
}
- std::vector<detail::DeviceImpl *> deviceImpls;
- deviceImpls.reserve(deviceList.size());
- for (const device &dev : deviceList) {
- deviceImpls.push_back(detail::ImplUtils::getSyclObjImpl(dev));
- }
+ auto deviceImpls = detail::getSyclObjImpls(deviceList);
impl = detail::ContextImpl::create(std::move(deviceImpls), asyncHandler,
propList);
- assert(impl && "ContextImpl creation failed");
}
backend context::get_backend() const noexcept { return impl->getBackend(); }
diff --git a/libsycl/src/detail/context_impl.cpp b/libsycl/src/detail/context_impl.cpp
index b0618d2a5ab0e..a5cb0680cbed6 100644
--- a/libsycl/src/detail/context_impl.cpp
+++ b/libsycl/src/detail/context_impl.cpp
@@ -16,8 +16,9 @@ namespace detail {
ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
const async_handler &AsyncHandler,
const property_list &PropList, Private)
- : MAsyncHandler(AsyncHandler), MDevices(std::move(DeviceList)),
- MPropList(PropList) {
+ : MAsyncHandler(AsyncHandler), MDevices(std::move(DeviceList)) {
+ // TODO: Remove this when property_list is implemented
+ std::ignore = PropList;
assert(!MDevices.empty() && "Device list must not be empty");
std::vector<ol_device_handle_t> DeviceIds;
diff --git a/libsycl/src/detail/context_impl.hpp b/libsycl/src/detail/context_impl.hpp
index 99caed18e42d7..ec9c8d10aca7e 100644
--- a/libsycl/src/detail/context_impl.hpp
+++ b/libsycl/src/detail/context_impl.hpp
@@ -86,7 +86,6 @@ class ContextImpl : public std::enable_shared_from_this<ContextImpl> {
const async_handler MAsyncHandler;
const std::vector<DeviceImpl *> MDevices;
ol_context_handle_t MOffloadContext{};
- property_list MPropList;
};
} // namespace detail
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index b5bddc82e0d9a..9464257f25ba5 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include <sycl/__impl/context.hpp>
#include <sycl/__impl/device.hpp>
#include <sycl/__impl/platform.hpp>
diff --git a/libsycl/test/basic/context.cpp b/libsycl/test/basic/context.cpp
index cfb3ac471542e..10f8842c47289 100644
--- a/libsycl/test/basic/context.cpp
+++ b/libsycl/test/basic/context.cpp
@@ -17,10 +17,6 @@ void dummyAsyncHandler(sycl::exception_list) {}
void check(const context &ctx) {
auto devices = ctx.get_devices();
- if (devices.empty()) {
- std::cout << "Context has no devices" << std::endl;
- return_fail();
- }
auto plt = ctx.get_platform();
for (const auto &dev : devices) {
diff --git a/libsycl/unittests/context/context_ctors.cpp b/libsycl/unittests/context/context_ctors.cpp
index 19f6a515733eb..ff1b328df3271 100644
--- a/libsycl/unittests/context/context_ctors.cpp
+++ b/libsycl/unittests/context/context_ctors.cpp
@@ -18,6 +18,7 @@ void dummyAsyncHandler(exception_list) {}
TEST(Context, DefaultConstructor) {
mock::MockWrapper Mock;
+ // TODO: remove once context is properly implemented
std::ignore = device{};
EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(1);
@@ -69,3 +70,17 @@ TEST(Context, DeviceListConstructor) {
context Ctx({Dev1, Dev2}, AsyncHandler);
}
+
+TEST(Context, DeviceListConstructorThrowsOnEmptyList) {
+ mock::MockWrapper Mock;
+ async_handler AsyncHandler = dummyAsyncHandler;
+
+ EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(0);
+
+ try {
+ context Ctx(std::vector<device>{}, AsyncHandler);
+ FAIL() << "Expected sycl::exception";
+ } catch (const exception &Ex) {
+ EXPECT_EQ(Ex.code(), make_error_code(errc::invalid));
+ }
+}
>From 0c33b09da0f21a8a62d323ba91e8dfd11c6440d9 Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Wed, 9 Sep 2026 01:21:06 +0300
Subject: [PATCH 5/6] Fix context error code and drop a stale include and
comment
---
libsycl/src/context.cpp | 14 --------------
libsycl/src/detail/context_impl.cpp | 8 ++++++--
libsycl/src/platform.cpp | 1 -
libsycl/unittests/context/context_ctors.cpp | 7 ++++++-
4 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/libsycl/src/context.cpp b/libsycl/src/context.cpp
index c8bf75c9140e6..1f1be69e89139 100644
--- a/libsycl/src/context.cpp
+++ b/libsycl/src/context.cpp
@@ -21,20 +21,6 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
context::context(const std::vector<device> &deviceList,
async_handler asyncHandler, const property_list &propList) {
- if (deviceList.empty()) {
- throw exception(make_error_code(errc::invalid),
- "Device list must not be empty");
- }
-
- const auto &platform = deviceList[0].get_platform();
- if (std::any_of(deviceList.begin(), deviceList.end(),
- [&platform](const device &dev) {
- return dev.get_platform() != platform;
- })) {
- throw exception(make_error_code(errc::invalid),
- "All devices must be associated with the same platform");
- }
-
auto deviceImpls = detail::getSyclObjImpls(deviceList);
impl = detail::ContextImpl::create(std::move(deviceImpls), asyncHandler,
diff --git a/libsycl/src/detail/context_impl.cpp b/libsycl/src/detail/context_impl.cpp
index a5cb0680cbed6..2360c481eaef0 100644
--- a/libsycl/src/detail/context_impl.cpp
+++ b/libsycl/src/detail/context_impl.cpp
@@ -28,8 +28,12 @@ ContextImpl::ContextImpl(std::vector<DeviceImpl *> &&DeviceList,
DeviceIds.push_back(D->getOLHandle());
}
- callAndThrow(olCreateContext, DeviceIds.size(), DeviceIds.data(),
- &MOffloadContext);
+ auto Result = callNoCheck(olCreateContext, DeviceIds.size(), DeviceIds.data(),
+ &MOffloadContext);
+ if (isFailed(Result))
+ throw sycl::exception(make_error_code(errc::invalid),
+ "Failed to create SYCL context: " +
+ formatCodeString(Result));
}
ContextImpl::~ContextImpl() {
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index 9464257f25ba5..b5bddc82e0d9a 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -6,7 +6,6 @@
//
//===----------------------------------------------------------------------===//
-#include <sycl/__impl/context.hpp>
#include <sycl/__impl/device.hpp>
#include <sycl/__impl/platform.hpp>
diff --git a/libsycl/unittests/context/context_ctors.cpp b/libsycl/unittests/context/context_ctors.cpp
index ff1b328df3271..a718c9b403ca9 100644
--- a/libsycl/unittests/context/context_ctors.cpp
+++ b/libsycl/unittests/context/context_ctors.cpp
@@ -18,6 +18,8 @@ void dummyAsyncHandler(exception_list) {}
TEST(Context, DefaultConstructor) {
mock::MockWrapper Mock;
+ // This line triggers lazy platform discovery, which we want to suppress
+ // from the expected calls of the mock lib.
// TODO: remove once context is properly implemented
std::ignore = device{};
@@ -75,7 +77,10 @@ TEST(Context, DeviceListConstructorThrowsOnEmptyList) {
mock::MockWrapper Mock;
async_handler AsyncHandler = dummyAsyncHandler;
- EXPECT_CALL(Mock.get(), olCreateContext(_, _, _)).Times(0);
+ EXPECT_CALL(Mock.get(), olCreateContext(0, _, _))
+ .Times(1)
+ .WillOnce(Return(
+ mock::getMockLiboffload().makeEmptyStrError(OL_ERRC_INVALID_SIZE)));
try {
context Ctx(std::vector<device>{}, AsyncHandler);
>From ac3185123d6f3bbaa9b4e1eeb401ed506b4a0a9b Mon Sep 17 00:00:00 2001
From: Robertkq <robertvuia06 at gmail.com>
Date: Wed, 9 Sep 2026 01:42:27 +0300
Subject: [PATCH 6/6] Omit explicit \param in favor of \p
---
libsycl/include/sycl/__impl/context.hpp | 68 +++++--------------------
1 file changed, 14 insertions(+), 54 deletions(-)
diff --git a/libsycl/include/sycl/__impl/context.hpp b/libsycl/include/sycl/__impl/context.hpp
index 5c4a463197d95..8a9fea4296850 100644
--- a/libsycl/include/sycl/__impl/context.hpp
+++ b/libsycl/include/sycl/__impl/context.hpp
@@ -43,91 +43,51 @@ using is_context_info_desc_t = typename is_info_desc<T, context>::return_type;
// SYCL 2020 4.6.3. Context class
class _LIBSYCL_EXPORT context {
public:
- /// Constructs a SYCL context instance using the device selected by
+ /// Constructs a SYCL context using the device selected by
/// default_selector_v.
- ///
- /// \param propList SYCL properties to be associated with the context.
explicit context(const property_list &propList = {})
: context(device{}, propList) {}
- /// Constructs a SYCL context instance using the device selected by
+ /// Constructs a SYCL context using the device selected by
/// default_selector_v.
- ///
- /// \param asyncHandler Async handler to be used for asynchronous error
- /// reporting.
- /// \param propList SYCL properties to be associated with the context.
explicit context(async_handler asyncHandler,
const property_list &propList = {})
: context(device{}, asyncHandler, propList) {}
- /// Constructs a SYCL context instance using the provided device.
- /// The context will be associated with the platform of the provided device.
- ///
- /// \param dev is an instance of SYCL device
- /// \param propList SYCL properties to be associated with the context.
+ /// Constructs a SYCL context associated with the platform of \p dev.
explicit context(const device &dev, const property_list &propList = {})
: context(std::vector<device>{dev}, propList) {}
- /// Constructs a SYCL context instance using the provided device.
- /// The context will be associated with the platform of the provided device.
- ///
- /// \param dev is an instance of SYCL device
- /// \param asyncHandler Async handler to be used for asynchronous error
- /// reporting.
- /// \param propList SYCL properties to be associated with the context.
+ /// Constructs a SYCL context associated with the platform of \p dev.
explicit context(const device &dev, async_handler asyncHandler,
const property_list &propList = {})
: context(std::vector<device>{dev}, asyncHandler, propList) {}
- /// Constructs a SYCL context instance that contains all of the devices
- /// in the platform plt.
+ /// Constructs a SYCL context containing all devices in \p plt.
///
- /// \param plt is an instance of SYCL platform
- /// \param propList SYCL properties to be associated with the context.
- ///
- /// \throws an exception with code errc::invalid if the platform plt has no
- /// devices.
+ /// \throws an exception with code errc::invalid if \p plt has no devices.
explicit context(const platform &plt, const property_list &propList = {})
: context(plt.get_devices(), propList) {}
- /// Constructs a SYCL context instance that contains all of the devices
- /// in the platform plt.
- ///
- /// \param plt is an instance of SYCL platform
- /// \param asyncHandler Async handler to be used for asynchronous error
- /// reporting.
- /// \param propList SYCL properties to be associated with the context.
+ /// Constructs a SYCL context containing all devices in \p plt.
///
- /// \throws an exception with code errc::invalid if the platform plt has no
- /// devices.
+ /// \throws an exception with code errc::invalid if \p plt has no devices.
explicit context(const platform &plt, async_handler asyncHandler,
const property_list &propList = {})
: context(plt.get_devices(), asyncHandler, propList) {}
- /// Constructs a SYCL context instance using the provided list of
- /// devices. The context will be associated with each SYCL device in the
- /// deviceList. This requires that all devices in the deviceList are
- /// associated with the same platform.
+ /// Constructs a SYCL context associated with each device in \p deviceList.
+ /// All devices in \p deviceList must belong to the same platform.
///
- /// \param deviceList is a vector of SYCL devices
- /// \param propList SYCL properties to be associated with the context.
- ///
- /// \throws an exception with code errc::invalid if the deviceList is empty.
+ /// \throws an exception with code errc::invalid if \p deviceList is empty.
explicit context(const std::vector<device> &deviceList,
const property_list &propList = {})
: context(deviceList, detail::defaultAsyncHandler, propList) {}
- /// Constructs a SYCL context instance using the provided list of
- /// devices. The context will be associated with each SYCL device in the
- /// deviceList. This requires that all devices in the deviceList are
- /// associated with the same platform.
- ///
- /// \param deviceList is a vector of SYCL devices
- /// \param asyncHandler Async handler to be used for asynchronous error
- /// reporting.
- /// \param propList SYCL properties to be associated with the context.
+ /// Constructs a SYCL context associated with each device in \p deviceList.
+ /// All devices in \p deviceList must belong to the same platform.
///
- /// \throws an exception with code errc::invalid if the deviceList is empty.
+ /// \throws an exception with code errc::invalid if \p deviceList is empty.
explicit context(const std::vector<device> &deviceList,
async_handler asyncHandler,
const property_list &propList = {});
More information about the llvm-commits
mailing list