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

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

---------

Signed-off-by: Tikhomirova, Kseniya <kseniya.tikhomirova@intel.com>
This commit is contained in:
Kseniya Tikhomirova 2026-01-20 16:41:51 +01:00 committed by GitHub
parent 3d009a7b0d
commit 4f7c733293
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 1433 additions and 61 deletions

View File

@ -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,23 @@ 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_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()
set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
add_subdirectory(src)
add_custom_target(libsycl-runtime-libraries
DEPENDS ${LIBSYCL_RT_LIBS}
)
add_subdirectory(src)
add_subdirectory(tools)

View File

@ -3,7 +3,7 @@
The libsycl subproject is an implementation of the SYCL runtime library as defined by the
[SYCL 2020 specification](https://registry.khronos.org/SYCL/specs/sycl-2020/html/sycl-2020.html).
Subproject documentation is available at: [SYCL RT documentation](./docs).
Subproject documentation is available at: [Libsycl documentation](./docs).
libsycl runtime library and headers require C++17 support or higher.

View File

@ -10,8 +10,10 @@ SYCL runtime implementation
Current Status
========
The implementation is in the very early stages of upstreaming. The first milestone is to get
support for a simple SYCL application with device code using Unified Shared Memory:
The implementation is in the very early stages of upstreaming. The first
milestone is to get
support for a simple SYCL application with device code using Unified Shared
Memory:
.. code-block:: c++
@ -43,15 +45,18 @@ support for a simple SYCL application with device code using Unified Shared Memo
return error;
}
This requires at least partial support of the following functionality on the libsycl side:
* ``sycl::platform`` class
* ``sycl::device`` class
* ``sycl::context`` class
* ``sycl::queue`` class
* ``sycl::handler`` class
* ``sycl::id`` and ``sycl::range`` classes
* Unified shared memory allocation/deallocation
* Program manager, an internal component for retrieving and using device images from the multi-architectural binaries
This requires at least partial support of the following functionality on the
libsycl side:
* ``sycl::platform`` class
* ``sycl::device`` class
* ``sycl::context`` class
* ``sycl::queue`` class
* ``sycl::handler`` class
* ``sycl::id`` and ``sycl::range`` classes
* Unified shared memory allocation/deallocation
* Program manager, an internal component for retrieving and using device images
from the multi-architectural binaries
Build steps
========
@ -69,11 +74,20 @@ 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" \
-DCMAKE_BUILD_TYPE=Release
-DLLVM_ENABLE_RUNTIMES="offload;openmp;libsycl" \
-DCMAKE_BUILD_TYPE=Release \
# must be default and configured in liboffload,
# requires level zero, see offload/cmake/Modules/LibomptargetGetDependencies.cmake
-DLIBOMPTARGET_PLUGINS_TO_BUILD=level_zero
ninja -C $build_llvm install
Limitations
========
Libsycl is not currently supported on Windows because it depends on liboffload
which doesn't currently support Windows.

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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
// SYCL 2020 4.1. Backends.
enum class backend : unsigned char {
opencl = 0,
level_zero,
cuda,
hip,
};
namespace detail {
template <typename T> struct is_backend_info_desc : std::false_type {};
} // namespace detail
// SYCL 2020 4.5.1.1. Type traits backend_traits.
template <backend Backend> class backend_traits;
template <backend Backend, typename SyclType>
using backend_input_t =
typename backend_traits<Backend>::template input_type<SyclType>;
template <backend Backend, typename SyclType>
using backend_return_t =
typename backend_traits<Backend>::template return_type<SyclType>;
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL___IMPL_BACKEND_HPP

View File

@ -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
@ -56,4 +56,40 @@
#endif // __SYCL_DEVICE_ONLY__
#if defined(_MSC_VER)
static_assert(_MSVC_LANG >= 201703L, "Libsycl requires C++17 or later.");
#else
static_assert(__cplusplus >= 201703L, "Libsycl requires C++17 or later.");
#endif
#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
#if defined(_WIN32) && !defined(_DLL) && !defined(__SYCL_DEVICE_ONLY__)
// When built for use with the MSVC C++ standard library, libsycl requires
// use of the DLL versions of the MSVC run-time (RT) library. This requirement
// extends to applications that link with libsycl since the same MSVC run-time
// library must be used to ensure ABI compatibility for objects of C++ standard
// library types like std::vector that are passed to or returned from SYCL
// interfaces. Applications must therefore compile and link with the /MD option
// when linking to a release build of libsycl and with the /MDd option when
// linking to a debug build.
# define ERROR_MESSAGE \
"Libsycl requires use of a DLL version of the MSVC RT library. " \
"Please use /MD to link with a release build of libsycl or /MDd to link" \
" with a debug build."
# 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_CONFIG_HPP

View File

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// 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 used to navigate between SYCL interface
/// objects and their corresponding implementation objects.
///
//===----------------------------------------------------------------------===//
#ifndef _LIBSYCL___IMPL_DETAIL_OBJ_UTILS_HPP
#define _LIBSYCL___IMPL_DETAIL_OBJ_UTILS_HPP
#include <sycl/__impl/detail/config.hpp>
#include <cassert>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
// SYCL interface classes are required to contain an `impl` data member
// which points to the corresponding implementation object. The data
// member is required to be accessible by the `ImpUtils` class. SYCL
// interface classes that declare the data member private or protected
// are required to befriend the `ImpUtils` class.
struct ImplUtils {
// Helper function to access an implementation object from a SYCL interface
// object.
template <typename SyclObject>
static const decltype(SyclObject::impl) &
getSyclObjImpl(const SyclObject &Obj) {
assert(Obj.impl && "every constructor should create an impl");
return Obj.impl;
}
// Helper function to create a SYCL interface object from an implementation.
template <typename SyclObject, typename Impl>
static SyclObject createSyclObjFromImpl(Impl &&ImplObj) {
if constexpr (std::is_same_v<decltype(SyclObject::impl),
std::shared_ptr<std::decay_t<Impl>>>)
return SyclObject{ImplObj.shared_from_this()};
else
return SyclObject{std::forward<Impl>(ImplObj)};
}
};
template <typename SyclObject>
auto getSyclObjImpl(const SyclObject &Obj)
-> decltype(ImplUtils::getSyclObjImpl(Obj)) {
return ImplUtils::getSyclObjImpl(Obj);
}
template <typename SyclObject, typename Impl>
SyclObject createSyclObjFromImpl(Impl &&ImplObj) {
return ImplUtils::createSyclObjFromImpl<SyclObject>(
std::forward<Impl>(ImplObj));
}
// SYCL 2020 4.5.2. Common reference semantics (std::hash support).
template <typename T> struct HashBase {
size_t operator()(const T &Obj) const {
auto &Impl = sycl::detail::getSyclObjImpl(Obj);
return std::hash<std::decay_t<decltype(Impl)>>{}(Impl);
}
};
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL___IMPL_DETAIL_OBJ_UTILS_HPP

View File

@ -0,0 +1,153 @@
//===----------------------------------------------------------------------===//
//
// 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
// int is used as the underlying type for consistency with std::error_code.
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 sycl::errc and sycl_category().
///
/// \param E SYCL 2020 error code.
///
/// \returns constructed error code.
_LIBSYCL_EXPORT std::error_code make_error_code(sycl::errc E) noexcept;
/// Obtains a reference to the static error category object for SYCL errors.
///
/// This object overrides the virtual function error_category::name() to return
/// a pointer to the string "sycl". When the implementation throws an
/// sycl::exception object Ex with this category, the error code value contained
/// by the exception (Ex.code().value()) is one of the enumerated values in
/// sycl::errc.
///
/// \returns the error category object for SYCL errors.
_LIBSYCL_EXPORT const std::error_category &sycl_category() noexcept;
/// \brief SYCL 2020 exception class (4.13.2.) for sync and async error handling
/// in a SYCL application (host code).
///
/// Derived from std::exception so uncaught exceptions are printed in c++
/// default exception handler. Virtual inheritance is mandated by SYCL 2020.
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();
/// Returns the error code stored inside the exception.
///
/// \returns the error code stored inside the exception.
const std::error_code &code() const noexcept;
/// Returns the error category of the error code stored inside the exception.
///
/// \returns the error category of the error code stored inside the exception.
const std::error_category &category() const noexcept;
/// Returns string that describes the error that triggered the exception.
///
/// \returns an implementation-defined non-null constant C-style string that
/// describes the error that triggered the exception.
const char *what() const noexcept final;
/// Checks if the exception has an associated SYCL context.
///
/// \returns true if this SYCL exception has an associated SYCL context and
/// false if it does not.
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);
};
/// \brief 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;
/// Returns the size of the list.
///
/// \returns the size of the list.
size_type size() const;
/// Returns an iterator to the beginning of the list of asynchronous
/// exceptions.
///
/// \returns an iterator to the beginning of the list of asynchronous
/// exceptions.
iterator begin() const;
/// Returns an iterator to the end of the list of asynchronous exceptions.
///
/// \returns an iterator to the end of the list of asynchronous exceptions.
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

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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 helpers for info descriptors.
///
//===----------------------------------------------------------------------===//
#ifndef _LIBSYCL___IMPL_INFO_DESC_BASE_HPP
#define _LIBSYCL___IMPL_INFO_DESC_BASE_HPP
#include <sycl/__impl/detail/config.hpp>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
template <typename Desc, typename DescOf> struct info_desc_tag {};
template <typename Desc, typename DescOf, typename = void>
struct is_info_desc : std::false_type {};
template <typename Desc, typename DescOf>
struct is_info_desc<
Desc, DescOf,
std::enable_if_t<std::is_base_of_v<info_desc_tag<Desc, DescOf>, Desc>>>
: std::true_type {
using return_type = typename Desc::return_type;
};
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL___IMPL_INFO_DESC_BASE_HPP

View File

@ -0,0 +1,49 @@
//===----------------------------------------------------------------------===//
//
// 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 <sycl/__impl/info/desc_base.hpp>
#include <string>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
class platform;
namespace detail {
template <typename T>
using is_platform_info_desc_t = typename is_info_desc<T, platform>::return_type;
} // namespace detail
// SYCL 2020 A.1. Platform information descriptors.
namespace info {
namespace platform {
// SYCL 2020 4.6.2.4. Information descriptors.
struct version : detail::info_desc_tag<version, sycl::platform> {
using return_type = std::string;
};
struct name : detail::info_desc_tag<name, sycl::platform> {
using return_type = std::string;
};
struct vendor : detail::info_desc_tag<vendor, sycl::platform> {
using return_type = std::string;
};
} // namespace platform
} // namespace info
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL___IMPL_INFO_PLATFORM_HPP

View File

@ -15,17 +15,78 @@
#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_utils.hpp>
#include <sycl/__impl/info/platform.hpp>
#include <memory>
#include <vector>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
class PlatformImpl;
} // namespace detail
/// \brief SYCL 2020 platform class (4.6.2.) encapsulating a single SYCL
/// platform on which kernel functions may be executed.
class _LIBSYCL_EXPORT platform {
public:
/// Constructs a SYCL platform which contains the default device.
platform();
// The platform class provides the common reference semantics (SYCL
// 2020 4.5.2).
platform(const platform &rhs) = default;
platform(platform &&rhs) = default;
platform &operator=(const platform &rhs) = default;
platform &operator=(platform &&rhs) = default;
friend bool operator==(const platform &lhs, const platform &rhs) {
return lhs.impl == rhs.impl;
}
friend bool operator!=(const platform &lhs, const platform &rhs) {
return !(lhs == rhs);
}
/// Returns the backend associated with this platform.
///
/// \return the backend associated with this platform.
backend get_backend() const noexcept;
/// Queries this SYCL platform for info.
///
/// The return type depends on information being queried.
template <typename Param>
detail::is_platform_info_desc_t<Param> get_info() const;
/// Queries this SYCL platform for SYCL backend-specific information.
///
/// The return type depends on information being queried.
template <typename Param>
typename detail::is_backend_info_desc<Param>::return_type
get_backend_info() const;
/// 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::PlatformImpl &Impl) : impl(&Impl) {}
detail::PlatformImpl *impl;
friend sycl::detail::ImplUtils;
}; // class platform
_LIBSYCL_END_NAMESPACE_SYCL
template <>
struct std::hash<sycl::platform>
: public sycl::detail::HashBase<sycl::platform> {};
#endif // _LIBSYCL___IMPL_PLATFORM_HPP

View File

@ -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

View File

@ -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})
@ -15,21 +11,25 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
$<$<STREQUAL:${CMAKE_SYSTEM_NAME},Windows>:_LIBSYCL_BUILDING_LIBRARY>)
cxx_add_warning_flags(${LIB_OBJ_NAME} ${LIBSYCL_ENABLE_WERROR} ${LIBSYCL_ENABLE_PEDANTIC})
target_include_directories(
${LIB_OBJ_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${LIBSYCL_BUILD_INCLUDE_DIR}
)
add_library(${LIB_TARGET_NAME} SHARED
$<TARGET_OBJECTS:${LIB_OBJ_NAME}>)
add_dependencies(${LIB_OBJ_NAME}
sycl-headers
LLVMOffload
)
set_target_properties(${LIB_TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(${LIB_OBJ_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${LIBSYCL_BUILD_INCLUDE_DIR}
$<TARGET_PROPERTY:LLVMOffload,INTERFACE_INCLUDE_DIRECTORIES>
)
set_target_properties(${LIB_TARGET_NAME}
PROPERTIES
LINKER_LANGUAGE CXX
POSITION_INDEPENDENT_CODE TRUE)
if (CMAKE_SYSTEM_NAME STREQUAL Windows)
# Install stripped PDB
@ -53,9 +53,11 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME)
if (UNIX AND NOT APPLE)
set(linker_script "${CMAKE_CURRENT_SOURCE_DIR}/ld-version-script.txt")
target_link_libraries(
${LIB_TARGET_NAME} PRIVATE "-Wl,--version-script=${linker_script}")
set_target_properties(${LIB_TARGET_NAME} PROPERTIES LINK_DEPENDS ${linker_script})
target_link_libraries(${LIB_TARGET_NAME}
PRIVATE "-Wl,--version-script=${linker_script}")
set_target_properties(${LIB_TARGET_NAME}
PROPERTIES
LINK_DEPENDS ${linker_script})
endif()
endif()
@ -65,32 +67,34 @@ 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
VERSION ${LIBSYCL_VERSION_STRING}
SOVERSION ${LIBSYCL_VERSION_STRING})
set_target_properties(${LIB_TARGET_NAME} PROPERTIES OUTPUT_NAME ${LIB_OUTPUT_NAME})
set_target_properties(${LIB_TARGET_NAME}
PROPERTIES
VERSION ${LIBSYCL_VERSION_STRING}
SOVERSION ${LIBSYCL_VERSION_STRING})
set_target_properties(${LIB_TARGET_NAME}
PROPERTIES
OUTPUT_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}
SOURCES ${LIBSYCL_SOURCES})
add_sycl_rt_library(${LIBSYCL_LIB_NAME}
sycl_object
${LIBSYCL_SHARED_OUTPUT_NAME}
SOURCES
${LIBSYCL_SOURCES})
install(TARGETS ${LIBSYCL_RT_LIBS}
ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}" COMPONENT libsycl

View File

@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// 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<PlatformImplUPtr> &getPlatformCache() {
static std::vector<PlatformImplUPtr> PlatformCache{};
return PlatformCache;
}
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) {
// TODO: Investigate how to handle and report errors that occur during
// shutdown.
}
break;
case DLL_PROCESS_ATTACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
#else
// `syclUnload()` is declared as a low priority destructor to ensure it runs
// after all other global destructors. Priorities 0-100 are reserved for use
// by the compiler and C and C++ standard libraries. SYCL applications may use
// priorities in the range 101-109 to schedule destructors to run after libsycl
// finalization.
__attribute__((destructor(110))) static void syclUnload() { shutdown(); }
#endif
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// 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 PlatformImpl;
/// Returns offload topologies (one per backend) discovered from liboffload.
///
/// This vector is populated only once at the first call of get_platforms().
///
/// \returns std::vector of all offload topologies.
std::vector<detail::OffloadTopology> &getOffloadTopologies();
/// Returns implementation class objects for all platforms discovered from
/// liboffload.
///
/// This vector is populated only once at the first call of get_platforms().
///
/// \returns std::vector of implementation objects for all platforms.
std::vector<std::unique_ptr<PlatformImpl>> &getPlatformCache();
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL_GLOBAL_OBJECTS

View File

@ -0,0 +1,78 @@
//===----------------------------------------------------------------------===//
//
// 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() {
callAndThrow(olInit);
using PerBackendDataType =
std::array<std::pair<PlatformWithDevStorageType, size_t /*DevCount*/>,
OL_PLATFORM_BACKEND_LAST>;
PerBackendDataType Mapping;
// olIterateDevices() calls the lambda for each device. Devices that fail
// probes or that report unknown backends are silently ignored.
// TODO for debug purposes env variable can be added to report error at the
// first failure and interrupt iteration.
callNoCheck(
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 = callNoCheck(
olGetDeviceInfo, Dev, OL_DEVICE_INFO_PLATFORM, sizeof(Plat), &Plat);
// If an error occurs, ignore the device and continue iteration.
if (Res != OL_SUCCESS)
return true;
ol_platform_backend_t OlBackend = OL_PLATFORM_BACKEND_UNKNOWN;
Res = callNoCheck(olGetPlatformInfo, Plat, OL_PLATFORM_INFO_BACKEND,
sizeof(OlBackend), &OlBackend);
// If an error occurs, ignore the device and continue iteration.
if (Res != OL_SUCCESS)
return true;
// Ignore host and unknown backends
if (OL_PLATFORM_BACKEND_HOST == OlBackend ||
OL_PLATFORM_BACKEND_UNKNOWN == OlBackend)
return true;
// Ignore the device if the backend index exceeds the number of backends
// known at compile time. This should only happen when running with a
// newer version of liboffload than libsycl was compiled with.
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.setBackend(static_cast<ol_platform_backend_t>(I));
Topo.registerNewPlatformsAndDevices(Mapping[I].first, Mapping[I].second);
}
}
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL

View File

@ -0,0 +1,122 @@
//===----------------------------------------------------------------------===//
//
// 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 {
T *ptr{};
size_t len{};
T *begin() const { return ptr; }
T *end() const { return ptr + len; }
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) {}
/// Updates backend for this topology.
///
/// \param B new backend value.
void setBackend(ol_platform_backend_t B) { MBackend = B; }
/// Returns all platforms associated with this topology.
///
/// \returns minimal span-like view to platforms associated with this
/// topology.
range_view<const ol_platform_handle_t> platforms() const {
return {MPlatforms.data(), MPlatforms.size()};
}
/// Returns all devices associated with specific platform.
///
/// \param PlatformId platform_id is index into MPlatforms.
///
/// \returns minimal span-like view to devices associated with specified
/// platform.
range_view<const ol_device_handle_t>
devicesForPlatform(size_t PlatformId) const {
if (PlatformId >= MDevRangePerPlatformId.size()) {
assert(false && "Platform index exceeds number of platforms.");
return {nullptr, 0};
}
return MDevRangePerPlatformId[PlatformId];
}
/// Register new platform and devices into this topology.
///
/// \param PlatformsAndDev associative container with platforms & devices.
/// \param TotalDevCount total device count for the 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<const 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());
}
/// Queries backend of this topology.
///
/// \returns backend of this topology.
ol_platform_backend_t backend() const { 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 MPlatforms)
std::vector<range_view<const ol_device_handle_t>>
MDevRangePerPlatformId; // MDevRangePerPlatformId.size() ==
// MPlatforms.size()
};
// Initialize the topologies by calling olIterateDevices.
void discoverOffloadDevices();
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL_OFFLOAD_TOPOLOGY

View File

@ -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(ol_errc_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

View File

@ -0,0 +1,115 @@
//===----------------------------------------------------------------------===//
//
// 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 {
/// Converts liboffload error code to C-string.
///
/// \param Error liboffload error code.
///
/// \returns C-string representing the name of Error as specified in enum.
const char *stringifyErrorCode(ol_errc_t Error);
/// Contructs C++-string with information about liboffload error.
///
/// \param Error liboffload result of calling API.
///
/// \returns C++-string containing all available data of failure.
inline std::string formatCodeString(ol_result_t Result) {
return std::to_string(Result->Code) + " (" +
std::string(stringifyErrorCode(Result->Code)) + ") " + Result->Details;
}
/// Checks liboffload API call result.
///
/// Used after calling the API without check.
/// To be called when specific handling is needed and explicitly done by
/// developer before throwing exception.
///
/// \param Error liboffload result of calling API.
///
/// \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) {
throw sycl::exception(sycl::make_error_code(errc),
detail::formatCodeString(Result));
}
}
/// Calls the API, doesn't check result.
/// To be called when specific handling is needed and explicitly done by
/// developer after.
///
/// \param Function liboffload API function to be called.
/// \param Args arguments to be passed to the liboffload API function.
///
/// \returns liboffload error code returned by API call.
template <typename FunctionType, typename... ArgsT>
ol_result_t callNoCheck(FunctionType &Function, ArgsT &&...Args) {
return Function(std::forward<ArgsT>(Args)...);
}
/// Calls the API and checks result.
///
/// \param Function liboffload API function to be called.
/// \param Args arguments to be passed to the liboffload API function.
///
/// \throw sycl::runtime_exception if the call was not successful.
template <typename FunctionType, typename... ArgsT>
void callAndThrow(FunctionType &Function, ArgsT &&...Args) {
auto Err = callNoCheck(Function, std::forward<ArgsT>(Args)...);
checkAndThrow(Err);
}
/// Converts liboffload backend to SYCL backend.
///
/// \param Backend liboffload backend.
///
/// \returns sycl::backend matching specified liboffload backend.
backend convertBackend(ol_platform_backend_t Backend);
/// Helper to map SYCL information descriptors to OL_<HANDLE>_INFO_<SMTH>.
///
/// Typical usage:
/// \code
/// using Map = info_ol_mapping<ol_foo_info_t>;
/// constexpr auto olInfo = map_info_desc<FromDesc, ol_foo_info_t>(
/// Map::M<DescVal0>{OL_FOO_INFO_VAL0},
/// Map::M<DescVal1>{OL_FOO_INFO_VAL1},
/// ...)
/// \endcode
template <typename To> struct info_ol_mapping {
template <typename From> struct M {
To value;
constexpr M(To value) : value(value) {}
};
};
template <typename From, typename To, typename... Ts>
constexpr To map_info_desc(typename info_ol_mapping<To>::template M<Ts>... ms) {
return std::get<typename info_ol_mapping<To>::template M<From>>(
std::tuple{ms...})
.value;
}
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL
#endif // _LIBSYCL_OFFLOAD_UTILS

View File

@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
//
// 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_utils.hpp>
#include <detail/global_objects.hpp>
#include <detail/platform_impl.hpp>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
PlatformImpl &PlatformImpl::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");
}
const std::vector<PlatformImplUPtr> &PlatformImpl::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<PlatformImpl>(
OffloadPlatform, PlatformIndex++, PrivateTag{}));
}
}
return true;
}();
return getPlatformCache();
}
PlatformImpl::PlatformImpl(ol_platform_handle_t Platform, size_t PlatformIndex,
PrivateTag)
: MOffloadPlatform(Platform), MOffloadPlatformIndex(PlatformIndex) {
ol_platform_backend_t Backend = OL_PLATFORM_BACKEND_UNKNOWN;
callAndThrow(olGetPlatformInfo, MOffloadPlatform, OL_PLATFORM_INFO_BACKEND,
sizeof(Backend), &Backend);
MBackend = convertBackend(Backend);
MOffloadBackend = Backend;
}
} // namespace detail
_LIBSYCL_END_NAMESPACE_SYCL

View File

@ -0,0 +1,112 @@
//===----------------------------------------------------------------------===//
//
// 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/offload_utils.hpp>
#include <OffloadAPI.h>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
_LIBSYCL_BEGIN_NAMESPACE_SYCL
namespace detail {
using PlatformImplUPtr = std::unique_ptr<PlatformImpl>;
class PlatformImpl {
struct PrivateTag {
explicit PrivateTag() = default;
};
public:
/// Constructs PlatformImpl 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).
/// All platform impls are created during first getPlatforms() call.
PlatformImpl(ol_platform_handle_t Platform, size_t PlatformIndex, PrivateTag);
~PlatformImpl() = default;
/// Returns the backend associated with this platform.
///
/// \returns sycl::backend associated with this platform.
backend getBackend() const noexcept { return MBackend; }
/// Returns all SYCL platforms from all backends that are
/// available in the system.
///
/// \returns std::vector of all platforms that are available in the system.
static const std::vector<PlatformImplUPtr> &getPlatforms();
/// Returns the raw underlying offload platform handle.
///
/// The caller is responsible for ensuring that the returned handle is only
/// used while the PlatformImpl object from which it was obtained is still
/// within its lifetime.
///
/// \return a raw offload platform handle.
const ol_platform_handle_t &getHandleRef() const { return MOffloadPlatform; }
/// Queries the cache to get the implementation for specified offloading RT
/// platform. All platform implementation objects are created at first
/// get_platforms call.
///
/// \param Platform is the offloading RT Platform handle representing the
/// platform.
/// \return the PlatformImpl representing the offloading RT platform.
static PlatformImpl &getPlatformImpl(ol_platform_handle_t Platform);
/// Queries this platform for info.
///
/// The return type depends on information being queried.
template <typename Param> typename Param::return_type getInfo() const {
// For now we have only std::string properties
static_assert(std::is_same_v<typename Param::return_type, std::string>);
using namespace info::platform;
using Map = info_ol_mapping<ol_platform_info_t>;
constexpr ol_platform_info_t olInfo =
map_info_desc<Param, ol_platform_info_t>(
Map::M<version>{OL_PLATFORM_INFO_VERSION},
Map::M<name>{OL_PLATFORM_INFO_NAME},
Map::M<vendor>{OL_PLATFORM_INFO_VENDOR_NAME});
size_t ExpectedSize = 0;
callAndThrow(olGetPlatformInfoSize, MOffloadPlatform, olInfo,
&ExpectedSize);
std::string Result;
Result.resize(ExpectedSize - 1);
callAndThrow(olGetPlatformInfo, MOffloadPlatform, olInfo, 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

48
libsycl/src/exception.cpp Normal file
View File

@ -0,0 +1,48 @@
//===----------------------------------------------------------------------===//
//
// 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/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 false; }
_LIBSYCL_END_NAMESPACE_SYCL

View File

@ -0,0 +1,21 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// SYCL 2020 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

View File

@ -8,10 +8,37 @@
#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() {
auto &PlatformImpls = detail::PlatformImpl::getPlatforms();
std::vector<platform> Platforms;
Platforms.reserve(PlatformImpls.size());
for (auto &PlatformImpl : PlatformImpls) {
platform Platform = detail::createSyclObjFromImpl<platform>(*PlatformImpl);
Platforms.push_back(std::move(Platform));
}
return Platforms;
}
template <typename Param>
detail::is_platform_info_desc_t<Param> platform::get_info() const {
return impl->getInfo<Param>();
}
#define _LIBSYCL_EXPORT_GET_INFO(Desc) \
template _LIBSYCL_EXPORT \
detail::is_platform_info_desc_t<info::platform::Desc> \
platform::get_info<info::platform::Desc>() const;
_LIBSYCL_EXPORT_GET_INFO(version)
_LIBSYCL_EXPORT_GET_INFO(name)
_LIBSYCL_EXPORT_GET_INFO(vendor)
#undef _LIBSYCL_EXPORT_GET_INFO
_LIBSYCL_END_NAMESPACE_SYCL

View File

@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of SYCL RT version macro.
/// This file contains the declaration of libsycl version macro.
///
//===----------------------------------------------------------------------===//
#define _LIBSYCL_MAJOR_VERSION ${LIBSYCL_MAJOR_VERSION}

View File

@ -0,0 +1 @@
add_subdirectory(sycl-ls)

View File

@ -0,0 +1,29 @@
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 (NOT LLVM_ENABLE_RTTI AND COMPILER_HAS_NORTTI_FLAG)
target_compile_options(sycl-ls PRIVATE -fno-rtti)
endif()
if (WIN32)
# For security purposes, searches for dependent libraries are limited to
# the combination of directories specified by the following flags of
# LoadLibraryEx().
# - LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR (0x100)
# - LOAD_LIBRARY_SEARCH_SYSTEM32 (0x800)
target_link_options(sycl-ls PRIVATE LINKER:/DEPENDENTLOADFLAG:0x900)
endif()
install(TARGETS sycl-ls
RUNTIME DESTINATION "bin" COMPONENT sycl-ls)

View File

@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// 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;
inline std::string_view getBackendName(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";
}
return "";
}
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;
return EXIT_SUCCESS;
}
for (const auto &Platform : Platforms) {
backend Backend = Platform.get_backend();
std::cout << "[" << getBackendName(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;
}
}
} catch (sycl::exception &e) {
std::cerr << "SYCL Exception encountered: " << e.what() << std::endl
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}