[llvm] [libsycl] Add USM alloc & release funcs (PR #181120)

Kseniya Tikhomirova via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 12 04:38:39 PST 2026


https://github.com/KseniyaTikhomirova updated https://github.com/llvm/llvm-project/pull/181120

>From b836e37b1346065c06b254393357186659bb4aa4 Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Fri, 2 Jan 2026 08:35:29 -0800
Subject: [PATCH] [libsycl] Add USM alloc & release funcs

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 libsycl/docs/index.rst                        |   8 +
 libsycl/include/sycl/__impl/async_handler.hpp |  33 ++
 libsycl/include/sycl/__impl/context.hpp       |  99 ++++++
 .../__impl/detail/default_async_handler.hpp   |  55 ++++
 libsycl/include/sycl/__impl/device.hpp        |   2 +-
 libsycl/include/sycl/__impl/property_list.hpp |  33 ++
 libsycl/include/sycl/__impl/queue.hpp         | 159 ++++++++++
 .../include/sycl/__impl/usm_alloc_type.hpp    |  25 ++
 libsycl/include/sycl/__impl/usm_functions.hpp | 300 ++++++++++++++++++
 libsycl/include/sycl/sycl.hpp                 |   3 +
 libsycl/src/CMakeLists.txt                    |   5 +
 libsycl/src/context.cpp                       |  33 ++
 libsycl/src/detail/context_impl.cpp           |  27 ++
 libsycl/src/detail/context_impl.hpp           |  75 +++++
 libsycl/src/detail/device_impl.cpp            |  13 +-
 libsycl/src/detail/device_impl.hpp            |   4 +-
 libsycl/src/detail/global_objects.cpp         |   1 +
 libsycl/src/detail/offload/offload_utils.cpp  |  17 +
 libsycl/src/detail/offload/offload_utils.hpp  |  14 +-
 libsycl/src/detail/platform_impl.cpp          |   9 +
 libsycl/src/detail/platform_impl.hpp          |  25 +-
 libsycl/src/detail/queue_impl.cpp             |  25 ++
 libsycl/src/detail/queue_impl.hpp             |  83 +++++
 libsycl/src/device.cpp                        |   4 -
 libsycl/src/queue.cpp                         |  36 +++
 libsycl/src/usm_functions.cpp                 | 130 ++++++++
 libsycl/test/phase0.cpp                       |  33 ++
 libsycl/test/usm/alloc_functions.cpp          | 124 ++++++++
 28 files changed, 1359 insertions(+), 16 deletions(-)
 create mode 100644 libsycl/include/sycl/__impl/async_handler.hpp
 create mode 100644 libsycl/include/sycl/__impl/context.hpp
 create mode 100644 libsycl/include/sycl/__impl/detail/default_async_handler.hpp
 create mode 100644 libsycl/include/sycl/__impl/property_list.hpp
 create mode 100644 libsycl/include/sycl/__impl/queue.hpp
 create mode 100644 libsycl/include/sycl/__impl/usm_alloc_type.hpp
 create mode 100644 libsycl/include/sycl/__impl/usm_functions.hpp
 create mode 100644 libsycl/src/context.cpp
 create mode 100644 libsycl/src/detail/context_impl.cpp
 create mode 100644 libsycl/src/detail/context_impl.hpp
 create mode 100644 libsycl/src/detail/queue_impl.cpp
 create mode 100644 libsycl/src/detail/queue_impl.hpp
 create mode 100644 libsycl/src/queue.cpp
 create mode 100644 libsycl/src/usm_functions.cpp
 create mode 100644 libsycl/test/phase0.cpp
 create mode 100644 libsycl/test/usm/alloc_functions.cpp

diff --git a/libsycl/docs/index.rst b/libsycl/docs/index.rst
index 03e083227ace4..87c4843561534 100644
--- a/libsycl/docs/index.rst
+++ b/libsycl/docs/index.rst
@@ -105,4 +105,12 @@ TODO for added SYCL classes
   * ``has_extension``: deprecated API, to implement on RT level with ``device::has``
 
 * 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
+* ``queue``: to implement USM methods, to implement synchronization methods, to implement submit & copy with accessors (low priority), get_info & properties, ctors that accepts context (blocked by lack of liboffload support)
+* ``property_list``: to fully implement and integrate to existing SYCL runtime classes supporting it
+* usm allocations:
+
+  * add aligned functions (blocked by liboffload support)
+  * forward templated funcs to alignment methods (rewrite current impl)
+  * handle sub devices once they are implemented (blocked by liboffload support)
 
diff --git a/libsycl/include/sycl/__impl/async_handler.hpp b/libsycl/include/sycl/__impl/async_handler.hpp
new file mode 100644
index 0000000000000..e6550d75e9437
--- /dev/null
+++ b/libsycl/include/sycl/__impl/async_handler.hpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the SYCL async_handler type, which
+/// is a callable such as a function class or lambda, with an exception_list as
+/// a parameter. Invocation of an async_handler may be triggered by the queue
+/// member functions queue::wait_and_throw or queue::throw_asynchronous, by the
+/// event member function event::wait_and_throw, or automatically on destruction
+/// of a queue or context that contains unconsumed asynchronous errors.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_ASYNC_HANDLER_HPP
+#define _LIBSYCL___IMPL_ASYNC_HANDLER_HPP
+
+#include <functional>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+class exception_list;
+
+// SYCL 2020 4.13.2. Exception class interface.
+using async_handler = std::function<void(sycl::exception_list)>;
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_ASYNC_HANDLER_HPP
diff --git a/libsycl/include/sycl/__impl/context.hpp b/libsycl/include/sycl/__impl/context.hpp
new file mode 100644
index 0000000000000..70cd1fbaf55f8
--- /dev/null
+++ b/libsycl/include/sycl/__impl/context.hpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the SYCL context class, which
+/// represents the runtime data structures and state required by a SYCL backend
+/// API to interact with a group of devices associated with a platform.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_CONTEXT_HPP
+#define _LIBSYCL___IMPL_CONTEXT_HPP
+
+#include <sycl/__impl/backend.hpp>
+#include <sycl/__impl/info/desc_base.hpp>
+
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/detail/obj_utils.hpp>
+
+#include <memory>
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+class context;
+class device;
+class platform;
+
+namespace detail {
+class ContextImpl;
+template <typename T>
+using is_context_info_desc_t = typename is_info_desc<T, context>::return_type;
+} // namespace detail
+
+// SYCL 2020 4.6.3. Context class
+class _LIBSYCL_EXPORT context {
+public:
+  context(const context &rhs) = default;
+
+  context(context &&rhs) = default;
+
+  context &operator=(const context &rhs) = default;
+
+  context &operator=(context &&rhs) = default;
+
+  friend bool operator==(const context &lhs, const context &rhs) {
+    return lhs.impl == rhs.impl;
+  }
+
+  friend bool operator!=(const context &lhs, const context &rhs) {
+    return !(lhs == rhs);
+  }
+
+  /// Returns the backend associated with this context.
+  ///
+  /// \return the backend associated with this context.
+  backend get_backend() const noexcept;
+
+  /// Gets platform associated with this SYCL context.
+  ///
+  /// \return a valid instance of SYCL platform.
+  platform get_platform() const;
+
+  /// Gets devices associated with this SYCL context.
+  ///
+  /// \return a vector of valid SYCL device instances.
+  std::vector<device> get_devices() const;
+
+  /// Queries this SYCL context for information.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param>
+  detail::is_context_info_desc_t<Param> get_info() const;
+
+  /// Queries this SYCL context for SYCL backend-specific information.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param>
+  typename Param::return_type get_backend_info() const;
+
+private:
+  context(const std::shared_ptr<detail::ContextImpl> &Impl) : impl(Impl) {}
+  std::shared_ptr<detail::ContextImpl> impl;
+
+  friend sycl::detail::ImplUtils;
+}; // class context
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+template <>
+struct std::hash<sycl::context> : public sycl::detail::HashBase<sycl::context> {
+};
+
+#endif // _LIBSYCL___IMPL_CONTEXT_HPP
diff --git a/libsycl/include/sycl/__impl/detail/default_async_handler.hpp b/libsycl/include/sycl/__impl/detail/default_async_handler.hpp
new file mode 100644
index 0000000000000..977a1dfa0c0a9
--- /dev/null
+++ b/libsycl/include/sycl/__impl/detail/default_async_handler.hpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains definition of an implementation-defined default
+/// async_handler which is invoked when an asynchronous error occurs in a queue
+/// or context that has no user-supplied asynchronous error handler object (see
+/// SYCL 2020 4.13.1.2).
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_DETAIL_DEFAULT_ASYNC_HANDLER_HPP
+#define _LIBSYCL___IMPL_DETAIL_DEFAULT_ASYNC_HANDLER_HPP
+
+#include <sycl/__impl/exception.hpp>
+
+#include <iostream>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+// SYCL 2020 4.13.1.2. Behavior without an async handler.
+// If an asynchronous error occurs in a queue or context that has no
+// user-supplied asynchronous error handler object async_handler, then an
+// implementation-defined default async_handler is called to handle the error in
+// the same situations that a user-supplied async_handler would be. The default
+// async_handler must in some way report all errors passed to it, when possible,
+// and must then invoke std::terminate or equivalent.
+inline void defaultAsyncHandler(exception_list ExceptionList) {
+  std::cerr
+      << "Implementation-defined default async_handler caught exceptions:";
+  for (auto &Exception : ExceptionList) {
+    try {
+      if (Exception) {
+        std::rethrow_exception(Exception);
+      }
+    } catch (const std::exception &E) {
+      std::cerr << "\n\t" << E.what();
+    }
+  }
+  std::cerr << std::endl;
+  std::terminate();
+}
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_DETAIL_DEFAULT_ASYNC_HANDLER_HPP
diff --git a/libsycl/include/sycl/__impl/device.hpp b/libsycl/include/sycl/__impl/device.hpp
index 55b624f8fcbd5..fa4c888d66582 100644
--- a/libsycl/include/sycl/__impl/device.hpp
+++ b/libsycl/include/sycl/__impl/device.hpp
@@ -52,7 +52,7 @@ class _LIBSYCL_EXPORT device {
 
   /// Constructs a SYCL device instance using the default device (device chosen
   /// by default device selector).
-  device();
+  device() : device(default_selector_v) {}
 
   /// Constructs a SYCL device instance using the device
   /// identified by the provided device selector.
diff --git a/libsycl/include/sycl/__impl/property_list.hpp b/libsycl/include/sycl/__impl/property_list.hpp
new file mode 100644
index 0000000000000..f0718564cbfd2
--- /dev/null
+++ b/libsycl/include/sycl/__impl/property_list.hpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the SYCL property_list type, which
+/// contains zero or more properties and is used as an optional parameter in
+/// SYCL runtime classes constructors. Each of those properties augments the
+/// semantics of the class with a particular feature.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_PROPERTY_LIST_HPP
+#define _LIBSYCL___IMPL_PROPERTY_LIST_HPP
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+/// Collection of properties for SYCL objects. Supported properties are defined
+/// by exact object the property_list passed to.
+// Just a placeholder for initial stage.
+class property_list {
+public:
+  template <typename... Properties>
+  property_list([[maybe_unused]] Properties... props) {}
+};
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_PROPERTY_LIST_HPP
diff --git a/libsycl/include/sycl/__impl/queue.hpp b/libsycl/include/sycl/__impl/queue.hpp
new file mode 100644
index 0000000000000..e475e83ec0a04
--- /dev/null
+++ b/libsycl/include/sycl/__impl/queue.hpp
@@ -0,0 +1,159 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the declaration of the SYCL queue class, which
+/// schedules kernels on a device.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_QUEUE_HPP
+#define _LIBSYCL___IMPL_QUEUE_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/detail/default_async_handler.hpp>
+#include <sycl/__impl/detail/obj_utils.hpp>
+
+#include <sycl/__impl/async_handler.hpp>
+#include <sycl/__impl/device.hpp>
+#include <sycl/__impl/property_list.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+class context;
+
+namespace detail {
+class QueueImpl;
+} // namespace detail
+
+// SYCL 2020 4.6.5. Queue class.
+class _LIBSYCL_EXPORT queue {
+public:
+  queue(const queue &rhs) = default;
+
+  queue(queue &&rhs) = default;
+
+  queue &operator=(const queue &rhs) = default;
+
+  queue &operator=(queue &&rhs) = default;
+
+  friend bool operator==(const queue &lhs, const queue &rhs) {
+    return lhs.impl == rhs.impl;
+  }
+
+  friend bool operator!=(const queue &lhs, const queue &rhs) {
+    return !(lhs == rhs);
+  }
+
+  /// Constructs a SYCL queue instance using the device returned by an instance
+  /// of default_selector.
+  ///
+  /// \param propList is a list of properties for queue construction.
+  explicit queue(const property_list &propList = {})
+      : queue(detail::SelectDevice(default_selector_v),
+              detail::defaultAsyncHandler, propList) {}
+
+  /// Constructs a SYCL queue instance with an async_handler using the device
+  /// returned by an instance of default_selector.
+  ///
+  /// \param asyncHandler is a SYCL asynchronous exception handler.
+  /// \param propList is a list of properties for queue construction.
+  explicit queue(const async_handler &asyncHandler,
+                 const property_list &propList = {})
+      : queue(detail::SelectDevice(default_selector_v), asyncHandler,
+              propList) {}
+
+  /// Constructs a SYCL queue instance using the device identified by the
+  /// device selector provided.
+  /// \param deviceSelector is SYCL 2020 Device Selector, a simple callable that
+  /// takes a device and returns an int
+  /// \param propList is a list of properties for queue construction.
+  template <
+      typename DeviceSelector,
+      typename = detail::EnableIfDeviceSelectorIsInvocable<DeviceSelector>>
+  explicit queue(const DeviceSelector &deviceSelector,
+                 const property_list &propList = {})
+      : queue(detail::SelectDevice(deviceSelector), detail::defaultAsyncHandler,
+              propList) {}
+
+  /// Constructs a SYCL queue instance using the device identified by the
+  /// device selector provided.
+  /// \param deviceSelector is SYCL 2020 Device Selector, a simple callable that
+  /// takes a device and returns an int
+  /// \param asyncHandler is a SYCL asynchronous exception handler.
+  /// \param propList is a list of properties for queue construction.
+  template <
+      typename DeviceSelector,
+      typename = detail::EnableIfDeviceSelectorIsInvocable<DeviceSelector>>
+  explicit queue(const DeviceSelector &deviceSelector,
+                 const async_handler &asyncHandler,
+                 const property_list &propList = {})
+      : queue(detail::SelectDevice(deviceSelector), asyncHandler, propList) {}
+
+  /// Constructs a SYCL queue instance using the device provided.
+  ///
+  /// \param syclDevice is an instance of SYCL device.
+  /// \param propList is a list of properties for queue construction.
+  explicit queue(const device &syclDevice, const property_list &propList = {})
+      : queue(syclDevice, detail::defaultAsyncHandler, propList) {}
+
+  /// Constructs a SYCL queue instance with an async_handler using the device
+  /// provided.
+  ///
+  /// \param syclDevice is an instance of SYCL device.
+  /// \param asyncHandler is a SYCL asynchronous exception handler.
+  /// \param propList is a list of properties for queue construction.
+  explicit queue(const device &syclDevice, const async_handler &asyncHandler,
+                 const property_list &propList = {});
+
+  /// Returns the SYCL backend that is associated with this queue.
+  ///
+  /// \return the backend associated with this queue.
+  backend get_backend() const noexcept;
+
+  /// Returns context that is associated with this queue.
+  ///
+  /// \return an associated SYCL context.
+  context get_context() const;
+
+  /// Returns device that is associated with this queue.
+  ///
+  /// \return SYCL device this queue was constructed with.
+  device get_device() const;
+
+  /// Returns whether the queue is in order or out of order.
+  ///
+  /// Equivalent to has_property<property::queue::in_order>().
+  ///
+  /// \return true if queue is in order.
+  bool is_in_order() const;
+
+  /// Queries SYCL queue for information.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param> typename Param::return_type get_info() const;
+
+  /// Queries SYCL queue for SYCL backend-specific information.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param>
+  typename Param::return_type get_backend_info() const;
+
+private:
+  queue(const std::shared_ptr<detail::QueueImpl> &Impl) : impl(Impl) {}
+  std::shared_ptr<detail::QueueImpl> impl;
+
+  friend sycl::detail::ImplUtils;
+}; // class queue
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+template <>
+struct std::hash<sycl::queue> : public sycl::detail::HashBase<sycl::queue> {};
+
+#endif // _LIBSYCL___IMPL_QUEUE_HPP
diff --git a/libsycl/include/sycl/__impl/usm_alloc_type.hpp b/libsycl/include/sycl/__impl/usm_alloc_type.hpp
new file mode 100644
index 0000000000000..5455202754d0e
--- /dev/null
+++ b/libsycl/include/sycl/__impl/usm_alloc_type.hpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_USM_ALLOC_TYPE_HPP
+#define _LIBSYCL___IMPL_USM_ALLOC_TYPE_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace usm {
+
+// SYCL 2020 4.8.2. Kinds of unified shared memory.
+enum class alloc : char { host = 0, device = 1, shared = 2, unknown = 3 };
+
+} // namespace usm
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_USM_ALLOC_TYPE_HPP
diff --git a/libsycl/include/sycl/__impl/usm_functions.hpp b/libsycl/include/sycl/__impl/usm_functions.hpp
new file mode 100644
index 0000000000000..c4bba0c2b144c
--- /dev/null
+++ b/libsycl/include/sycl/__impl/usm_functions.hpp
@@ -0,0 +1,300 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_USM_FUNCTIONS_HPP
+#define _LIBSYCL___IMPL_USM_FUNCTIONS_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <sycl/__impl/context.hpp>
+#include <sycl/__impl/queue.hpp>
+#include <sycl/__impl/usm_alloc_type.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+// SYCL 2020 4.8.3.2. Device allocation functions.
+
+/// Allocates device USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclDevice device that is used for allocation.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which is allocated on
+/// syclDevice and which must eventually be deallocated with sycl::free in order
+/// to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_device(std::size_t numBytes,
+                                    const device &syclDevice,
+                                    const context &syclContext,
+                                    const property_list &propList = {});
+
+/// Allocates device USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclDevice device that is used for allocation.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which is allocated on
+/// syclDevice and which must eventually be deallocated with sycl::free in order
+/// to avoid a memory leak.
+template <typename T>
+T *malloc_device(std::size_t count, const device &syclDevice,
+                 const context &syclContext,
+                 const property_list &propList = {}) {
+  // TODO: to rewrite with aligned_malloc_device once it's supported in
+  // liboffload.
+  return static_cast<T *>(
+      malloc_device(count * sizeof(T), syclDevice, syclContext, propList));
+}
+
+/// Allocates device USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclQueue queue that provides the device and context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which is allocated on
+/// syclDevice and which must eventually be deallocated with sycl::free in order
+/// to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_device(std::size_t numBytes,
+                                    const queue &syclQueue,
+                                    const property_list &propList = {});
+
+/// Allocates device USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclQueue queue that provides the device and context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which is allocated on
+/// syclDevice and which must eventually be deallocated with sycl::free in order
+/// to avoid a memory leak.
+template <typename T>
+T *malloc_device(std::size_t count, const queue &syclQueue,
+                 const property_list &propList = {}) {
+  return malloc_device<T>(count, syclQueue.get_device(),
+                          syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.3. Host allocation functions.
+
+/// Allocates host USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclContext context that should have access to the allocated memory.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_host(std::size_t numBytes,
+                                  const context &syclContext,
+                                  const property_list &propList = {});
+
+/// Allocates host USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclContext context that should have access to the allocated memory.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+template <typename T>
+T *malloc_host(std::size_t count, const context &syclContext,
+               const property_list &propList = {}) {
+  // TODO: to rewrite with aligned_malloc_host once it's supported in
+  // liboffload.
+  return static_cast<T *>(
+      malloc_host(count * sizeof(T), syclContext, propList));
+}
+
+/// Allocates host USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclQueue queue that provides the context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_host(std::size_t numBytes, const queue &syclQueue,
+                                  const property_list &propList = {});
+
+/// Allocates host USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclQueue queue that provides the context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+template <typename T>
+T *malloc_host(std::size_t count, const queue &syclQueue,
+               const property_list &propList = {}) {
+  return malloc_host<T>(count, syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.4. Shared allocation functions.
+
+/// Allocates shared  USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclDevice device that is used for allocation.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_shared(std::size_t numBytes,
+                                    const device &syclDevice,
+                                    const context &syclContext,
+                                    const property_list &propList = {});
+
+/// Allocates shared  USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclDevice device that is used for allocation.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+template <typename T>
+T *malloc_shared(std::size_t count, const device &syclDevice,
+                 const context &syclContext,
+                 const property_list &propList = {}) {
+  // TODO: to rewrite with aligned_malloc_shared once it's supported in
+  // liboffload.
+  return static_cast<T *>(
+      malloc_shared(count * sizeof(T), syclDevice, syclContext, propList));
+}
+
+/// Allocates shared  USM.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclQueue queue that provides the device and context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+void *_LIBSYCL_EXPORT malloc_shared(std::size_t numBytes,
+                                    const queue &syclQueue,
+                                    const property_list &propList = {});
+
+/// Allocates shared  USM.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclQueue queue that provides the device and context.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak.
+template <typename T>
+T *malloc_shared(std::size_t count, const queue &syclQueue,
+                 const property_list &propList = {}) {
+  return malloc_shared<T>(count, syclQueue.get_device(),
+                          syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.5. Parameterized allocation functions
+
+/// Allocates USM of type `kind`.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclDevice device that is used for allocation. The syclDevice
+/// parameter is ignored if kind is usm::alloc::host.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param kind type of memory to allocate.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak. If there are
+/// not enough resources to allocate the requested memory, these functions
+/// return nullptr.
+void *_LIBSYCL_EXPORT malloc(std::size_t numBytes, const device &syclDevice,
+                             const context &syclContext, usm::alloc kind,
+                             const property_list &propList = {});
+
+/// Allocates USM of type `kind`.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclDevice device that is used for allocation. The syclDevice
+/// parameter is ignored if kind is usm::alloc::host.
+/// \param syclContext context that contains syclDevice or its parent device if
+/// syclDevice is a subdevice.
+/// \param kind type of memory to allocate.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak. If there are
+/// not enough resources to allocate the requested memory, these functions
+/// return nullptr.
+template <typename T>
+T *malloc(std::size_t count, const device &syclDevice,
+          const context &syclContext, usm::alloc kind,
+          const property_list &propList = {}) {
+  // TODO: to rewrite with aligned_malloc once it's supported in liboffload.
+  return static_cast<T *>(
+      malloc(count * sizeof(T), syclDevice, syclContext, kind, propList));
+}
+
+/// Allocates USM of type `kind`.
+///
+/// \param numBytes  allocation size that is specified in bytes.
+/// \param syclQueue queue that provides the device and context.
+/// \param kind type of memory to allocate.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak. If there are
+/// not enough resources to allocate the requested memory, these functions
+/// return nullptr.
+void *_LIBSYCL_EXPORT malloc(std::size_t numBytes, const queue &syclQueue,
+                             usm::alloc kind,
+                             const property_list &propList = {});
+
+/// Allocates USM of type `kind`.
+///
+/// \param count  allocation size that is specified in number of elements of
+/// type T.
+/// \param syclQueue queue that provides the device and context.
+/// \param kind type of memory to allocate.
+/// \param propList properties for the memory allocation.
+/// \return a pointer to the newly allocated memory, which must eventually be
+/// deallocated with sycl::free in order to avoid a memory leak. If there are
+/// not enough resources to allocate the requested memory, these functions
+/// return nullptr.
+template <typename T>
+T *malloc(std::size_t count, const queue &syclQueue, usm::alloc kind,
+          const property_list &propList = {}) {
+  return malloc<T>(count, syclQueue.get_device(), syclQueue.get_context(), kind,
+                   propList);
+}
+
+// SYCL 2020 4.8.3.6. Memory deallocation functions
+
+/// Deallocate USM of any kind.
+///
+/// \param ptr pointer that satisfies the following preconditions: points to
+/// memory allocated against ctxt using one of the USM allocation routines, or
+/// is a null pointer, ptr has not previously been deallocated; there are no
+/// in-progress or enqueued commands using the memory pointed to by ptr.
+/// \param ctxt context that is associated with ptr.
+void _LIBSYCL_EXPORT free(void *ptr, const context &ctxt);
+
+/// Deallocate USM of any kind.
+///
+/// Equivalent to free(ptr, q.get_context()).
+///
+/// \param ptr pointer that satisfies the following preconditions: points to
+/// memory allocated against ctxt using one of the USM allocation routines, or
+/// is a null pointer, ptr has not previously been deallocated; there are no
+/// in-progress or enqueued commands using the memory pointed to by ptr.
+/// \param q queue to determine the context associated with ptr.
+void _LIBSYCL_EXPORT free(void *ptr, const queue &q);
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_USM_FUNCTIONS_HPP
diff --git a/libsycl/include/sycl/sycl.hpp b/libsycl/include/sycl/sycl.hpp
index 3e7f81092256c..3fcf088f45535 100644
--- a/libsycl/include/sycl/sycl.hpp
+++ b/libsycl/include/sycl/sycl.hpp
@@ -14,9 +14,12 @@
 #ifndef _LIBSYCL_SYCL_HPP
 #define _LIBSYCL_SYCL_HPP
 
+#include <sycl/__impl/context.hpp>
 #include <sycl/__impl/device.hpp>
 #include <sycl/__impl/device_selector.hpp>
 #include <sycl/__impl/exception.hpp>
 #include <sycl/__impl/platform.hpp>
+#include <sycl/__impl/queue.hpp>
+#include <sycl/__impl/usm_functions.hpp>
 
 #endif // _LIBSYCL_SYCL_HPP
diff --git a/libsycl/src/CMakeLists.txt b/libsycl/src/CMakeLists.txt
index 0a83f2ef36443..67ba7d28968de 100644
--- a/libsycl/src/CMakeLists.txt
+++ b/libsycl/src/CMakeLists.txt
@@ -81,14 +81,19 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
 endfunction(add_sycl_rt_library)
 
 set(LIBSYCL_SOURCES
+    "context.cpp"
     "exception.cpp"
     "exception_list.cpp"
     "device.cpp"
     "device_selector.cpp"
     "platform.cpp"
+    "queue.cpp"
+    "usm_functions.cpp"
+    "detail/context_impl.cpp"
     "detail/device_impl.cpp"
     "detail/global_objects.cpp"
     "detail/platform_impl.cpp"
+    "detail/queue_impl.cpp"
     "detail/offload/offload_utils.cpp"
     "detail/offload/offload_topology.cpp"
 )
diff --git a/libsycl/src/context.cpp b/libsycl/src/context.cpp
new file mode 100644
index 0000000000000..e50c8bde98c48
--- /dev/null
+++ b/libsycl/src/context.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <sycl/__impl/device.hpp>
+
+#include <detail/context_impl.hpp>
+#include <detail/platform_impl.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+backend context::get_backend() const noexcept { return impl->getBackend(); }
+
+platform context::get_platform() const {
+  return detail::createSyclObjFromImpl<platform>(impl->getPlatformImpl());
+}
+
+std::vector<device> context::get_devices() const {
+  std::vector<device> Devices;
+
+  impl->iterateDevices([&Devices](detail::DeviceImpl *DevImpl) {
+    assert(DevImpl && "Device impl can't be nullptr");
+    Devices.push_back(detail::createSyclObjFromImpl<device>(*DevImpl));
+  });
+
+  return Devices;
+}
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/context_impl.cpp b/libsycl/src/detail/context_impl.cpp
new file mode 100644
index 0000000000000..a3353e9304c44
--- /dev/null
+++ b/libsycl/src/detail/context_impl.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <detail/context_impl.hpp>
+#include <detail/platform_impl.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+void ContextImpl::iterateDevices(
+    const std::function<void(DeviceImpl *)> &callback) const {
+  // Intentionally don't store devices in context now. This class should be
+  // reimplemented once liboffload adds context support. Treat context as
+  // default context that is associated with all devices in the platform.
+  return MPlatform.iterateDevices(info::device_type::all, callback);
+}
+
+backend ContextImpl::getBackend() const { return MPlatform.getBackend(); }
+
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/context_impl.hpp b/libsycl/src/detail/context_impl.hpp
new file mode 100644
index 0000000000000..0e58e61d080bf
--- /dev/null
+++ b/libsycl/src/detail/context_impl.hpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL_CONTEXT_IMPL
+#define _LIBSYCL_CONTEXT_IMPL
+
+#include <sycl/__impl/context.hpp>
+#include <sycl/__impl/detail/config.hpp>
+
+#include <OffloadAPI.h>
+
+#include <functional>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+namespace detail {
+
+class PlatformImpl;
+class DeviceImpl;
+
+/// Context dummy (w/o liboffload handle) that represents all devices
+/// in platform.
+///
+/// Presence of context object is essential for many APIs. This dummy is a way
+/// to support them in case of absence of context support in liboffload. For
+/// backends where context exists and participates in operations liboffload
+/// plugins create and use default context that represents all devices in that
+/// platform. Duplicating this logic here.
+class ContextImpl : public std::enable_shared_from_this<ContextImpl> {
+  struct Private {
+    explicit Private() = default;
+  };
+
+public:
+  /// Constructs a ContextImpl using a platform.
+  ///
+  /// Newly created instance represents all devices in platform.
+  ///
+  /// \param Platform is a platform to associate this context with.
+  ContextImpl(PlatformImpl &Platform, Private) : MPlatform(Platform) {}
+
+  /// Constructs a ContextImpl with a provided arguments. Variadic helper.
+  /// Restrics ways of ContextImpl creation.
+  template <typename... Ts>
+  static std::shared_ptr<ContextImpl> create(Ts &&...args) {
+    return std::make_shared<ContextImpl>(std::forward<Ts>(args)..., Private{});
+  }
+
+  /// Returns associated platform
+  ///
+  /// \return platform implementation object this context is associated with.
+  PlatformImpl &getPlatformImpl() const { return MPlatform; }
+
+  /// Calls "callback" with every device associated
+  /// with this context.
+  void iterateDevices(const std::function<void(DeviceImpl *)> &callback) const;
+
+  /// Returns backend of the platform this context is associated with.
+  ///
+  /// \return SYCL backend.
+  backend getBackend() const;
+
+private:
+  PlatformImpl &MPlatform;
+};
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_CONTEXT_IMPL
diff --git a/libsycl/src/detail/device_impl.cpp b/libsycl/src/detail/device_impl.cpp
index de702cc4b7839..4efc4d458c37e 100644
--- a/libsycl/src/detail/device_impl.cpp
+++ b/libsycl/src/detail/device_impl.cpp
@@ -22,11 +22,16 @@ bool DeviceImpl::has(aspect Aspect) const {
   case (aspect::accelerator):
     return isAccelerator();
   case (aspect::custom):
-    return false;
   case (aspect::emulated):
-    return false;
   case (aspect::host_debuggable):
     return false;
+  case (aspect::usm_device_allocations):
+  case (aspect::usm_host_allocations):
+  case (aspect::usm_shared_allocations):
+    // liboffload works with USM only and has no query to check support. We
+    // assume that USM is always supported otherwise lifoffload won't be able to
+    // work with device at all.
+    return true;
   default:
     // Other aspects are not implemented yet
     return false;
@@ -49,7 +54,9 @@ bool DeviceImpl::isAccelerator() const {
   return getDeviceType() == info::device_type::accelerator;
 }
 
-backend DeviceImpl::getBackend() const { return MPlatform.getBackend(); }
+backend DeviceImpl::getBackend() const noexcept {
+  return MPlatform.getBackend();
+}
 
 } // namespace detail
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/device_impl.hpp b/libsycl/src/detail/device_impl.hpp
index 5fd0893c99125..c83b767aad02f 100644
--- a/libsycl/src/detail/device_impl.hpp
+++ b/libsycl/src/detail/device_impl.hpp
@@ -65,7 +65,7 @@ class DeviceImpl {
   /// Returns the backend associated with this device.
   ///
   /// \return the sycl::backend associated with this device.
-  backend getBackend() const;
+  backend getBackend() const noexcept;
 
   /// Returns the implementation class object of platform associated with this
   /// device.
@@ -115,6 +115,8 @@ class DeviceImpl {
       static_assert(false && "Info descriptor is not properly supported");
   }
 
+  ol_device_handle_t getOLHandle() { return MOffloadDevice; }
+
 private:
   ol_device_handle_t MOffloadDevice = {};
   PlatformImpl &MPlatform;
diff --git a/libsycl/src/detail/global_objects.cpp b/libsycl/src/detail/global_objects.cpp
index fa7274d137040..06e44a36a21e2 100644
--- a/libsycl/src/detail/global_objects.cpp
+++ b/libsycl/src/detail/global_objects.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <detail/device_impl.hpp>
 #include <detail/global_objects.hpp>
 #include <detail/platform_impl.hpp>
 
diff --git a/libsycl/src/detail/offload/offload_utils.cpp b/libsycl/src/detail/offload/offload_utils.cpp
index 9a2609daddcee..e4e68eb83747e 100644
--- a/libsycl/src/detail/offload/offload_utils.cpp
+++ b/libsycl/src/detail/offload/offload_utils.cpp
@@ -88,5 +88,22 @@ info::device_type convertDeviceTypeToSYCL(ol_device_type_t DeviceType) {
   }
 }
 
+ol_alloc_type_t convertUSMTypeToOL(usm::alloc USMType) {
+  switch (USMType) {
+  case usm::alloc::host:
+    return OL_ALLOC_TYPE_HOST;
+  case usm::alloc::device:
+    return OL_ALLOC_TYPE_DEVICE;
+  case usm::alloc::shared:
+    return OL_ALLOC_TYPE_MANAGED;
+  default:
+    // usm::alloc::unknown can be returned to user from get_pointer_type but it
+    // can't be converted to a valid backend type and there is no need to do
+    // that.
+    throw exception(sycl::make_error_code(sycl::errc::runtime),
+                    "USM type is not supported");
+  }
+}
+
 } // namespace detail
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/offload/offload_utils.hpp b/libsycl/src/detail/offload/offload_utils.hpp
index f32326fb87fc9..222f49fd68231 100644
--- a/libsycl/src/detail/offload/offload_utils.hpp
+++ b/libsycl/src/detail/offload/offload_utils.hpp
@@ -13,6 +13,7 @@
 #include <sycl/__impl/detail/config.hpp>
 #include <sycl/__impl/exception.hpp>
 #include <sycl/__impl/info/device_type.hpp>
+#include <sycl/__impl/usm_alloc_type.hpp>
 
 #include <OffloadAPI.h>
 
@@ -37,6 +38,10 @@ inline std::string formatCodeString(ol_result_t Result) {
          std::string(stringifyErrorCode(Result->Code)) + ") " + Result->Details;
 }
 
+inline bool isSuccess(const ol_result_t &Result) {
+  return Result == OL_SUCCESS;
+}
+
 /// Checks liboffload API call result.
 ///
 /// Used after calling the API without check.
@@ -48,7 +53,7 @@ inline std::string formatCodeString(ol_result_t Result) {
 /// \throw sycl::runtime_exception if the call was not successful.
 template <sycl::errc errc = sycl::errc::runtime>
 void checkAndThrow(ol_result_t Result) {
-  if (Result != OL_SUCCESS) {
+  if (!isSuccess(Result)) {
     throw sycl::exception(sycl::make_error_code(errc),
                           detail::formatCodeString(Result));
   }
@@ -100,6 +105,13 @@ ol_device_type_t convertDeviceTypeToOL(info::device_type DeviceType);
 /// \returns SYCL device type matching specified liboffload device type.
 info::device_type convertDeviceTypeToSYCL(ol_device_type_t DeviceType);
 
+/// Converts SYCL USM  type to liboffload type.
+///
+/// \param DeviceType SYCL USM type.
+///
+/// \returns ol_alloc_type_t matching specified SYCL USM type.
+ol_alloc_type_t convertUSMTypeToOL(usm::alloc USMType);
+
 /// Helper to map SYCL information descriptors to OL_<HANDLE>_INFO_<SMTH>.
 ///
 /// Typical usage:
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
index 0116ad68d4bdd..a09f9068a9dfd 100644
--- a/libsycl/src/detail/platform_impl.cpp
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -9,6 +9,7 @@
 #include <sycl/__impl/detail/config.hpp>
 #include <sycl/__impl/detail/obj_utils.hpp>
 
+#include <detail/context_impl.hpp>
 #include <detail/device_impl.hpp>
 #include <detail/global_objects.hpp>
 #include <detail/platform_impl.hpp>
@@ -75,6 +76,8 @@ PlatformImpl::PlatformImpl(ol_platform_handle_t Platform, size_t PlatformIndex,
                   MRootDevices.emplace_back(std::make_unique<DeviceImpl>(
                       Device, *this, DeviceImpl::PrivateTag{}));
                 });
+
+  MDefaultContext = ContextImpl::create(*this);
 }
 
 const std::vector<DeviceImplUPtr> &PlatformImpl::getRootDevices() const {
@@ -119,5 +122,11 @@ void PlatformImpl::iterateDevices(
   }
 }
 
+ContextImpl &PlatformImpl::getDefaultContext() {
+  assert(MDefaultContext &&
+         "Default context for platform must be created in platform ctor");
+  return *MDefaultContext.get();
+}
+
 } // namespace detail
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
index e23ce6a492281..9699eaaec6b6c 100644
--- a/libsycl/src/detail/platform_impl.hpp
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -13,7 +13,6 @@
 #include <sycl/__impl/detail/config.hpp>
 #include <sycl/__impl/platform.hpp>
 
-#include <detail/device_impl.hpp>
 #include <detail/offload/offload_utils.hpp>
 
 #include <OffloadAPI.h>
@@ -29,6 +28,7 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 namespace detail {
 
 class DeviceImpl;
+class ContextImpl;
 
 using PlatformImplUPtr = std::unique_ptr<PlatformImpl>;
 using DeviceImplUPtr = std::unique_ptr<DeviceImpl>;
@@ -121,15 +121,28 @@ class PlatformImpl {
   void iterateDevices(info::device_type DeviceType,
                       std::function<void(DeviceImpl *)> callback) const;
 
-private:
+  /// Returns all root devices for platform
+  ///
+  /// \return reference to collection of root devices
   const std::vector<DeviceImplUPtr> &getRootDevices() const;
 
-  ol_platform_handle_t MOffloadPlatform{};
-  size_t MOffloadPlatformIndex{};
-  ol_platform_backend_t MOffloadBackend{OL_PLATFORM_BACKEND_UNKNOWN};
-  backend MBackend{};
+  /// Returns context dummy (w/o liboffload handle) that represents all devices
+  /// in platform.
+  ///
+  /// \return context implementation object
+  ContextImpl &getDefaultContext();
+
+private:
+  const ol_platform_handle_t MOffloadPlatform{};
+  const size_t MOffloadPlatformIndex{};
+
+  ol_platform_backend_t MOffloadBackend;
+  backend MBackend;
 
   std::vector<DeviceImplUPtr> MRootDevices;
+
+  // To be redesigned  once liboffload supports context
+  std::shared_ptr<ContextImpl> MDefaultContext;
 };
 
 } // namespace detail
diff --git a/libsycl/src/detail/queue_impl.cpp b/libsycl/src/detail/queue_impl.cpp
new file mode 100644
index 0000000000000..dec2d7d5507aa
--- /dev/null
+++ b/libsycl/src/detail/queue_impl.cpp
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <detail/device_impl.hpp>
+#include <detail/queue_impl.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+QueueImpl::QueueImpl(DeviceImpl &deviceImpl, const async_handler &asyncHandler,
+                     const property_list &propList, PrivateTag)
+    : MIsInorder(false), MAsyncHandler(asyncHandler), MPropList(propList),
+      MDevice(deviceImpl),
+      MContext(MDevice.getPlatformImpl().getDefaultContext()) {}
+
+backend QueueImpl::getBackend() const noexcept { return MDevice.getBackend(); }
+
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/queue_impl.hpp b/libsycl/src/detail/queue_impl.hpp
new file mode 100644
index 0000000000000..81c327fcd03cc
--- /dev/null
+++ b/libsycl/src/detail/queue_impl.hpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL_QUEUE_IMPL
+#define _LIBSYCL_QUEUE_IMPL
+
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/queue.hpp>
+
+#include <OffloadAPI.h>
+
+#include <memory>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+namespace detail {
+
+class ContextImpl;
+class DeviceImpl;
+
+class QueueImpl : public std::enable_shared_from_this<QueueImpl> {
+  struct PrivateTag {
+    explicit PrivateTag() = default;
+  };
+
+public:
+  ~QueueImpl() = default;
+
+  /// Constructs a SYCL queue from a device using an asyncHandler and
+  /// propList provided.
+  ///
+  /// \param deviceImpl is a SYCL device that is used to dispatch tasks
+  /// submitted to the queue.
+  /// \param asyncHandler is a SYCL asynchronous exception handler.
+  /// \param propList is a list of properties to use for queue construction.
+  explicit QueueImpl(DeviceImpl &deviceImpl, const async_handler &asyncHandler,
+                     const property_list &propList, PrivateTag);
+
+  /// Constructs a QueueImpl with a provided arguments. Variadic helper.
+  /// Restrics ways of QueueImpl creation.
+  template <typename... Ts>
+  static std::shared_ptr<QueueImpl> create(Ts &&...args) {
+    return std::make_shared<QueueImpl>(std::forward<Ts>(args)..., PrivateTag{});
+  }
+
+  /// Returns backend this queue is associated with.
+  ///
+  /// \return SYCL backend.
+  backend getBackend() const noexcept;
+
+  /// Returns context this queue is associated with.
+  ///
+  /// \return context implementation object.
+  ContextImpl &getContext() { return MContext; }
+
+  /// Returns device this queue is associated with.
+  ///
+  /// \return device implementation object.
+  DeviceImpl &getDevice() { return MDevice; }
+
+  /// Returns whether the queue is in order or out of order.
+  ///
+  /// \return true if queue is in order.
+  bool isInOrder() const { return MIsInorder; }
+
+private:
+  // ol_queue_handle_t MOffloadQueue = {};
+  const bool MIsInorder;
+  const async_handler MAsyncHandler;
+  const property_list MPropList;
+  DeviceImpl &MDevice;
+  ContextImpl &MContext;
+};
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_QUEUE_IMPL
diff --git a/libsycl/src/device.cpp b/libsycl/src/device.cpp
index db61d2ff3a22e..a499919190db2 100644
--- a/libsycl/src/device.cpp
+++ b/libsycl/src/device.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <sycl/__impl/device.hpp>
-
 #include <detail/device_impl.hpp>
 #include <detail/platform_impl.hpp>
 
@@ -15,8 +13,6 @@
 
 _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
-device::device() : device(default_selector_v) {}
-
 bool device::is_cpu() const { return impl->isCPU(); }
 
 bool device::is_gpu() const { return impl->isGPU(); }
diff --git a/libsycl/src/queue.cpp b/libsycl/src/queue.cpp
new file mode 100644
index 0000000000000..faed274674447
--- /dev/null
+++ b/libsycl/src/queue.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <sycl/__impl/context.hpp>
+#include <sycl/__impl/queue.hpp>
+
+#include <detail/context_impl.hpp>
+#include <detail/device_impl.hpp>
+#include <detail/queue_impl.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+queue::queue(const device &syclDevice, const async_handler &asyncHandler,
+             const property_list &propList) {
+  impl = detail::QueueImpl::create(*detail::getSyclObjImpl(syclDevice),
+                                   asyncHandler, propList);
+}
+
+backend queue::get_backend() const noexcept { return impl->getBackend(); }
+
+context queue::get_context() const {
+  return detail::createSyclObjFromImpl<context>(impl->getContext());
+}
+
+device queue::get_device() const {
+  return detail::createSyclObjFromImpl<device>(impl->getDevice());
+}
+
+bool queue::is_in_order() const { return impl->isInOrder(); }
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/usm_functions.cpp b/libsycl/src/usm_functions.cpp
new file mode 100644
index 0000000000000..de03b7fa79563
--- /dev/null
+++ b/libsycl/src/usm_functions.cpp
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <sycl/__impl/usm_functions.hpp>
+
+#include <detail/device_impl.hpp>
+#include <detail/offload/offload_utils.hpp>
+
+#include <OffloadAPI.h>
+
+#include <algorithm>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+// SYCL 2020 4.8.3.2. Device allocation functions.
+
+void *malloc_device(std::size_t numBytes, const device &syclDevice,
+                    const context &syclContext, const property_list &propList) {
+  return malloc(numBytes, syclDevice, syclContext, usm::alloc::device,
+                propList);
+}
+
+void *malloc_device(std::size_t numBytes, const queue &syclQueue,
+                    const property_list &propList) {
+  return malloc_device(numBytes, syclQueue.get_device(),
+                       syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.3. Host allocation functions.
+
+void *malloc_host(std::size_t numBytes, const context &syclContext,
+                  const property_list &propList) {
+  auto ContextDevices = syclContext.get_devices();
+  assert(!ContextDevices.empty() && "Context can't be created without device");
+  if (std::none_of(
+          ContextDevices.begin(), ContextDevices.end(),
+          [](device Dev) { return Dev.has(aspect::usm_host_allocations); }))
+    throw sycl::exception(
+        sycl::errc::feature_not_supported,
+        "All devices of context do not support host USM allocations.");
+  return malloc(numBytes, ContextDevices[0], syclContext, usm::alloc::host,
+                propList);
+}
+
+void *malloc_host(std::size_t numBytes, const queue &syclQueue,
+                  const property_list &propList) {
+  return malloc_host(numBytes, syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.4. Shared allocation functions.
+
+void *malloc_shared(std::size_t numBytes, const device &syclDevice,
+                    const context &syclContext, const property_list &propList) {
+  return malloc(numBytes, syclDevice, syclContext, usm::alloc::shared,
+                propList);
+}
+
+void *malloc_shared(std::size_t numBytes, const queue &syclQueue,
+                    const property_list &propList) {
+  return malloc_shared(numBytes, syclQueue.get_device(),
+                       syclQueue.get_context(), propList);
+}
+
+// SYCL 2020 4.8.3.5. Parameterized allocation functions
+
+static aspect getAspectByAllocationKind(usm::alloc kind) {
+  switch (kind) {
+  case usm::alloc::host:
+    return aspect::usm_host_allocations;
+  case usm::alloc::device:
+    return aspect::usm_device_allocations;
+  case usm::alloc::shared:
+    return aspect::usm_shared_allocations;
+  default:
+    assert(false &&
+           "Must be unreachable, usm::unknown allocation can't be requested");
+    // usm::alloc::unknown can be returned to user from get_pointer_type but
+    // it can't be converted to a valid backend type and there is no need to
+    // do that.
+    throw exception(sycl::make_error_code(sycl::errc::runtime),
+                    "USM type is not supported");
+  }
+}
+
+void *malloc(std::size_t numBytes, const device &syclDevice,
+             const context &syclContext, usm::alloc kind,
+             const property_list &propList) {
+  auto ContextDevices = syclContext.get_devices();
+  assert(!ContextDevices.empty() && "Context can't be created without device");
+  if (std::none_of(ContextDevices.begin(), ContextDevices.end(),
+                   [&syclDevice](device Dev) { return Dev == syclDevice; }))
+    throw exception(make_error_code(errc::invalid),
+                    "Specified device is not contained by specified context.");
+  if (!syclDevice.has(getAspectByAllocationKind(kind)))
+    throw sycl::exception(
+        sycl::errc::feature_not_supported,
+        "Device doesn't support requested kind of USM allocation");
+
+  if (!numBytes)
+    return nullptr;
+
+  void *Ptr{};
+  auto Result = detail::callNoCheck(
+      olMemAlloc, detail::getSyclObjImpl(syclDevice)->getOLHandle(),
+      detail::convertUSMTypeToOL(kind), numBytes, &Ptr);
+  assert(!!Result != !!Ptr && "Successful USM allocation can't return nullptr");
+  return detail::isSuccess(Result) ? Ptr : nullptr;
+}
+
+void *malloc(std::size_t numBytes, const queue &syclQueue, usm::alloc kind,
+             const property_list &propList) {
+  return malloc(numBytes, syclQueue.get_device(), syclQueue.get_context(), kind,
+                propList);
+}
+
+// SYCL 2020 4.8.3.6. Memory deallocation functions
+
+void free(void *ptr, const context &ctxt) {
+  std::ignore = ctxt;
+  detail::callAndThrow(olMemFree, ptr);
+}
+
+void free(void *ptr, const queue &q) { return free(ptr, q.get_context()); }
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/test/phase0.cpp b/libsycl/test/phase0.cpp
new file mode 100644
index 0000000000000..5fdcc2cc4a265
--- /dev/null
+++ b/libsycl/test/phase0.cpp
@@ -0,0 +1,33 @@
+// REQUIRES: any-device
+// RUN: %clangxx %sycl_options %s -o %t.out
+// RUN: %t.out
+
+#include <iostream>
+#include <sycl/sycl.hpp>
+
+using namespace sycl;
+
+int main() {
+  queue myQueue;
+
+  int *data = sycl::malloc_shared<int>(1024, myQueue);
+
+  // myQueue.parallel_for(1024, [=](id<1> idx) {
+  //   data[idx] = idx;
+  // });
+
+  // myQueue.wait();
+
+  size_t error{};
+  // for (int i = 0; i < 1024; i++) {
+  //   if ((data[i] != i)) {
+  //     error++;
+  //     std::cerr << "Data mismatch is found: data[" << i << "] = " << data[i]
+  //               << std::endl;
+  //   }
+  // }
+
+  sycl::free(data, myQueue);
+
+  return error > 0;
+}
diff --git a/libsycl/test/usm/alloc_functions.cpp b/libsycl/test/usm/alloc_functions.cpp
new file mode 100644
index 0000000000000..f3ce8441ab580
--- /dev/null
+++ b/libsycl/test/usm/alloc_functions.cpp
@@ -0,0 +1,124 @@
+// REQUIRES: any-device
+// RUN: %clangxx %sycl_options %s -o %t.out
+// RUN: %t.out
+
+#include <sycl/sycl.hpp>
+
+#include <cstddef>
+#include <iostream>
+#include <tuple>
+
+using namespace sycl;
+
+constexpr size_t Align = 256;
+
+struct alignas(Align) Aligned {
+  int x;
+};
+
+int main() {
+  queue q;
+  context ctx = q.get_context();
+  device d = q.get_device();
+
+  auto check = [&q](size_t Alignment, auto AllocFn, int Line = __builtin_LINE(),
+                    int Case = 0) {
+    // First allocation might naturally be over-aligned. Do several of them to
+    // do the verification;
+    decltype(AllocFn()) Arr[10];
+    for (auto *&Elem : Arr)
+      Elem = AllocFn();
+    for (auto *Ptr : Arr) {
+      auto v = reinterpret_cast<uintptr_t>(Ptr);
+      if ((v & (Alignment - 1)) != 0) {
+        std::cout << "Failed at line " << Line << ", case " << Case
+                  << std::endl;
+        assert(false && "Not properly aligned!");
+        break; // To be used with commented out assert above.
+      }
+    }
+    for (auto *Ptr : Arr)
+      free(Ptr, q);
+  };
+
+  // The strictest (largest) fundamental alignment of any type is the alignment
+  // of max_align_t. This is, however, smaller than the minimal alignment
+  // returned by the underlyging runtime as of now.
+  constexpr size_t FAlign = alignof(std::max_align_t);
+
+  auto CheckAll = [&](size_t Expected, auto Funcs,
+                      int Line = __builtin_LINE()) {
+    std::apply(
+        [&](auto... Fs) {
+          int Case = 0;
+          (void)std::initializer_list<int>{
+              (check(Expected, Fs, Line, Case++), 0)...};
+        },
+        Funcs);
+  };
+
+  auto MDevice = [&](auto... args) {
+    return malloc_device(sizeof(std::max_align_t), args...);
+  };
+  CheckAll(FAlign,
+           std::tuple{[&]() { return MDevice(q); },
+                      [&]() { return MDevice(d, ctx); },
+                      [&]() { return MDevice(q, property_list{}); },
+                      [&]() { return MDevice(d, ctx, property_list{}); }});
+
+  auto MHost = [&](auto... args) {
+    return malloc_host(sizeof(std::max_align_t), args...);
+  };
+  CheckAll(FAlign,
+           std::tuple{[&]() { return MHost(q); }, [&]() { return MHost(ctx); },
+                      [&]() { return MHost(q, property_list{}); },
+                      [&]() { return MHost(ctx, property_list{}); }});
+
+  if (d.has(aspect::usm_shared_allocations)) {
+    auto MShared = [&](auto... args) {
+      return malloc_shared(sizeof(std::max_align_t), args...);
+    };
+
+    CheckAll(FAlign,
+             std::tuple{[&]() { return MShared(q); },
+                        [&]() { return MShared(d, ctx); },
+                        [&]() { return MShared(q, property_list{}); },
+                        [&]() { return MShared(d, ctx, property_list{}); }});
+  }
+
+  auto TDevice = [&](auto... args) {
+    return malloc_device<Aligned>(1, args...);
+  };
+  CheckAll(Align, std::tuple{[&]() { return TDevice(q); },
+                             [&]() { return TDevice(d, ctx); }});
+
+  auto THost = [&](auto... args) { return malloc_host<Aligned>(1, args...); };
+  CheckAll(Align, std::tuple{[&]() { return THost(q); },
+                             [&]() { return THost(ctx); }});
+
+  if (d.has(aspect::usm_shared_allocations)) {
+    auto TShared = [&](auto... args) {
+      return malloc_shared<Aligned>(1, args...);
+    };
+    CheckAll(Align, std::tuple{[&]() { return TShared(q); },
+                               [&]() { return TShared(d, ctx); }});
+  }
+
+  auto Malloc = [&](auto... args) {
+    return malloc(sizeof(std::max_align_t), args...);
+  };
+  CheckAll(
+      FAlign,
+      std::tuple{
+          [&]() { return Malloc(q, usm::alloc::host); },
+          [&]() { return Malloc(d, ctx, usm::alloc::host); },
+          [&]() { return Malloc(q, usm::alloc::host, property_list{}); },
+          [&]() { return Malloc(d, ctx, usm::alloc::host, property_list{}); }});
+
+  auto TMalloc = [&](auto... args) { return malloc<Aligned>(1, args...); };
+  CheckAll(Align,
+           std::tuple{[&]() { return TMalloc(q, usm::alloc::host); },
+                      [&]() { return TMalloc(d, ctx, usm::alloc::host); }});
+
+  return 0;
+}



More information about the llvm-commits mailing list