[llvm] [SYCL] Add platform enumeration and info query using liboffload (PR #166927)

Kseniya Tikhomirova via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 20 03:31:24 PST 2025


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

>From b22192afdcbda7441e7a8fe7cbc9a06903e9e6ea Mon Sep 17 00:00:00 2001
From: Kseniya Tikhomirova <kseniya.tikhomirova at intel.com>
Date: Fri, 7 Nov 2025 12:36:59 +0100
Subject: [PATCH 1/7] [SYCL] Add platform enumeration and info query using
 liboffload (#2)

This is part of the SYCL support upstreaming effort. The relevant RFCs can
be found here:

https://discourse.llvm.org/t/rfc-add-full-support-for-the-sycl-programming-model/74080
https://discourse.llvm.org/t/rfc-sycl-runtime-upstreaming/74479

The SYCL runtime is device-agnostic and uses liboffload for offloading to GPU.
This commit adds a dependency on liboffload, implementation of platform::get_platforms, platform::get_backend and platform::get_info methods, initial implementation of sycl-ls tool for manual testing of added functionality.

Plan for next PR:

device/context impl, rest of platform
test infrastructure (depends on L0 liboffload plugin CI, our effort is joined)
ABI tests
---
 libsycl/CMakeLists.txt                        |  18 ++-
 libsycl/docs/index.rst                        |  12 +-
 libsycl/include/sycl/__impl/backend.hpp       |  70 +++++++++++
 libsycl/include/sycl/__impl/detail/config.hpp |   4 +-
 .../sycl/__impl/detail/macro_definitions.hpp  |  52 ++++++++
 .../include/sycl/__impl/detail/obj_base.hpp   |  64 ++++++++++
 libsycl/include/sycl/__impl/exception.hpp     | 116 ++++++++++++++++++
 libsycl/include/sycl/__impl/info/platform.def |   8 ++
 libsycl/include/sycl/__impl/info/platform.hpp |  54 ++++++++
 libsycl/include/sycl/__impl/platform.hpp      |  87 ++++++++++++-
 libsycl/include/sycl/sycl.hpp                 |   1 +
 libsycl/src/CMakeLists.txt                    |  29 ++---
 libsycl/src/detail/global_objects.cpp         |  73 +++++++++++
 libsycl/src/detail/global_objects.hpp         |  33 +++++
 libsycl/src/detail/offload/info_code.hpp      |  30 +++++
 .../src/detail/offload/offload_topology.cpp   |  79 ++++++++++++
 .../src/detail/offload/offload_topology.hpp   | 101 +++++++++++++++
 libsycl/src/detail/offload/offload_utils.cpp  |  65 ++++++++++
 libsycl/src/detail/offload/offload_utils.hpp  |  59 +++++++++
 libsycl/src/detail/platform_impl.cpp          |  65 ++++++++++
 libsycl/src/detail/platform_impl.hpp          | 102 +++++++++++++++
 libsycl/src/exception.cpp                     |  57 +++++++++
 libsycl/src/exception_list.cpp                |  27 ++++
 libsycl/src/platform.cpp                      |  21 +++-
 libsycl/tools/CMakeLists.txt                  |   1 +
 libsycl/tools/sycl-ls/CMakeLists.txt          |  25 ++++
 libsycl/tools/sycl-ls/sycl-ls.cpp             |  70 +++++++++++
 27 files changed, 1292 insertions(+), 31 deletions(-)
 create mode 100644 libsycl/include/sycl/__impl/backend.hpp
 create mode 100644 libsycl/include/sycl/__impl/detail/macro_definitions.hpp
 create mode 100644 libsycl/include/sycl/__impl/detail/obj_base.hpp
 create mode 100644 libsycl/include/sycl/__impl/exception.hpp
 create mode 100644 libsycl/include/sycl/__impl/info/platform.def
 create mode 100644 libsycl/include/sycl/__impl/info/platform.hpp
 create mode 100644 libsycl/src/detail/global_objects.cpp
 create mode 100644 libsycl/src/detail/global_objects.hpp
 create mode 100644 libsycl/src/detail/offload/info_code.hpp
 create mode 100644 libsycl/src/detail/offload/offload_topology.cpp
 create mode 100644 libsycl/src/detail/offload/offload_topology.hpp
 create mode 100644 libsycl/src/detail/offload/offload_utils.cpp
 create mode 100644 libsycl/src/detail/offload/offload_utils.hpp
 create mode 100644 libsycl/src/detail/platform_impl.cpp
 create mode 100644 libsycl/src/detail/platform_impl.hpp
 create mode 100644 libsycl/src/exception.cpp
 create mode 100644 libsycl/src/exception_list.cpp
 create mode 100644 libsycl/tools/CMakeLists.txt
 create mode 100644 libsycl/tools/sycl-ls/CMakeLists.txt
 create mode 100644 libsycl/tools/sycl-ls/sycl-ls.cpp

diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt
index fe08a4249bada..54ef3d4b1878a 100644
--- a/libsycl/CMakeLists.txt
+++ b/libsycl/CMakeLists.txt
@@ -37,8 +37,6 @@ option(LIBSYCL_ENABLE_PEDANTIC "Compile with pedantic enabled." OFF)
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
-set(LIBSYCL_SHARED_OUTPUT_NAME "sycl" CACHE STRING "Output name for the shared libsycl runtime library.")
-
 if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
   set(LIBSYCL_TARGET_SUBDIR ${LLVM_DEFAULT_TARGET_TRIPLE})
   if(LIBSYCL_LIBDIR_SUBDIR)
@@ -65,7 +63,7 @@ set(LIBSYCL_SOURCE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
 
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBSYCL_LIBRARY_DIR})
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBSYCL_LIBRARY_DIR})
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBSYCL_LIBRARY_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_TOOLS_BINARY_DIR})
 
 set(LIBSYCL_MAJOR_VERSION 0)
 set(LIBSYCL_MINOR_VERSION 1)
@@ -117,10 +115,22 @@ add_custom_command(
 install(DIRECTORY "${LIBSYCL_SOURCE_INCLUDE_DIR}/sycl" DESTINATION ${LIBSYCL_INCLUDE_DIR} COMPONENT sycl-headers)
 install(DIRECTORY "${LIBSYCL_SOURCE_INCLUDE_DIR}/CL" DESTINATION ${LIBSYCL_INCLUDE_DIR} COMPONENT sycl-headers)
 
-set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
+set(LIBSYCL_LIB_NAME "sycl")
+set(LIBSYCL_SHARED_OUTPUT_NAME "${LIBSYCL_LIB_NAME}")
+if (CMAKE_SYSTEM_NAME STREQUAL Windows)
+  if (CMAKE_MSVC_RUNTIME_LIBRARY AND (NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$"))
+      message(FATAL_ERROR "libsycl requires a DLL version of the MSVC CRT.")
+  endif()
+  if ((NOT CMAKE_MSVC_RUNTIME_LIBRARY AND uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
+      OR (CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDebugDLL"))
+    set(LIBSYCL_SHARED_OUTPUT_NAME "${LIBSYCL_SHARED_OUTPUT_NAME}d")
+  endif()
+endif()
 
 add_subdirectory(src)
 
+set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
 add_custom_target(libsycl-runtime-libraries
   DEPENDS ${LIBSYCL_RT_LIBS}
 )
+add_subdirectory(tools)
diff --git a/libsycl/docs/index.rst b/libsycl/docs/index.rst
index 78e76e73284d3..83df7807c9df9 100644
--- a/libsycl/docs/index.rst
+++ b/libsycl/docs/index.rst
@@ -69,11 +69,17 @@ To build LLVM with libsycl runtime enabled the following script can be used.
   mkdir -p $installprefix
 
   cmake -G Ninja -S $llvm/llvm -B $build_llvm \
-        -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
+        -DLLVM_ENABLE_PROJECTS="clang" \
         -DLLVM_INSTALL_UTILS=ON \
         -DCMAKE_INSTALL_PREFIX=$installprefix \
-        -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libsycl;libunwind" \
+        -DLLVM_ENABLE_RUNTIMES="offload;openmp;libsycl" \
         -DCMAKE_BUILD_TYPE=Release
 
   ninja -C $build_llvm install
-  
\ No newline at end of file
+
+
+Limitations
+========
+
+SYCL runtime is not tested and is not guaranteed to work on Windows because offloading runtime (liboffload) used by SYCL runtime doesn't currently support Windows.
+The limitation to be revised once liboffload will add support for Windows.
diff --git a/libsycl/include/sycl/__impl/backend.hpp b/libsycl/include/sycl/__impl/backend.hpp
new file mode 100644
index 0000000000000..bc361e487af69
--- /dev/null
+++ b/libsycl/include/sycl/__impl/backend.hpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 enum class backend that is
+/// implementation-defined and is populated with a unique identifier for each
+/// SYCL backend that the SYCL implementation can support.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_BACKEND_HPP
+#define _LIBSYCL___IMPL_BACKEND_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <string_view>
+#include <type_traits>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+// 4.1. Backends
+enum class backend : char {
+  opencl = 1,
+  level_zero = 2,
+  cuda = 3,
+  hip = 4,
+  all = 5,
+};
+
+namespace detail {
+template <typename T> struct is_backend_info_desc : std::false_type {};
+} // namespace detail
+
+// 4.5.1.1. Type traits backend_traits
+template <backend Backend> class backend_traits;
+
+template <backend Backend, typename SYCLObjectT>
+using backend_input_t =
+    typename backend_traits<Backend>::template input_type<SYCLObjectT>;
+template <backend Backend, typename SYCLObjectT>
+using backend_return_t =
+    typename backend_traits<Backend>::template return_type<SYCLObjectT>;
+
+namespace detail {
+inline std::string_view get_backend_name(const backend &Backend) {
+  switch (Backend) {
+  case backend::opencl:
+    return "opencl";
+  case backend::level_zero:
+    return "level_zero";
+  case backend::cuda:
+    return "cuda";
+  case backend::hip:
+    return "hip";
+  case backend::all:
+    return "all";
+  }
+
+  return "";
+}
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_BACKEND_HPP
diff --git a/libsycl/include/sycl/__impl/detail/config.hpp b/libsycl/include/sycl/__impl/detail/config.hpp
index cc9059762af1b..ea7a8530a8cfe 100644
--- a/libsycl/include/sycl/__impl/detail/config.hpp
+++ b/libsycl/include/sycl/__impl/detail/config.hpp
@@ -41,8 +41,8 @@
 
 #    else // _WIN32
 
-#      define _LIBSYCL_DLL_LOCAL [[__gnu__::__visibility__("hidden")]]
-#      define _LIBSYCL_EXPORT [[__gnu__::__visibility__("default")]]
+#      define _LIBSYCL_DLL_LOCAL __attribute__((visibility("hidden")))
+#      define _LIBSYCL_EXPORT __attribute__((visibility("default")))
 
 #    endif // _WIN32
 #  endif   // _LIBSYCL_EXPORT
diff --git a/libsycl/include/sycl/__impl/detail/macro_definitions.hpp b/libsycl/include/sycl/__impl/detail/macro_definitions.hpp
new file mode 100644
index 0000000000000..c9e148709d721
--- /dev/null
+++ b/libsycl/include/sycl/__impl/detail/macro_definitions.hpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 macro definitions used in SYCL implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP
+#define _LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP
+
+#ifndef __SYCL2020_DEPRECATED
+#  if SYCL_LANGUAGE_VERSION == 202012L &&                                      \
+      !defined(SYCL2020_DISABLE_DEPRECATION_WARNINGS)
+#    define __SYCL2020_DEPRECATED(message) [[deprecated(message)]]
+#  else
+#    define __SYCL2020_DEPRECATED(message)
+#  endif
+#endif // __SYCL2020_DEPRECATED
+
+static_assert(__cplusplus >= 201703L,
+              "SYCL RT does not support C++ version earlier than C++17.");
+
+#if defined(_WIN32) && !defined(_DLL) && !defined(__SYCL_DEVICE_ONLY__)
+// SYCL library is designed such a way that STL objects cross DLL boundary,
+// which is guaranteed to work properly only when the application uses the same
+// C++ runtime that SYCL library uses.
+// The appplications using sycl.dll must be linked with dynamic/release C++ MSVC
+// runtime, i.e. be compiled with /MD switch. Similarly, the applications using
+// sycld.dll must be linked with dynamic/debug C++ runtime and be compiled with
+// /MDd switch.
+// Compiler automatically adds /MD or /MDd when -fsycl switch is used.
+// The options /MD and /MDd that make the code to use dynamic runtime also
+// define the _DLL macro.
+#  define ERROR_MESSAGE                                                        \
+    "SYCL library is designed to work safely with dynamic C++ runtime."        \
+    "Please use /MD switch with sycl.dll, /MDd switch with sycld.dll, "        \
+    "or -fsycl switch to set C++ runtime automatically."
+#  if defined(_MSC_VER)
+#    pragma message(ERROR_MESSAGE)
+#  else
+#    warning ERROR_MESSAGE
+#  endif
+#  undef ERROR_MESSAGE
+#endif // defined(_WIN32) && !defined(_DLL) && !defined(__SYCL_DEVICE_ONLY__)
+
+#endif //_LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP
diff --git a/libsycl/include/sycl/__impl/detail/obj_base.hpp b/libsycl/include/sycl/__impl/detail/obj_base.hpp
new file mode 100644
index 0000000000000..d0314bbdbf767
--- /dev/null
+++ b/libsycl/include/sycl/__impl/detail/obj_base.hpp
@@ -0,0 +1,64 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 helper functions for tranformation between implementation
+/// and SYCL's interface objects.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP
+#define _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+template <class Impl, class SyclObject> class ObjBase {
+public:
+  using ImplType = Impl;
+  using Base = ObjBase<Impl, SyclObject>;
+
+protected:
+  ImplType &impl;
+
+  explicit ObjBase(ImplType &pImpl) : impl(pImpl) {}
+  ObjBase() = default;
+
+  static SyclObject createSyclProxy(ImplType &impl) { return SyclObject(impl); }
+
+  template <class Obj>
+  friend const typename Obj::ImplType &getSyclObjImpl(const Obj &Object);
+
+  template <class Obj>
+  friend Obj createSyclObjFromImpl(
+      std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj);
+};
+
+template <class Obj>
+const typename Obj::ImplType &getSyclObjImpl(const Obj &Object) {
+  return Object.impl;
+}
+
+template <class Obj>
+Obj createSyclObjFromImpl(
+    std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj) {
+  return Obj::Base::createSyclProxy(ImplObj);
+}
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP
diff --git a/libsycl/include/sycl/__impl/exception.hpp b/libsycl/include/sycl/__impl/exception.hpp
new file mode 100644
index 0000000000000..d41a833e1bc10
--- /dev/null
+++ b/libsycl/include/sycl/__impl/exception.hpp
@@ -0,0 +1,116 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 2020 Exception class
+/// interface (4.13.2.)
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_EXCEPTION_HPP
+#define _LIBSYCL___IMPL_EXCEPTION_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <exception>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+class context;
+
+enum class errc : int {
+  success = 0,
+  runtime = 1,
+  kernel = 2,
+  accessor = 3,
+  nd_range = 4,
+  event = 5,
+  kernel_argument = 6,
+  build = 7,
+  invalid = 8,
+  memory_allocation = 9,
+  platform = 10,
+  profiling = 11,
+  feature_not_supported = 12,
+  kernel_not_supported = 13,
+  backend_mismatch = 14,
+};
+
+/// Constructs an error code using E and sycl_category()
+_LIBSYCL_EXPORT std::error_code make_error_code(sycl::errc E) noexcept;
+
+/// Obtains a reference to the static error category object for SYCL errors.
+_LIBSYCL_EXPORT const std::error_category &sycl_category() noexcept;
+
+// Derive from std::exception so uncaught exceptions are printed in c++ default
+// exception handler.
+// Virtual inheritance is mandated by SYCL 2020.
+// 4.13.2. Exception class interface
+class _LIBSYCL_EXPORT exception : public virtual std::exception {
+public:
+  exception(std::error_code, const char *);
+  exception(std::error_code Ec, const std::string &Msg)
+      : exception(Ec, Msg.c_str()) {}
+
+  exception(std::error_code EC) : exception(EC, "") {}
+  exception(int EV, const std::error_category &ECat, const std::string &WhatArg)
+      : exception(EV, ECat, WhatArg.c_str()) {}
+  exception(int EV, const std::error_category &ECat, const char *WhatArg)
+      : exception({EV, ECat}, WhatArg) {}
+  exception(int EV, const std::error_category &ECat)
+      : exception({EV, ECat}, "") {}
+
+  virtual ~exception();
+
+  const std::error_code &code() const noexcept;
+  const std::error_category &category() const noexcept;
+
+  const char *what() const noexcept final;
+
+  bool has_context() const noexcept;
+
+private:
+  // Exceptions must be noexcept copy constructible, so cannot use std::string
+  // directly.
+  std::shared_ptr<std::string> MMessage;
+  std::error_code MErrC = make_error_code(sycl::errc::invalid);
+};
+
+/// Used as a container for a list of asynchronous exceptions
+///
+class _LIBSYCL_EXPORT exception_list {
+public:
+  using value_type = std::exception_ptr;
+  using reference = value_type &;
+  using const_reference = const value_type &;
+  using size_type = std::size_t;
+  using iterator = std::vector<std::exception_ptr>::const_iterator;
+  using const_iterator = std::vector<std::exception_ptr>::const_iterator;
+
+  size_type size() const;
+  // first asynchronous exception
+  iterator begin() const;
+  // refer to past-the-end last asynchronous exception
+  iterator end() const;
+
+private:
+  std::vector<std::exception_ptr> MList;
+};
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+namespace std {
+template <> struct is_error_code_enum<sycl::errc> : true_type {};
+} // namespace std
+
+#endif // _LIBSYCL___IMPL_EXCEPTION_HPP
diff --git a/libsycl/include/sycl/__impl/info/platform.def b/libsycl/include/sycl/__impl/info/platform.def
new file mode 100644
index 0000000000000..68835fc3e3640
--- /dev/null
+++ b/libsycl/include/sycl/__impl/info/platform.def
@@ -0,0 +1,8 @@
+#ifndef __SYCL_PARAM_TRAITS_SPEC
+static_assert(false, "__SYCL_PARAM_TRAITS_SPEC is required but not defined");
+#endif
+
+// 4.6.2.4. Information descriptors
+__SYCL_PARAM_TRAITS_SPEC(platform, version, std::string, OL_PLATFORM_INFO_VERSION)
+__SYCL_PARAM_TRAITS_SPEC(platform, name, std::string, OL_PLATFORM_INFO_NAME)
+__SYCL_PARAM_TRAITS_SPEC(platform, vendor, std::string, OL_PLATFORM_INFO_VENDOR_NAME)
diff --git a/libsycl/include/sycl/__impl/info/platform.hpp b/libsycl/include/sycl/__impl/info/platform.hpp
new file mode 100644
index 0000000000000..d175b66adf570
--- /dev/null
+++ b/libsycl/include/sycl/__impl/info/platform.hpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 SYCL 2020 platform info types.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL___IMPL_INFO_PLATFORM_HPP
+#define _LIBSYCL___IMPL_INFO_PLATFORM_HPP
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <string>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+// A.1. Platform information descriptors
+namespace info {
+namespace platform {
+#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, OffloadCode)         \
+  struct Desc {                                                                \
+    using return_type = ReturnT;                                               \
+  };
+
+// 4.6.2.4. Information descriptors
+#include <sycl/__impl/info/platform.def>
+
+#undef __SYCL_PARAM_TRAITS_SPEC
+} // namespace platform
+} // namespace info
+
+namespace detail {
+template <typename T> struct is_platform_info_desc : std::false_type {};
+
+#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, OffloadCode)         \
+  template <>                                                                  \
+  struct is_##DescType##_info_desc<info::DescType::Desc> : std::true_type {    \
+    using return_type = info::DescType::Desc::return_type;                     \
+  };
+
+#include <sycl/__impl/info/platform.def>
+
+#undef __SYCL_PARAM_TRAITS_SPEC
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL___IMPL_INFO_PLATFORM_HPP
diff --git a/libsycl/include/sycl/__impl/platform.hpp b/libsycl/include/sycl/__impl/platform.hpp
index bac59ac93d3dd..b54c339208e84 100644
--- a/libsycl/include/sycl/__impl/platform.hpp
+++ b/libsycl/include/sycl/__impl/platform.hpp
@@ -15,15 +15,96 @@
 #ifndef _LIBSYCL___IMPL_PLATFORM_HPP
 #define _LIBSYCL___IMPL_PLATFORM_HPP
 
+#include <sycl/__impl/backend.hpp>
 #include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/detail/obj_base.hpp>
+#include <sycl/__impl/info/platform.hpp>
+
+#include <memory>
+#include <vector>
 
 _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
-class _LIBSYCL_EXPORT platform {
+namespace detail {
+class platform_impl;
+} // namespace detail
+
+// 4.6.2. Platform class
+class _LIBSYCL_EXPORT platform
+    : public detail::ObjBase<detail::platform_impl, platform> {
 public:
-  /// Constructs a SYCL platform which contains the default device.
-  platform();
+  /// Constructs a platform object that is a copy of the platform which contains
+  /// the device returned by default_selector_v.
+  // platform();
+
+  /// Constructs a platform object that is a copy of the platform which contains
+  /// the device that is selected by selector.
+  /// \param DeviceSelectorInstance is SYCL 2020 Device Selector, a simple
+  /// callable taking a device reference and returning an integer rank.
+  // template <typename DeviceSelector>
+  // explicit platform(const DeviceSelector& DeviceSelectorInstance);
+
+  /// Returns the backend associated with this platform.
+  ///
+  /// \return the backend associated with this platform
+  backend get_backend() const noexcept;
+
+  /// Returns all SYCL devices associated with this platform.
+  ///
+  /// If there are no devices that match given device
+  /// type, resulting vector is empty.
+  ///
+  /// \param DeviceType is a SYCL device type.
+  /// \return a vector of SYCL devices.
+  // std::vector<device>
+  //     get_devices(info::device_type DeviceType = info::device_type::all)
+  //     const;
+
+  /// Queries this SYCL platform for info.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param>
+  typename detail::is_platform_info_desc<Param>::return_type get_info() const {
+    return get_info_impl<Param>();
+  }
+
+  // template <typename Param>
+  // typename detail::is_backend_info_desc<Param>::return_type
+  // get_backend_info() const;
+
+  /// Indicates if all of the SYCL devices on this platform have the
+  /// given feature.
+  ///
+  /// \param Aspect is one of the values in Table 4.20 of the SYCL 2020
+  /// Provisional Spec.
+  ///
+  /// \return true if all of the SYCL devices on this platform have the
+  /// given feature.
+  // bool has(aspect Aspect) const;
+
+  /// Checks if platform supports specified extension.
+  ///
+  /// \param ExtensionName is a string containing extension name.
+  /// \return true if specified extension is supported by this SYCL platform.
+  // __SYCL2020_DEPRECATED(
+  //     "use platform::has() function with aspects APIs instead")
+  // bool has_extension(const std::string& ExtensionName) const; // Deprecated
+
+  /// Returns all SYCL platforms from all backends that are available in the
+  /// system.
+  ///
+  /// \return A std::vector containing all of the platforms from all backends
+  /// that are available in the system.
+  static std::vector<platform> get_platforms();
+
+private:
+  platform(detail::platform_impl &Impl) : ObjBase(Impl) {}
+
+  template <typename Param>
+  typename detail::is_platform_info_desc<Param>::return_type
+  get_info_impl() const;
 
+  friend detail::ObjBase<detail::platform_impl, platform>;
 }; // class platform
 
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/include/sycl/sycl.hpp b/libsycl/include/sycl/sycl.hpp
index 76399eba758d2..ef91ab2381770 100644
--- a/libsycl/include/sycl/sycl.hpp
+++ b/libsycl/include/sycl/sycl.hpp
@@ -14,6 +14,7 @@
 #ifndef _LIBSYCL_SYCL_HPP
 #define _LIBSYCL_SYCL_HPP
 
+#include <sycl/__impl/exception.hpp>
 #include <sycl/__impl/platform.hpp>
 
 #endif // _LIBSYCL_SYCL_HPP
diff --git a/libsycl/src/CMakeLists.txt b/libsycl/src/CMakeLists.txt
index 206b85681cb84..5c8010801f231 100644
--- a/libsycl/src/CMakeLists.txt
+++ b/libsycl/src/CMakeLists.txt
@@ -2,10 +2,6 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../runtimes/cmake/
 include(WarningFlags)
 
 function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
-  if (NOT LLVM_ENABLE_PIC)
-    message( FATAL_ERROR "Position-Independent Code generation is required for libsycl shared library" )
-  endif()
-
   cmake_parse_arguments(ARG "" "" "COMPILE_OPTIONS;SOURCES" ${ARGN})
 
   add_library(${LIB_OBJ_NAME} OBJECT ${ARG_SOURCES})
@@ -20,6 +16,7 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
     PRIVATE
       ${CMAKE_CURRENT_SOURCE_DIR}
       ${LIBSYCL_BUILD_INCLUDE_DIR}
+      ${CMAKE_CURRENT_BINARY_DIR}/../../offload/liboffload/API
   )
 
   add_library(${LIB_TARGET_NAME} SHARED
@@ -27,6 +24,7 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
 
   add_dependencies(${LIB_OBJ_NAME}
     sycl-headers
+    LLVMOffload
   )
 
   set_target_properties(${LIB_TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
@@ -49,7 +47,7 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
     target_compile_options(${LIB_OBJ_NAME} PUBLIC /EHsc)
   else()
     target_compile_options(${LIB_OBJ_NAME} PUBLIC
-                           -fvisibility=hidden -fvisibility-inlines-hidden)
+                           -fvisibility=hidden -fvisibility-inlines-hidden -fPIC)
 
     if (UNIX AND NOT APPLE)
       set(linker_script "${CMAKE_CURRENT_SOURCE_DIR}/ld-version-script.txt")
@@ -65,6 +63,7 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
     PRIVATE
       ${CMAKE_DL_LIBS}
       ${CMAKE_THREAD_LIBS_INIT}
+      LLVMOffload
   )
 
   set_target_properties(${LIB_TARGET_NAME} PROPERTIES
@@ -74,22 +73,16 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
 endfunction(add_sycl_rt_library)
 
 set(LIBSYCL_SOURCES
+    "exception.cpp"
+    "exception_list.cpp"
     "platform.cpp"
+    "detail/global_objects.cpp"
+    "detail/platform_impl.cpp"
+    "detail/offload/offload_utils.cpp"
+    "detail/offload/offload_topology.cpp"
 )
 
-set(LIB_NAME "sycl")
-set(LIB_OUTPUT_NAME "${LIB_NAME}")
-if (CMAKE_SYSTEM_NAME STREQUAL Windows)
-  if (CMAKE_MSVC_RUNTIME_LIBRARY AND (NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$"))
-      message(FATAL_ERROR "libsycl requires a DLL version of the MSVC CRT.")
-  endif()
-  if ((NOT CMAKE_MSVC_RUNTIME_LIBRARY AND uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
-      OR (CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDebugDLL"))
-    set(LIB_OUTPUT_NAME "${LIB_OUTPUT_NAME}d")
-  endif()
-endif()
-
-add_sycl_rt_library(${LIB_NAME} sycl_object ${LIB_OUTPUT_NAME}
+add_sycl_rt_library(${LIBSYCL_LIB_NAME} sycl_object ${LIBSYCL_SHARED_OUTPUT_NAME}
                     SOURCES ${LIBSYCL_SOURCES})
 
 install(TARGETS ${LIBSYCL_RT_LIBS}
diff --git a/libsycl/src/detail/global_objects.cpp b/libsycl/src/detail/global_objects.cpp
new file mode 100644
index 0000000000000..1dbb7074ed453
--- /dev/null
+++ b/libsycl/src/detail/global_objects.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/global_objects.hpp>
+#include <detail/platform_impl.hpp>
+
+#ifdef _WIN32
+#  include <windows.h>
+#endif
+
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+namespace detail {
+
+std::vector<detail::OffloadTopology> &getOffloadTopologies() {
+  static std::vector<detail::OffloadTopology> Topologies(
+      OL_PLATFORM_BACKEND_LAST);
+  return Topologies;
+}
+
+std::vector<std::unique_ptr<platform_impl>> &getPlatformCache() {
+  static std::vector<std::unique_ptr<platform_impl>> PlatformCache{};
+  return PlatformCache;
+}
+
+std::mutex &getPlatformMapMutex() {
+  static std::mutex PlatformMapMutex{};
+  return PlatformMapMutex;
+}
+
+void shutdown() {
+  // No error reporting in shutdown
+  std::ignore = olShutDown();
+}
+
+#ifdef _WIN32
+extern "C" _LIBSYCL_EXPORT BOOL WINAPI DllMain(HINSTANCE hinstDLL,
+                                               DWORD fdwReason,
+                                               LPVOID lpReserved) {
+  // Perform actions based on the reason for calling.
+  switch (fdwReason) {
+  case DLL_PROCESS_DETACH:
+    try {
+      shutdown();
+    } catch (std::exception &e) {
+      // report
+    }
+
+    break;
+  case DLL_PROCESS_ATTACH:
+    break;
+  case DLL_THREAD_ATTACH:
+    break;
+  case DLL_THREAD_DETACH:
+    break;
+  }
+  return TRUE; // Successful DLL_PROCESS_ATTACH.
+}
+#else
+// Setting low priority on destructor ensures it runs after all other global
+// destructors. Priorities 0-100 are reserved by the compiler. The priority
+// value 110 allows SYCL users to run their destructors after runtime library
+// deinitialization.
+__attribute__((destructor(110))) static void syclUnload() { shutdown(); }
+#endif
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/global_objects.hpp b/libsycl/src/detail/global_objects.hpp
new file mode 100644
index 0000000000000..57deee4e5529b
--- /dev/null
+++ b/libsycl/src/detail/global_objects.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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBSYCL_GLOBAL_OBJECTS
+#define _LIBSYCL_GLOBAL_OBJECTS
+
+#include <detail/offload/offload_topology.hpp>
+#include <sycl/__impl/detail/config.hpp>
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+class platform_impl;
+
+// Offload topologies (one per backend) discovered from liboffload.
+std::vector<detail::OffloadTopology> &getOffloadTopologies();
+
+std::mutex &getPlatformMapMutex();
+std::vector<std::unique_ptr<platform_impl>> &getPlatformCache();
+
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_GLOBAL_OBJECTS
diff --git a/libsycl/src/detail/offload/info_code.hpp b/libsycl/src/detail/offload/info_code.hpp
new file mode 100644
index 0000000000000..a9734d380a7c4
--- /dev/null
+++ b/libsycl/src/detail/offload/info_code.hpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_INFO_CODE
+#define _LIBSYCL_INFO_CODE
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+#include <OffloadAPI.h>
+
+namespace detail {
+template <typename T> struct OffloadInfoCode;
+
+#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, OffloadCode)         \
+  template <> struct OffloadInfoCode<info::DescType::Desc> {                   \
+    static constexpr auto value = OffloadCode;                                 \
+  };
+#include <sycl/__impl/info/platform.def>
+#undef __SYCL_PARAM_TRAITS_SPEC
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_INFO_CODE
diff --git a/libsycl/src/detail/offload/offload_topology.cpp b/libsycl/src/detail/offload/offload_topology.cpp
new file mode 100644
index 0000000000000..8a85ab477b885
--- /dev/null
+++ b/libsycl/src/detail/offload/offload_topology.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/global_objects.hpp>
+#include <detail/offload/offload_topology.hpp>
+#include <detail/offload/offload_utils.hpp>
+
+#include <array>
+#include <unordered_map>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+void discoverOffloadDevices() {
+  [[maybe_unused]] static auto DiscoverOnce = [&]() {
+    call_and_throw(olInit);
+
+    using PerBackendDataType =
+        std::array<std::pair<PlatformWithDevStorageType, size_t /*DevCount*/>,
+                   OL_PLATFORM_BACKEND_LAST>;
+
+    PerBackendDataType Mapping;
+    // olIterateDevices calls lambda for every device.
+    // Returning early means jump to next iteration/next device.
+    call_nocheck(
+        olIterateDevices,
+        [](ol_device_handle_t Dev, void *User) -> bool {
+          auto *Data = static_cast<PerBackendDataType *>(User);
+          ol_platform_handle_t Plat = nullptr;
+          ol_result_t Res =
+              call_nocheck(olGetDeviceInfo, Dev, OL_DEVICE_INFO_PLATFORM,
+                           sizeof(Plat), &Plat);
+          // If error occures, ignore platform and continue iteration
+          if (Res != OL_SUCCESS)
+            return true;
+
+          ol_platform_backend_t OlBackend = OL_PLATFORM_BACKEND_UNKNOWN;
+          Res = call_nocheck(olGetPlatformInfo, Plat, OL_PLATFORM_INFO_BACKEND,
+                             sizeof(OlBackend), &OlBackend);
+          // If error occures, ignore platform and continue iteration
+          if (Res != OL_SUCCESS)
+            return true;
+
+          // Skip host & unknown backends
+          if (OL_PLATFORM_BACKEND_HOST == OlBackend ||
+              OL_PLATFORM_BACKEND_UNKNOWN == OlBackend)
+            return true;
+
+          // Ensure backend index fits into array size
+          if (OlBackend >= OL_PLATFORM_BACKEND_LAST)
+            return true;
+
+          auto &[Map, DevCount] = (*Data)[static_cast<size_t>(OlBackend)];
+          Map[Plat].push_back(Dev);
+          DevCount++;
+          return true;
+        },
+        &Mapping);
+    // Now register all platforms and devices into the topologies
+    auto &OffloadTopologies = getOffloadTopologies();
+    for (size_t I = 0; I < OL_PLATFORM_BACKEND_LAST; ++I) {
+      OffloadTopology &Topo = OffloadTopologies[I];
+      Topo.set_backend(static_cast<ol_platform_backend_t>(I));
+      Topo.registerNewPlatformsAndDevices(Mapping[I].first, Mapping[I].second);
+    }
+
+    return true;
+  }();
+}
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/offload/offload_topology.hpp b/libsycl/src/detail/offload/offload_topology.hpp
new file mode 100644
index 0000000000000..3bf2e78c10050
--- /dev/null
+++ b/libsycl/src/detail/offload/offload_topology.hpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_OFFLOAD_TOPOLOGY
+#define _LIBSYCL_OFFLOAD_TOPOLOGY
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <OffloadAPI.h>
+
+#include <cassert>
+#include <unordered_map>
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+// Minimal span-like view
+template <class T> struct range_view {
+  const T *ptr{};
+  size_t len{};
+  const T *begin() const { return ptr; }
+  const T *end() const { return ptr + len; }
+  const T &operator[](size_t i) const { return ptr[i]; }
+  size_t size() const { return len; }
+};
+
+using PlatformWithDevStorageType =
+    std::unordered_map<ol_platform_handle_t, std::vector<ol_device_handle_t>>;
+
+// Contiguous global storage of platform handlers and device handles (grouped by
+// platform) for a backend.
+struct OffloadTopology {
+  OffloadTopology() : MBackend(OL_PLATFORM_BACKEND_UNKNOWN) {}
+  OffloadTopology(ol_platform_backend_t OlBackend) : MBackend(OlBackend) {}
+
+  void set_backend(ol_platform_backend_t B) { MBackend = B; }
+
+  // Platforms for this backend
+  range_view<ol_platform_handle_t> platforms() const {
+    return {MPlatforms.data(), MPlatforms.size()};
+  }
+
+  // Devices for a specific platform (platform_id is index into Platforms)
+  range_view<ol_device_handle_t> devicesForPlatform(size_t PlatformId) const {
+    if (PlatformId >= MDevRangePerPlatformId.size())
+      return {nullptr, 0};
+    return MDevRangePerPlatformId[PlatformId];
+  }
+
+  // Register new platform and devices into this topology under that platform.
+  void
+  registerNewPlatformsAndDevices(PlatformWithDevStorageType &PlatformsAndDev,
+                                 size_t TotalDevCount) {
+    if (!PlatformsAndDev.size())
+      return;
+
+    MPlatforms.reserve(PlatformsAndDev.size());
+    MDevRangePerPlatformId.reserve(MPlatforms.size());
+    MDevices.reserve(TotalDevCount);
+
+    for (auto &[NewPlatform, NewDevs] : PlatformsAndDev) {
+      MPlatforms.push_back(NewPlatform);
+      range_view<ol_device_handle_t> R{MDevices.data() + MDevices.size(),
+                                       NewDevs.size()};
+      MDevices.insert(MDevices.end(), NewDevs.begin(), NewDevs.end());
+      MDevRangePerPlatformId.push_back(R);
+    }
+
+    assert(TotalDevCount == MDevices.size());
+  }
+
+  ol_platform_backend_t backend() { return MBackend; }
+
+private:
+  ol_platform_backend_t MBackend = OL_PLATFORM_BACKEND_UNKNOWN;
+
+  // Platforms and devices belonging to this backend (flattened)
+  std::vector<ol_platform_handle_t> MPlatforms;
+  std::vector<ol_device_handle_t> MDevices; // sorted by platform
+
+  // Vector holding range of devices for each platform (index is platform index
+  // within Platforms)
+  std::vector<range_view<ol_device_handle_t>>
+      MDevRangePerPlatformId; // PlatformDevices.size() == Platforms.size()
+};
+
+// Initialize the topologies by calling olIterateDevices.
+void discoverOffloadDevices();
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_OFFLOAD_TOPOLOGY
diff --git a/libsycl/src/detail/offload/offload_utils.cpp b/libsycl/src/detail/offload/offload_utils.cpp
new file mode 100644
index 0000000000000..2ccb27a9acf44
--- /dev/null
+++ b/libsycl/src/detail/offload/offload_utils.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/offload/offload_utils.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+namespace detail {
+
+const char *stringifyErrorCode(int32_t error) {
+  switch (error) {
+#define _OFFLOAD_ERRC(NAME)                                                    \
+  case NAME:                                                                   \
+    return #NAME;
+    _OFFLOAD_ERRC(OL_ERRC_UNKNOWN)
+    _OFFLOAD_ERRC(OL_ERRC_HOST_IO)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_BINARY)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_NULL_POINTER)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_ARGUMENT)
+    _OFFLOAD_ERRC(OL_ERRC_NOT_FOUND)
+    _OFFLOAD_ERRC(OL_ERRC_OUT_OF_RESOURCES)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_SIZE)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_ENUMERATION)
+    _OFFLOAD_ERRC(OL_ERRC_HOST_TOOL_NOT_FOUND)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_VALUE)
+    _OFFLOAD_ERRC(OL_ERRC_UNIMPLEMENTED)
+    _OFFLOAD_ERRC(OL_ERRC_UNSUPPORTED)
+    _OFFLOAD_ERRC(OL_ERRC_ASSEMBLE_FAILURE)
+    _OFFLOAD_ERRC(OL_ERRC_COMPILE_FAILURE)
+    _OFFLOAD_ERRC(OL_ERRC_LINK_FAILURE)
+    _OFFLOAD_ERRC(OL_ERRC_BACKEND_FAILURE)
+    _OFFLOAD_ERRC(OL_ERRC_UNINITIALIZED)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_NULL_HANDLE)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_PLATFORM)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_DEVICE)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_QUEUE)
+    _OFFLOAD_ERRC(OL_ERRC_INVALID_EVENT)
+    _OFFLOAD_ERRC(OL_ERRC_SYMBOL_KIND)
+#undef _OFFLOAD_ERRC
+
+  default:
+    return "Unknown error code";
+  }
+}
+
+backend convertBackend(ol_platform_backend_t Backend) {
+  switch (Backend) {
+  // case OL_PLATFORM_BACKEND_LEVEL_ZERO:
+  //   return backend::level_zero;
+  case OL_PLATFORM_BACKEND_CUDA:
+    return backend::cuda;
+  case OL_PLATFORM_BACKEND_AMDGPU:
+    return backend::hip;
+  default:
+    throw exception(make_error_code(errc::runtime),
+                    "convertBackend: Unsupported backend");
+  }
+}
+
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/offload/offload_utils.hpp b/libsycl/src/detail/offload/offload_utils.hpp
new file mode 100644
index 0000000000000..b48a6b49d2fd6
--- /dev/null
+++ b/libsycl/src/detail/offload/offload_utils.hpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_OFFLOAD_UTILS
+#define _LIBSYCL_OFFLOAD_UTILS
+
+#include <sycl/__impl/backend.hpp>
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/exception.hpp>
+
+#include <OffloadAPI.h>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+const char *stringifyErrorCode(int32_t error);
+
+inline std::string formatCodeString(int32_t code) {
+  return std::to_string(code) + " (" + std::string(stringifyErrorCode(code)) +
+         ")";
+}
+
+template <sycl::errc errc = sycl::errc::runtime>
+void checkAndThrow(ol_result_t Result) {
+  if (Result != OL_SUCCESS) {
+    throw sycl::exception(sycl::make_error_code(errc),
+                          detail::formatCodeString(Result->Code));
+  }
+}
+
+/// Calls the API, doesn't check result. To be called when specific handling is
+/// needed and explicitly done by developer after.
+template <typename FunctionType, typename... ArgsT>
+ol_result_t call_nocheck(FunctionType &Function, ArgsT &&...Args) {
+  return Function(std::forward<ArgsT>(Args)...);
+}
+
+/// Calls the API & checks the result
+///
+/// \throw sycl::runtime_exception if the call was not successful.
+template <typename FunctionType, typename... ArgsT>
+void call_and_throw(FunctionType &Function, ArgsT &&...Args) {
+  auto Err = call_nocheck(Function, std::forward<ArgsT>(Args)...);
+  checkAndThrow(Err);
+}
+
+backend convertBackend(ol_platform_backend_t Backend);
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_OFFLOAD_UTILS
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
new file mode 100644
index 0000000000000..324ec369cfcec
--- /dev/null
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/detail/config.hpp>
+#include <sycl/__impl/detail/obj_base.hpp>
+
+#include <detail/global_objects.hpp>
+#include <detail/platform_impl.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+platform_impl *
+platform_impl::getOrMakePlatformImpl(ol_platform_handle_t Platform,
+                                     size_t PlatformIndex) {
+  const std::lock_guard<std::mutex> Guard(getPlatformMapMutex());
+
+  std::vector<std::unique_ptr<platform_impl>> &PlatformCache =
+      getPlatformCache();
+
+  // If we've already seen this platform, return the impl
+  for (const auto &PlatImpl : PlatformCache) {
+    if (PlatImpl->getHandleRef() == Platform)
+      return PlatImpl.get();
+  }
+
+  // Otherwise make the impl.
+  std::unique_ptr<platform_impl> Result;
+  Result = std::make_unique<platform_impl>(Platform, PlatformIndex);
+  PlatformCache.emplace_back(std::move(Result));
+
+  return PlatformCache.back().get();
+}
+
+std::vector<platform> platform_impl::getPlatforms() {
+  discoverOffloadDevices();
+  std::vector<platform> Platforms;
+  for (const auto &Topo : getOffloadTopologies()) {
+    size_t PlatformIndex = 0;
+    for (const auto &OffloadPlatform : Topo.platforms()) {
+      platform Platform = detail::createSyclObjFromImpl<platform>(
+          *getOrMakePlatformImpl(OffloadPlatform, PlatformIndex++));
+      Platforms.push_back(std::move(Platform));
+    }
+  }
+  return Platforms;
+}
+
+platform_impl::platform_impl(ol_platform_handle_t Platform,
+                             size_t PlatformIndex)
+    : MOffloadPlatform(Platform), MOffloadPlatformIndex(PlatformIndex) {
+  ol_platform_backend_t Backend = OL_PLATFORM_BACKEND_UNKNOWN;
+  call_and_throw(olGetPlatformInfo, MOffloadPlatform, OL_PLATFORM_INFO_BACKEND,
+                 sizeof(Backend), &Backend);
+  MBackend = convertBackend(Backend);
+  MOffloadBackend = Backend;
+}
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
new file mode 100644
index 0000000000000..45a1cf37c1d3b
--- /dev/null
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_PLATFORM_IMPL
+#define _LIBSYCL_PLATFORM_IMPL
+
+#include <sycl/__impl/backend.hpp>
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/platform.hpp>
+
+#include "detail/offload/info_code.hpp"
+#include "detail/offload/offload_utils.hpp"
+
+#include <OffloadAPI.h>
+
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+class platform_impl {
+public:
+  /// Constructs platform_impl from a platform handle.
+  ///
+  /// \param Platform is a raw offload library handle representing platform.
+  /// \param PlatformIndex is a platform index in a backend (needed for a proper
+  /// indexing in device selector).
+  //
+  // Platforms can only be created under `GlobalHandler`'s ownership via
+  // `platform_impl::getOrMakePlatformImpl` method.
+  explicit platform_impl(ol_platform_handle_t Platform, size_t PlatformIndex);
+
+  ~platform_impl() = default;
+
+  /// Returns the backend associated with this platform.
+  backend getBackend() const noexcept { return MBackend; }
+
+  /// Returns all SYCL platforms from all backends that are available in the
+  /// system.
+  static std::vector<platform> getPlatforms();
+
+  /// Returns raw underlying offload platform handle.
+  ///
+  /// It does not retain handle. It is caller responsibility to make sure that
+  /// platform stays alive while raw handle is in use.
+  ///
+  /// \return a raw plug-in platform handle.
+  const ol_platform_handle_t &getHandleRef() const { return MOffloadPlatform; }
+
+  /// Returns platform index in a backend (needed for a proper indexing in
+  /// device selector).
+  size_t getPlatformIndex() const { return MOffloadPlatformIndex; }
+
+  /// Queries the cache to see if the specified offloading RT platform has been
+  /// seen before.  If so, return the cached platform_impl, otherwise create a
+  /// new one and cache it.
+  ///
+  /// \param Platform is the offloading RT Platform handle representing the
+  /// platform
+  /// \param PlatformIndex is a platform index in a backend (needed for a proper
+  /// indexing in device selector).
+  /// \return the platform_impl representing the offloading RT platform
+  static platform_impl *getOrMakePlatformImpl(ol_platform_handle_t Platform,
+                                              size_t PlatformIndex);
+
+  /// Queries this SYCL platform for info.
+  ///
+  /// The return type depends on information being queried.
+  template <typename Param> typename Param::return_type get_info() const {
+    // for now we have only std::string properties
+    static_assert(std::is_same_v<typename Param::return_type, std::string>);
+    size_t ExpectedSize = 0;
+    call_and_throw(olGetPlatformInfoSize, MOffloadPlatform,
+                   detail::OffloadInfoCode<Param>::value, &ExpectedSize);
+    std::string Result;
+    Result.resize(ExpectedSize - 1);
+    call_and_throw(olGetPlatformInfo, MOffloadPlatform,
+                   detail::OffloadInfoCode<Param>::value, ExpectedSize,
+                   Result.data());
+    return Result;
+  }
+
+private:
+  ol_platform_handle_t MOffloadPlatform{};
+  size_t MOffloadPlatformIndex{};
+  ol_platform_backend_t MOffloadBackend{OL_PLATFORM_BACKEND_UNKNOWN};
+  backend MBackend{};
+};
+
+} // namespace detail
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_PLATFORM_IMPL
diff --git a/libsycl/src/exception.cpp b/libsycl/src/exception.cpp
new file mode 100644
index 0000000000000..38fd8816934b9
--- /dev/null
+++ b/libsycl/src/exception.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 definition of the SYCL 2020 exception class interface
+/// (4.13.2.)
+///
+//===----------------------------------------------------------------------===//
+
+// 4.9.2 Exception Class Interface
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/exception.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+class SYCLCategory : public std::error_category {
+public:
+  const char *name() const noexcept override { return "sycl"; }
+  std::string message(int) const override { return "SYCL Error"; }
+};
+} // namespace detail
+
+// Free functions
+const std::error_category &sycl_category() noexcept {
+  static const detail::SYCLCategory SYCLCategoryObj;
+  return SYCLCategoryObj;
+}
+
+std::error_code make_error_code(sycl::errc Err) noexcept {
+  return std::error_code(static_cast<int>(Err), sycl_category());
+}
+
+// Exception methods implementation
+exception::exception(std::error_code EC, const char *Msg)
+    : MMessage(std::make_shared<std::string>(Msg)), MErrC(EC) {}
+
+exception::~exception() {}
+
+const std::error_code &exception::code() const noexcept { return MErrC; }
+
+const std::error_category &exception::category() const noexcept {
+  return code().category();
+}
+
+const char *exception::what() const noexcept { return MMessage->c_str(); }
+
+bool exception::has_context() const noexcept { /*return (MContext != nullptr);*/
+  return false;
+}
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/exception_list.cpp b/libsycl/src/exception_list.cpp
new file mode 100644
index 0000000000000..3eaf213deaaec
--- /dev/null
+++ b/libsycl/src/exception_list.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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains the definition of the SYCL 2020 exception_list class
+/// interface (4.13.2.)
+///
+//===----------------------------------------------------------------------===//
+
+// 4.13.2. Exception class interface
+#include <sycl/__impl/detail/config.hpp>
+#include <sycl/__impl/exception.hpp>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+exception_list::size_type exception_list::size() const { return MList.size(); }
+
+exception_list::iterator exception_list::begin() const { return MList.begin(); }
+
+exception_list::iterator exception_list::end() const { return MList.cend(); }
+
+_LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index b5d6517ee2120..1dc42a3f39b87 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -8,10 +8,29 @@
 
 #include <sycl/__impl/platform.hpp>
 
+#include <detail/platform_impl.hpp>
+
 #include <stdexcept>
 
 _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
-platform::platform() { throw std::runtime_error("Unimplemented"); }
+backend platform::get_backend() const noexcept { return impl.getBackend(); }
+
+std::vector<platform> platform::get_platforms() {
+  return detail::platform_impl::getPlatforms();
+}
+
+template <typename Param>
+typename detail::is_platform_info_desc<Param>::return_type
+platform::get_info_impl() const {
+  return impl.template get_info<Param>();
+}
+
+#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, OffloadCode)         \
+  template _LIBSYCL_EXPORT ReturnT                                             \
+  platform::get_info_impl<info::platform::Desc>() const;
+
+#include <sycl/__impl/info/platform.def>
+#undef __SYCL_PARAM_TRAITS_SPEC
 
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/tools/CMakeLists.txt b/libsycl/tools/CMakeLists.txt
new file mode 100644
index 0000000000000..74cfa653232c7
--- /dev/null
+++ b/libsycl/tools/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(sycl-ls)
diff --git a/libsycl/tools/sycl-ls/CMakeLists.txt b/libsycl/tools/sycl-ls/CMakeLists.txt
new file mode 100644
index 0000000000000..302ed43248007
--- /dev/null
+++ b/libsycl/tools/sycl-ls/CMakeLists.txt
@@ -0,0 +1,25 @@
+add_executable(sycl-ls sycl-ls.cpp)
+
+target_include_directories(sycl-ls SYSTEM PRIVATE ${LLVM_MAIN_INCLUDE_DIR})
+target_link_libraries(sycl-ls PRIVATE LLVMSupport LLVMObject)
+
+add_dependencies(sycl-ls sycl)
+target_include_directories(sycl-ls PRIVATE ${LIBSYCL_BUILD_INCLUDE_DIR})
+
+target_link_libraries(sycl-ls
+  PRIVATE
+    ${LIBSYCL_SHARED_OUTPUT_NAME}
+)
+
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag(-fno-rtti COMPILER_HAS_NORTTI_FLAG)
+if (COMPILER_HAS_NORTTI_FLAG)
+  target_compile_options(sycl-ls PRIVATE -fno-rtti)
+endif()
+
+if (WIN32)
+  # 0x900: Search for the dependency DLLs only in the System32 directory and in the directory with sycl-ls.exe
+  target_link_options(sycl-ls PRIVATE LINKER:/DEPENDENTLOADFLAG:0x900)
+endif()
+install(TARGETS sycl-ls
+  RUNTIME DESTINATION "bin" COMPONENT sycl-ls)
diff --git a/libsycl/tools/sycl-ls/sycl-ls.cpp b/libsycl/tools/sycl-ls/sycl-ls.cpp
new file mode 100644
index 0000000000000..d611a98af8063
--- /dev/null
+++ b/libsycl/tools/sycl-ls/sycl-ls.cpp
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The "sycl-ls" utility lists all platforms discovered by SYCL.
+//
+// There are two types of output:
+//   concise (default) and
+//   verbose (enabled with --verbose).
+//
+#include <sycl/sycl.hpp>
+
+#include "llvm/Support/CommandLine.h"
+
+#include <iostream>
+
+using namespace sycl;
+using namespace std::literals;
+
+int main(int argc, char **argv) {
+  llvm::cl::opt<bool> Verbose(
+      "verbose",
+      llvm::cl::desc("Verbosely prints all the discovered platforms"));
+  llvm::cl::alias VerboseShort("v", llvm::cl::desc("Alias for -verbose"),
+                               llvm::cl::aliasopt(Verbose));
+  llvm::cl::ParseCommandLineOptions(
+      argc, argv, "This program lists all backends discovered by SYCL");
+
+  try {
+    const auto &Platforms = platform::get_platforms();
+
+    if (Platforms.size() == 0) {
+      std::cout << "No platforms found." << std::endl;
+    }
+
+    for (const auto &Platform : Platforms) {
+      backend Backend = Platform.get_backend();
+      std::cout << "[" << detail::get_backend_name(Backend) << ":"
+                << "unknown" << "]" << std::endl;
+    }
+
+    if (Verbose) {
+      std::cout << "\nPlatforms: " << Platforms.size() << std::endl;
+      uint32_t PlatformNum = 0;
+      for (const auto &Platform : Platforms) {
+        ++PlatformNum;
+        auto PlatformVersion = Platform.get_info<info::platform::version>();
+        auto PlatformName = Platform.get_info<info::platform::name>();
+        auto PlatformVendor = Platform.get_info<info::platform::vendor>();
+        std::cout << "Platform [#" << PlatformNum << "]:" << std::endl;
+        std::cout << "    Version  : " << PlatformVersion << std::endl;
+        std::cout << "    Name     : " << PlatformName << std::endl;
+        std::cout << "    Vendor   : " << PlatformVendor << std::endl;
+
+        std::cout << "    Devices  : " << "unknown" << std::endl;
+      }
+    } else {
+      return EXIT_SUCCESS;
+    }
+  } catch (sycl::exception &e) {
+    std::cerr << "SYCL Exception encountered: " << e.what() << std::endl
+              << std::endl;
+  }
+
+  return EXIT_SUCCESS;
+}

>From bcb27113006043db629942ce7cd6eb9afbe593ff Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Tue, 18 Nov 2025 05:03:39 -0800
Subject: [PATCH 2/7] add partial spec and base for std::hash support

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 .../include/sycl/__impl/detail/obj_base.hpp   | 20 +++++++++++++++++--
 libsycl/include/sycl/__impl/platform.hpp      |  8 ++++++--
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/libsycl/include/sycl/__impl/detail/obj_base.hpp b/libsycl/include/sycl/__impl/detail/obj_base.hpp
index d0314bbdbf767..0ccbde1de6059 100644
--- a/libsycl/include/sycl/__impl/detail/obj_base.hpp
+++ b/libsycl/include/sycl/__impl/detail/obj_base.hpp
@@ -18,6 +18,7 @@
 #include <sycl/__impl/detail/config.hpp>
 
 #include <cassert>
+#include <optional>
 #include <type_traits>
 #include <utility>
 
@@ -25,10 +26,12 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
 namespace detail {
 
-template <class Impl, class SyclObject> class ObjBase {
+template <typename Impl, typename SyclObject> class ObjBase;
+template <typename Impl, typename SyclObject>
+class ObjBase<Impl &, SyclObject> {
 public:
   using ImplType = Impl;
-  using Base = ObjBase<Impl, SyclObject>;
+  using Base = ObjBase<Impl &, SyclObject>;
 
 protected:
   ImplType &impl;
@@ -57,6 +60,19 @@ Obj createSyclObjFromImpl(
   return Obj::Base::createSyclProxy(ImplObj);
 }
 
+// std::hash support (4.5.2. Common reference semantics)
+template <typename T> struct HashBase {
+  size_t operator()(const T &Obj) const {
+#ifdef __SYCL_DEVICE_ONLY__
+    (void)Obj;
+    return 0;
+#else
+    auto &Impl = sycl::detail::getSyclObjImpl(Obj);
+    return std::hash<std::decay_t<decltype(Impl)>>{}(Impl);
+#endif
+  }
+};
+
 } // namespace detail
 
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/include/sycl/__impl/platform.hpp b/libsycl/include/sycl/__impl/platform.hpp
index b54c339208e84..85182e7d52a68 100644
--- a/libsycl/include/sycl/__impl/platform.hpp
+++ b/libsycl/include/sycl/__impl/platform.hpp
@@ -31,7 +31,7 @@ class platform_impl;
 
 // 4.6.2. Platform class
 class _LIBSYCL_EXPORT platform
-    : public detail::ObjBase<detail::platform_impl, platform> {
+    : public detail::ObjBase<detail::platform_impl &, platform> {
 public:
   /// Constructs a platform object that is a copy of the platform which contains
   /// the device returned by default_selector_v.
@@ -104,9 +104,13 @@ class _LIBSYCL_EXPORT platform
   typename detail::is_platform_info_desc<Param>::return_type
   get_info_impl() const;
 
-  friend detail::ObjBase<detail::platform_impl, platform>;
+  friend detail::ObjBase<detail::platform_impl &, platform>;
 }; // class platform
 
 _LIBSYCL_END_NAMESPACE_SYCL
 
+template <>
+struct std::hash<sycl::platform>
+    : public sycl::detail::HashBase<sycl::platform> {};
+
 #endif // _LIBSYCL___IMPL_PLATFORM_HPP

>From b15b6c09f1090f53deef483a8cf41cdcd173ec51 Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Wed, 19 Nov 2025 05:43:55 -0800
Subject: [PATCH 3/7] fix comments

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 libsycl/include/sycl/__impl/backend.hpp  |  1 +
 libsycl/include/sycl/__impl/platform.hpp |  8 +-------
 libsycl/src/detail/platform_impl.hpp     |  4 ++--
 libsycl/src/platform.cpp                 | 11 +++++------
 4 files changed, 9 insertions(+), 15 deletions(-)

diff --git a/libsycl/include/sycl/__impl/backend.hpp b/libsycl/include/sycl/__impl/backend.hpp
index bc361e487af69..4b467f50cce5f 100644
--- a/libsycl/include/sycl/__impl/backend.hpp
+++ b/libsycl/include/sycl/__impl/backend.hpp
@@ -47,6 +47,7 @@ using backend_return_t =
     typename backend_traits<Backend>::template return_type<SYCLObjectT>;
 
 namespace detail {
+// Used by SYCL tools
 inline std::string_view get_backend_name(const backend &Backend) {
   switch (Backend) {
   case backend::opencl:
diff --git a/libsycl/include/sycl/__impl/platform.hpp b/libsycl/include/sycl/__impl/platform.hpp
index 85182e7d52a68..3e3fb3fb9facf 100644
--- a/libsycl/include/sycl/__impl/platform.hpp
+++ b/libsycl/include/sycl/__impl/platform.hpp
@@ -64,9 +64,7 @@ class _LIBSYCL_EXPORT platform
   ///
   /// The return type depends on information being queried.
   template <typename Param>
-  typename detail::is_platform_info_desc<Param>::return_type get_info() const {
-    return get_info_impl<Param>();
-  }
+  typename detail::is_platform_info_desc<Param>::return_type get_info() const;
 
   // template <typename Param>
   // typename detail::is_backend_info_desc<Param>::return_type
@@ -100,10 +98,6 @@ class _LIBSYCL_EXPORT platform
 private:
   platform(detail::platform_impl &Impl) : ObjBase(Impl) {}
 
-  template <typename Param>
-  typename detail::is_platform_info_desc<Param>::return_type
-  get_info_impl() const;
-
   friend detail::ObjBase<detail::platform_impl &, platform>;
 }; // class platform
 
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
index 45a1cf37c1d3b..1d7301d4687df 100644
--- a/libsycl/src/detail/platform_impl.hpp
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -13,8 +13,8 @@
 #include <sycl/__impl/detail/config.hpp>
 #include <sycl/__impl/platform.hpp>
 
-#include "detail/offload/info_code.hpp"
-#include "detail/offload/offload_utils.hpp"
+#include <detail/offload/info_code.hpp>
+#include <detail/offload/offload_utils.hpp>
 
 #include <OffloadAPI.h>
 
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index 1dc42a3f39b87..48d19148beb58 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -22,14 +22,13 @@ std::vector<platform> platform::get_platforms() {
 
 template <typename Param>
 typename detail::is_platform_info_desc<Param>::return_type
-platform::get_info_impl() const {
-  return impl.template get_info<Param>();
+platform::get_info() const {
+  return impl.get_info<Param>();
 }
 
-#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, OffloadCode)         \
-  template _LIBSYCL_EXPORT ReturnT                                             \
-  platform::get_info_impl<info::platform::Desc>() const;
-
+#define __SYCL_PARAM_TRAITS_SPEC(DescType, Desc, ReturnT, PiCode)              \
+  template _LIBSYCL_EXPORT ReturnT platform::get_info<info::platform::Desc>()  \
+      const;
 #include <sycl/__impl/info/platform.def>
 #undef __SYCL_PARAM_TRAITS_SPEC
 

>From 88d313c48f009086708ebba03ae989825c7b3e2d Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Wed, 19 Nov 2025 11:31:37 -0800
Subject: [PATCH 4/7] early init of platforms

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 libsycl/src/detail/common.hpp                 | 34 +++++++
 libsycl/src/detail/global_objects.cpp         |  5 --
 libsycl/src/detail/global_objects.hpp         |  1 -
 .../src/detail/offload/offload_topology.cpp   | 89 +++++++++----------
 .../src/detail/offload/offload_topology.hpp   | 12 +--
 libsycl/src/detail/platform_impl.cpp          | 46 ++++------
 libsycl/src/detail/platform_impl.hpp          | 10 +--
 libsycl/src/platform.cpp                      |  9 +-
 8 files changed, 110 insertions(+), 96 deletions(-)
 create mode 100644 libsycl/src/detail/common.hpp

diff --git a/libsycl/src/detail/common.hpp b/libsycl/src/detail/common.hpp
new file mode 100644
index 0000000000000..e47c231f9ab81
--- /dev/null
+++ b/libsycl/src/detail/common.hpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_COMMON
+#define _LIBSYCL_COMMON
+
+#include <sycl/__impl/detail/config.hpp>
+
+#include <cstddef>
+
+_LIBSYCL_BEGIN_NAMESPACE_SYCL
+
+namespace detail {
+
+// Minimal span-like view
+template <class T> struct range_view {
+  const T *ptr{};
+  size_t len{};
+  const T *begin() const { return ptr; }
+  const T *end() const { return ptr + len; }
+  const T &operator[](size_t i) const { return ptr[i]; }
+  size_t size() const { return len; }
+};
+
+} // namespace detail
+
+_LIBSYCL_END_NAMESPACE_SYCL
+
+#endif // _LIBSYCL_COMMON
diff --git a/libsycl/src/detail/global_objects.cpp b/libsycl/src/detail/global_objects.cpp
index 1dbb7074ed453..e48eb9d9d0ae9 100644
--- a/libsycl/src/detail/global_objects.cpp
+++ b/libsycl/src/detail/global_objects.cpp
@@ -29,11 +29,6 @@ std::vector<std::unique_ptr<platform_impl>> &getPlatformCache() {
   return PlatformCache;
 }
 
-std::mutex &getPlatformMapMutex() {
-  static std::mutex PlatformMapMutex{};
-  return PlatformMapMutex;
-}
-
 void shutdown() {
   // No error reporting in shutdown
   std::ignore = olShutDown();
diff --git a/libsycl/src/detail/global_objects.hpp b/libsycl/src/detail/global_objects.hpp
index 57deee4e5529b..81899623aed68 100644
--- a/libsycl/src/detail/global_objects.hpp
+++ b/libsycl/src/detail/global_objects.hpp
@@ -24,7 +24,6 @@ class platform_impl;
 // Offload topologies (one per backend) discovered from liboffload.
 std::vector<detail::OffloadTopology> &getOffloadTopologies();
 
-std::mutex &getPlatformMapMutex();
 std::vector<std::unique_ptr<platform_impl>> &getPlatformCache();
 
 } // namespace detail
diff --git a/libsycl/src/detail/offload/offload_topology.cpp b/libsycl/src/detail/offload/offload_topology.cpp
index 8a85ab477b885..c1509a39263e0 100644
--- a/libsycl/src/detail/offload/offload_topology.cpp
+++ b/libsycl/src/detail/offload/offload_topology.cpp
@@ -18,60 +18,55 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 namespace detail {
 
 void discoverOffloadDevices() {
-  [[maybe_unused]] static auto DiscoverOnce = [&]() {
-    call_and_throw(olInit);
+  call_and_throw(olInit);
 
-    using PerBackendDataType =
-        std::array<std::pair<PlatformWithDevStorageType, size_t /*DevCount*/>,
-                   OL_PLATFORM_BACKEND_LAST>;
+  using PerBackendDataType =
+      std::array<std::pair<PlatformWithDevStorageType, size_t /*DevCount*/>,
+                 OL_PLATFORM_BACKEND_LAST>;
 
-    PerBackendDataType Mapping;
-    // olIterateDevices calls lambda for every device.
-    // Returning early means jump to next iteration/next device.
-    call_nocheck(
-        olIterateDevices,
-        [](ol_device_handle_t Dev, void *User) -> bool {
-          auto *Data = static_cast<PerBackendDataType *>(User);
-          ol_platform_handle_t Plat = nullptr;
-          ol_result_t Res =
-              call_nocheck(olGetDeviceInfo, Dev, OL_DEVICE_INFO_PLATFORM,
-                           sizeof(Plat), &Plat);
-          // If error occures, ignore platform and continue iteration
-          if (Res != OL_SUCCESS)
-            return true;
-
-          ol_platform_backend_t OlBackend = OL_PLATFORM_BACKEND_UNKNOWN;
-          Res = call_nocheck(olGetPlatformInfo, Plat, OL_PLATFORM_INFO_BACKEND,
-                             sizeof(OlBackend), &OlBackend);
-          // If error occures, ignore platform and continue iteration
-          if (Res != OL_SUCCESS)
-            return true;
+  PerBackendDataType Mapping;
+  // olIterateDevices calls lambda for every device.
+  // Returning early means jump to next iteration/next device.
+  call_nocheck(
+      olIterateDevices,
+      [](ol_device_handle_t Dev, void *User) -> bool {
+        auto *Data = static_cast<PerBackendDataType *>(User);
+        ol_platform_handle_t Plat = nullptr;
+        ol_result_t Res = call_nocheck(
+            olGetDeviceInfo, Dev, OL_DEVICE_INFO_PLATFORM, sizeof(Plat), &Plat);
+        // If error occures, ignore platform and continue iteration
+        if (Res != OL_SUCCESS)
+          return true;
 
-          // Skip host & unknown backends
-          if (OL_PLATFORM_BACKEND_HOST == OlBackend ||
-              OL_PLATFORM_BACKEND_UNKNOWN == OlBackend)
-            return true;
+        ol_platform_backend_t OlBackend = OL_PLATFORM_BACKEND_UNKNOWN;
+        Res = call_nocheck(olGetPlatformInfo, Plat, OL_PLATFORM_INFO_BACKEND,
+                           sizeof(OlBackend), &OlBackend);
+        // If error occures, ignore platform and continue iteration
+        if (Res != OL_SUCCESS)
+          return true;
 
-          // Ensure backend index fits into array size
-          if (OlBackend >= OL_PLATFORM_BACKEND_LAST)
-            return true;
+        // Skip host & unknown backends
+        if (OL_PLATFORM_BACKEND_HOST == OlBackend ||
+            OL_PLATFORM_BACKEND_UNKNOWN == OlBackend)
+          return true;
 
-          auto &[Map, DevCount] = (*Data)[static_cast<size_t>(OlBackend)];
-          Map[Plat].push_back(Dev);
-          DevCount++;
+        // Ensure backend index fits into array size
+        if (OlBackend >= OL_PLATFORM_BACKEND_LAST)
           return true;
-        },
-        &Mapping);
-    // Now register all platforms and devices into the topologies
-    auto &OffloadTopologies = getOffloadTopologies();
-    for (size_t I = 0; I < OL_PLATFORM_BACKEND_LAST; ++I) {
-      OffloadTopology &Topo = OffloadTopologies[I];
-      Topo.set_backend(static_cast<ol_platform_backend_t>(I));
-      Topo.registerNewPlatformsAndDevices(Mapping[I].first, Mapping[I].second);
-    }
 
-    return true;
-  }();
+        auto &[Map, DevCount] = (*Data)[static_cast<size_t>(OlBackend)];
+        Map[Plat].push_back(Dev);
+        DevCount++;
+        return true;
+      },
+      &Mapping);
+  // Now register all platforms and devices into the topologies
+  auto &OffloadTopologies = getOffloadTopologies();
+  for (size_t I = 0; I < OL_PLATFORM_BACKEND_LAST; ++I) {
+    OffloadTopology &Topo = OffloadTopologies[I];
+    Topo.set_backend(static_cast<ol_platform_backend_t>(I));
+    Topo.registerNewPlatformsAndDevices(Mapping[I].first, Mapping[I].second);
+  }
 }
 
 } // namespace detail
diff --git a/libsycl/src/detail/offload/offload_topology.hpp b/libsycl/src/detail/offload/offload_topology.hpp
index 3bf2e78c10050..211f6a88a18e6 100644
--- a/libsycl/src/detail/offload/offload_topology.hpp
+++ b/libsycl/src/detail/offload/offload_topology.hpp
@@ -11,6 +11,8 @@
 
 #include <sycl/__impl/detail/config.hpp>
 
+#include <detail/common.hpp>
+
 #include <OffloadAPI.h>
 
 #include <cassert>
@@ -21,16 +23,6 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
 namespace detail {
 
-// Minimal span-like view
-template <class T> struct range_view {
-  const T *ptr{};
-  size_t len{};
-  const T *begin() const { return ptr; }
-  const T *end() const { return ptr + len; }
-  const T &operator[](size_t i) const { return ptr[i]; }
-  size_t size() const { return len; }
-};
-
 using PlatformWithDevStorageType =
     std::unordered_map<ol_platform_handle_t, std::vector<ol_device_handle_t>>;
 
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
index 324ec369cfcec..e282a8bb12912 100644
--- a/libsycl/src/detail/platform_impl.cpp
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -16,40 +16,32 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
 namespace detail {
 
-platform_impl *
-platform_impl::getOrMakePlatformImpl(ol_platform_handle_t Platform,
-                                     size_t PlatformIndex) {
-  const std::lock_guard<std::mutex> Guard(getPlatformMapMutex());
-
-  std::vector<std::unique_ptr<platform_impl>> &PlatformCache =
-      getPlatformCache();
-
-  // If we've already seen this platform, return the impl
+platform_impl *platform_impl::getPlatformImpl(ol_platform_handle_t Platform) {
+  auto &PlatformCache = getPlatformCache();
   for (const auto &PlatImpl : PlatformCache) {
     if (PlatImpl->getHandleRef() == Platform)
       return PlatImpl.get();
   }
-
-  // Otherwise make the impl.
-  std::unique_ptr<platform_impl> Result;
-  Result = std::make_unique<platform_impl>(Platform, PlatformIndex);
-  PlatformCache.emplace_back(std::move(Result));
-
-  return PlatformCache.back().get();
+  assert(false && "All platform_impl objects must be created during initial "
+                  "device & platform discovery");
+  return nullptr;
 }
 
-std::vector<platform> platform_impl::getPlatforms() {
-  discoverOffloadDevices();
-  std::vector<platform> Platforms;
-  for (const auto &Topo : getOffloadTopologies()) {
-    size_t PlatformIndex = 0;
-    for (const auto &OffloadPlatform : Topo.platforms()) {
-      platform Platform = detail::createSyclObjFromImpl<platform>(
-          *getOrMakePlatformImpl(OffloadPlatform, PlatformIndex++));
-      Platforms.push_back(std::move(Platform));
+range_view<std::unique_ptr<platform_impl>> platform_impl::getPlatforms() {
+  [[maybe_unused]] static auto InitPlatformsOnce = []() {
+    discoverOffloadDevices();
+    auto &PlatformCache = getPlatformCache();
+    for (const auto &Topo : getOffloadTopologies()) {
+      size_t PlatformIndex = 0;
+      for (const auto &OffloadPlatform : Topo.platforms()) {
+        PlatformCache.emplace_back(
+            std::make_unique<platform_impl>(OffloadPlatform, PlatformIndex++));
+      }
     }
-  }
-  return Platforms;
+    return true;
+  }();
+  auto &PlatformCache = getPlatformCache();
+  return {PlatformCache.data(), PlatformCache.size()};
 }
 
 platform_impl::platform_impl(ol_platform_handle_t Platform,
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
index 1d7301d4687df..4681cc69799d9 100644
--- a/libsycl/src/detail/platform_impl.hpp
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -13,6 +13,7 @@
 #include <sycl/__impl/detail/config.hpp>
 #include <sycl/__impl/platform.hpp>
 
+#include <detail/common.hpp>
 #include <detail/offload/info_code.hpp>
 #include <detail/offload/offload_utils.hpp>
 
@@ -44,9 +45,9 @@ class platform_impl {
   /// Returns the backend associated with this platform.
   backend getBackend() const noexcept { return MBackend; }
 
-  /// Returns all SYCL platforms from all backends that are available in the
-  /// system.
-  static std::vector<platform> getPlatforms();
+  /// Returns range-view to all SYCL platforms from all backends that are
+  /// available in the system.
+  static range_view<std::unique_ptr<platform_impl>> getPlatforms();
 
   /// Returns raw underlying offload platform handle.
   ///
@@ -69,8 +70,7 @@ class platform_impl {
   /// \param PlatformIndex is a platform index in a backend (needed for a proper
   /// indexing in device selector).
   /// \return the platform_impl representing the offloading RT platform
-  static platform_impl *getOrMakePlatformImpl(ol_platform_handle_t Platform,
-                                              size_t PlatformIndex);
+  static platform_impl *getPlatformImpl(ol_platform_handle_t Platform);
 
   /// Queries this SYCL platform for info.
   ///
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index 48d19148beb58..f2acb7b2afcab 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -17,7 +17,14 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 backend platform::get_backend() const noexcept { return impl.getBackend(); }
 
 std::vector<platform> platform::get_platforms() {
-  return detail::platform_impl::getPlatforms();
+  auto PlatformsView = detail::platform_impl::getPlatforms();
+  std::vector<platform> Platforms;
+  for (size_t i = 0; i < PlatformsView.len; i++) {
+    platform Platform =
+        detail::createSyclObjFromImpl<platform>(*PlatformsView.ptr[i].get());
+    Platforms.push_back(std::move(Platform));
+  }
+  return Platforms;
 }
 
 template <typename Param>

>From 849fed99b6b2f603b23faeff0b6fbf3e2f93299c Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Thu, 20 Nov 2025 03:13:37 -0800
Subject: [PATCH 5/7] remove unique_ptr, make ref const, add operator==

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 .../include/sycl/__impl/detail/obj_base.hpp   | 10 +++++-----
 libsycl/include/sycl/__impl/platform.hpp      | 14 +++++++++++++-
 libsycl/src/detail/global_objects.cpp         |  4 ++--
 libsycl/src/detail/global_objects.hpp         |  2 +-
 libsycl/src/detail/platform_impl.cpp          | 19 +++++++++----------
 libsycl/src/detail/platform_impl.hpp          |  4 ++--
 libsycl/src/platform.cpp                      |  5 +++--
 7 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/libsycl/include/sycl/__impl/detail/obj_base.hpp b/libsycl/include/sycl/__impl/detail/obj_base.hpp
index 0ccbde1de6059..eb5af900c1584 100644
--- a/libsycl/include/sycl/__impl/detail/obj_base.hpp
+++ b/libsycl/include/sycl/__impl/detail/obj_base.hpp
@@ -34,19 +34,19 @@ class ObjBase<Impl &, SyclObject> {
   using Base = ObjBase<Impl &, SyclObject>;
 
 protected:
-  ImplType &impl;
+  const ImplType &impl;
 
-  explicit ObjBase(ImplType &pImpl) : impl(pImpl) {}
+  explicit ObjBase(const ImplType &pImpl) : impl(pImpl) {}
   ObjBase() = default;
 
-  static SyclObject createSyclProxy(ImplType &impl) { return SyclObject(impl); }
+  static SyclObject createSyclProxy(const ImplType &impl) { return SyclObject(impl); }
 
   template <class Obj>
   friend const typename Obj::ImplType &getSyclObjImpl(const Obj &Object);
 
   template <class Obj>
   friend Obj createSyclObjFromImpl(
-      std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj);
+      std::add_lvalue_reference_t<const typename Obj::ImplType> ImplObj);
 };
 
 template <class Obj>
@@ -56,7 +56,7 @@ const typename Obj::ImplType &getSyclObjImpl(const Obj &Object) {
 
 template <class Obj>
 Obj createSyclObjFromImpl(
-    std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj) {
+    std::add_lvalue_reference_t<const typename Obj::ImplType> ImplObj) {
   return Obj::Base::createSyclProxy(ImplObj);
 }
 
diff --git a/libsycl/include/sycl/__impl/platform.hpp b/libsycl/include/sycl/__impl/platform.hpp
index 3e3fb3fb9facf..ba30fdcd809c3 100644
--- a/libsycl/include/sycl/__impl/platform.hpp
+++ b/libsycl/include/sycl/__impl/platform.hpp
@@ -37,6 +37,18 @@ class _LIBSYCL_EXPORT platform
   /// the device returned by default_selector_v.
   // platform();
 
+  platform(const platform &rhs) = default;
+
+  platform(platform &&rhs) = default;
+
+  platform &operator=(const platform &rhs) = default;
+
+  platform &operator=(platform &&rhs) = default;
+
+  bool operator==(const platform &rhs) const { return &impl == &rhs.impl; }
+
+  bool operator!=(const platform &rhs) const { return !(*this == rhs); }
+
   /// Constructs a platform object that is a copy of the platform which contains
   /// the device that is selected by selector.
   /// \param DeviceSelectorInstance is SYCL 2020 Device Selector, a simple
@@ -96,7 +108,7 @@ class _LIBSYCL_EXPORT platform
   static std::vector<platform> get_platforms();
 
 private:
-  platform(detail::platform_impl &Impl) : ObjBase(Impl) {}
+  platform(const detail::platform_impl &Impl) : ObjBase(Impl) {}
 
   friend detail::ObjBase<detail::platform_impl &, platform>;
 }; // class platform
diff --git a/libsycl/src/detail/global_objects.cpp b/libsycl/src/detail/global_objects.cpp
index e48eb9d9d0ae9..9990b4d27824a 100644
--- a/libsycl/src/detail/global_objects.cpp
+++ b/libsycl/src/detail/global_objects.cpp
@@ -24,8 +24,8 @@ std::vector<detail::OffloadTopology> &getOffloadTopologies() {
   return Topologies;
 }
 
-std::vector<std::unique_ptr<platform_impl>> &getPlatformCache() {
-  static std::vector<std::unique_ptr<platform_impl>> PlatformCache{};
+std::vector<platform_impl> &getPlatformCache() {
+  static std::vector<platform_impl> PlatformCache{};
   return PlatformCache;
 }
 
diff --git a/libsycl/src/detail/global_objects.hpp b/libsycl/src/detail/global_objects.hpp
index 81899623aed68..0b5ac246692bf 100644
--- a/libsycl/src/detail/global_objects.hpp
+++ b/libsycl/src/detail/global_objects.hpp
@@ -24,7 +24,7 @@ class platform_impl;
 // Offload topologies (one per backend) discovered from liboffload.
 std::vector<detail::OffloadTopology> &getOffloadTopologies();
 
-std::vector<std::unique_ptr<platform_impl>> &getPlatformCache();
+std::vector<platform_impl> &getPlatformCache();
 
 } // namespace detail
 _LIBSYCL_END_NAMESPACE_SYCL
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
index e282a8bb12912..37a8be00a5a9d 100644
--- a/libsycl/src/detail/platform_impl.cpp
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -16,26 +16,25 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
 namespace detail {
 
-platform_impl *platform_impl::getPlatformImpl(ol_platform_handle_t Platform) {
+platform_impl& platform_impl::getPlatformImpl(ol_platform_handle_t Platform) {
   auto &PlatformCache = getPlatformCache();
-  for (const auto &PlatImpl : PlatformCache) {
-    if (PlatImpl->getHandleRef() == Platform)
-      return PlatImpl.get();
+  for (auto &PlatImpl : PlatformCache) {
+    if (PlatImpl.getHandleRef() == Platform)
+      return PlatImpl;
   }
-  assert(false && "All platform_impl objects must be created during initial "
-                  "device & platform discovery");
-  return nullptr;
+
+  throw sycl::exception(sycl::make_error_code(sycl::errc::runtime),
+                              "Platform for requested handle can't be created. This handle is not in the list of platforms discovered by liboffload");
 }
 
-range_view<std::unique_ptr<platform_impl>> platform_impl::getPlatforms() {
+range_view<platform_impl> platform_impl::getPlatforms() {
   [[maybe_unused]] static auto InitPlatformsOnce = []() {
     discoverOffloadDevices();
     auto &PlatformCache = getPlatformCache();
     for (const auto &Topo : getOffloadTopologies()) {
       size_t PlatformIndex = 0;
       for (const auto &OffloadPlatform : Topo.platforms()) {
-        PlatformCache.emplace_back(
-            std::make_unique<platform_impl>(OffloadPlatform, PlatformIndex++));
+        PlatformCache.emplace_back(platform_impl(OffloadPlatform, PlatformIndex++));
       }
     }
     return true;
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
index 4681cc69799d9..f794f791d6295 100644
--- a/libsycl/src/detail/platform_impl.hpp
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -47,7 +47,7 @@ class platform_impl {
 
   /// Returns range-view to all SYCL platforms from all backends that are
   /// available in the system.
-  static range_view<std::unique_ptr<platform_impl>> getPlatforms();
+  static range_view<platform_impl> getPlatforms();
 
   /// Returns raw underlying offload platform handle.
   ///
@@ -70,7 +70,7 @@ class platform_impl {
   /// \param PlatformIndex is a platform index in a backend (needed for a proper
   /// indexing in device selector).
   /// \return the platform_impl representing the offloading RT platform
-  static platform_impl *getPlatformImpl(ol_platform_handle_t Platform);
+  static platform_impl& getPlatformImpl(ol_platform_handle_t Platform);
 
   /// Queries this SYCL platform for info.
   ///
diff --git a/libsycl/src/platform.cpp b/libsycl/src/platform.cpp
index f2acb7b2afcab..66c76d1c6bd73 100644
--- a/libsycl/src/platform.cpp
+++ b/libsycl/src/platform.cpp
@@ -19,9 +19,10 @@ backend platform::get_backend() const noexcept { return impl.getBackend(); }
 std::vector<platform> platform::get_platforms() {
   auto PlatformsView = detail::platform_impl::getPlatforms();
   std::vector<platform> Platforms;
-  for (size_t i = 0; i < PlatformsView.len; i++) {
+  Platforms.reserve(PlatformsView.size());
+  for (size_t i = 0; i < PlatformsView.size(); i++) {
     platform Platform =
-        detail::createSyclObjFromImpl<platform>(*PlatformsView.ptr[i].get());
+        detail::createSyclObjFromImpl<platform>(PlatformsView[i]);
     Platforms.push_back(std::move(Platform));
   }
   return Platforms;

>From 7f62590c2b830b83c81e59d95186565a12bd7072 Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Thu, 20 Nov 2025 03:29:50 -0800
Subject: [PATCH 6/7] fix installation

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 libsycl/CMakeLists.txt | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt
index 54ef3d4b1878a..f25f51def0cc7 100644
--- a/libsycl/CMakeLists.txt
+++ b/libsycl/CMakeLists.txt
@@ -127,10 +127,11 @@ if (CMAKE_SYSTEM_NAME STREQUAL Windows)
   endif()
 endif()
 
-add_subdirectory(src)
-
 set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
 add_custom_target(libsycl-runtime-libraries
   DEPENDS ${LIBSYCL_RT_LIBS}
 )
+
+add_subdirectory(src)
+
 add_subdirectory(tools)

>From f081eeaf758558533582b6ba119dcca72b9f0d75 Mon Sep 17 00:00:00 2001
From: "Tikhomirova, Kseniya" <kseniya.tikhomirova at intel.com>
Date: Thu, 20 Nov 2025 03:31:07 -0800
Subject: [PATCH 7/7] fix format

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova at intel.com>
---
 libsycl/include/sycl/__impl/detail/obj_base.hpp |  4 +++-
 libsycl/src/detail/platform_impl.cpp            | 11 +++++++----
 libsycl/src/detail/platform_impl.hpp            |  2 +-
 3 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/libsycl/include/sycl/__impl/detail/obj_base.hpp b/libsycl/include/sycl/__impl/detail/obj_base.hpp
index eb5af900c1584..fbeb47a70ebdd 100644
--- a/libsycl/include/sycl/__impl/detail/obj_base.hpp
+++ b/libsycl/include/sycl/__impl/detail/obj_base.hpp
@@ -39,7 +39,9 @@ class ObjBase<Impl &, SyclObject> {
   explicit ObjBase(const ImplType &pImpl) : impl(pImpl) {}
   ObjBase() = default;
 
-  static SyclObject createSyclProxy(const ImplType &impl) { return SyclObject(impl); }
+  static SyclObject createSyclProxy(const ImplType &impl) {
+    return SyclObject(impl);
+  }
 
   template <class Obj>
   friend const typename Obj::ImplType &getSyclObjImpl(const Obj &Object);
diff --git a/libsycl/src/detail/platform_impl.cpp b/libsycl/src/detail/platform_impl.cpp
index 37a8be00a5a9d..6bdb9188732d4 100644
--- a/libsycl/src/detail/platform_impl.cpp
+++ b/libsycl/src/detail/platform_impl.cpp
@@ -16,15 +16,17 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL
 
 namespace detail {
 
-platform_impl& platform_impl::getPlatformImpl(ol_platform_handle_t Platform) {
+platform_impl &platform_impl::getPlatformImpl(ol_platform_handle_t Platform) {
   auto &PlatformCache = getPlatformCache();
   for (auto &PlatImpl : PlatformCache) {
     if (PlatImpl.getHandleRef() == Platform)
       return PlatImpl;
   }
 
-  throw sycl::exception(sycl::make_error_code(sycl::errc::runtime),
-                              "Platform for requested handle can't be created. This handle is not in the list of platforms discovered by liboffload");
+  throw sycl::exception(
+      sycl::make_error_code(sycl::errc::runtime),
+      "Platform for requested handle can't be created. This handle is not in "
+      "the list of platforms discovered by liboffload");
 }
 
 range_view<platform_impl> platform_impl::getPlatforms() {
@@ -34,7 +36,8 @@ range_view<platform_impl> platform_impl::getPlatforms() {
     for (const auto &Topo : getOffloadTopologies()) {
       size_t PlatformIndex = 0;
       for (const auto &OffloadPlatform : Topo.platforms()) {
-        PlatformCache.emplace_back(platform_impl(OffloadPlatform, PlatformIndex++));
+        PlatformCache.emplace_back(
+            platform_impl(OffloadPlatform, PlatformIndex++));
       }
     }
     return true;
diff --git a/libsycl/src/detail/platform_impl.hpp b/libsycl/src/detail/platform_impl.hpp
index f794f791d6295..41ca27ab34b94 100644
--- a/libsycl/src/detail/platform_impl.hpp
+++ b/libsycl/src/detail/platform_impl.hpp
@@ -70,7 +70,7 @@ class platform_impl {
   /// \param PlatformIndex is a platform index in a backend (needed for a proper
   /// indexing in device selector).
   /// \return the platform_impl representing the offloading RT platform
-  static platform_impl& getPlatformImpl(ol_platform_handle_t Platform);
+  static platform_impl &getPlatformImpl(ol_platform_handle_t Platform);
 
   /// Queries this SYCL platform for info.
   ///



More information about the llvm-commits mailing list