diff --git a/libsycl/CMakeLists.txt b/libsycl/CMakeLists.txt index fe08a4249bada..f25f51def0cc7 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,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_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME}) - -add_subdirectory(src) +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_custom_target(libsycl-runtime-libraries DEPENDS ${LIBSYCL_RT_LIBS} ) + +add_subdirectory(src) + +add_subdirectory(tools) diff --git a/libsycl/README.md b/libsycl/README.md index 1ef6505bf7a03..22549e49760a0 100644 --- a/libsycl/README.md +++ b/libsycl/README.md @@ -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. diff --git a/libsycl/docs/index.rst b/libsycl/docs/index.rst index 78e76e73284d3..ea037837ab720 100644 --- a/libsycl/docs/index.rst +++ b/libsycl/docs/index.rst @@ -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,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 +======== + +Libsycl is not currently supported on Windows because it depends on liboffload +which doesn't currently support Windows. diff --git a/libsycl/include/sycl/__impl/backend.hpp b/libsycl/include/sycl/__impl/backend.hpp new file mode 100644 index 0000000000000..8dc5711d16b3d --- /dev/null +++ b/libsycl/include/sycl/__impl/backend.hpp @@ -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 + +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +// SYCL 2020 4.1. Backends. +enum class backend : unsigned char { + opencl = 0, + level_zero, + cuda, + hip, +}; + +namespace detail { +template struct is_backend_info_desc : std::false_type {}; +} // namespace detail + +// SYCL 2020 4.5.1.1. Type traits backend_traits. +template class backend_traits; + +template +using backend_input_t = + typename backend_traits::template input_type; +template +using backend_return_t = + typename backend_traits::template return_type; + +_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..f436cea522fe1 --- /dev/null +++ b/libsycl/include/sycl/__impl/detail/macro_definitions.hpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#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_MACRO_DEFINITIONS_HPP diff --git a/libsycl/include/sycl/__impl/detail/obj_utils.hpp b/libsycl/include/sycl/__impl/detail/obj_utils.hpp new file mode 100644 index 0000000000000..b4c1250e298c4 --- /dev/null +++ b/libsycl/include/sycl/__impl/detail/obj_utils.hpp @@ -0,0 +1,76 @@ +//===----------------------------------------------------------------------===// +// +// 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_UTILS_HPP +#define _LIBSYCL___IMPL_DETAIL_OBJ_UTILS_HPP + +#include + +#include +#include +#include +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +// Note! This class relies on the fact that all SYCL interface +// classes contain "impl" field that points to implementation object. "impl" +// field should be accessible from this class. +struct ImplUtils { + // Helper function for extracting implementation from SYCL's interface + // objects. + template + static const decltype(Obj::impl) &getSyclObjImpl(const Obj &SyclObj) { + assert(SyclObj.impl && "every constructor should create an impl"); + return SyclObj.impl; + } + + // Helper function for creation SYCL interface objects from implementations. + template + static SyclObject createSyclObjFromImpl(From &&from) { + if constexpr (std::is_same_v>>) + return SyclObject{from.shared_from_this()}; + else + return SyclObject{std::forward(from)}; + } +}; + +template +auto getSyclObjImpl(const Obj &SyclObj) + -> decltype(ImplUtils::getSyclObjImpl(SyclObj)) { + return ImplUtils::getSyclObjImpl(SyclObj); +} + +template +SyclObject createSyclObjFromImpl(From &&from) { + return ImplUtils::createSyclObjFromImpl(std::forward(from)); +} + +// SYCL 2020 4.5.2. Common reference semantics (std::hash support). +template struct HashBase { + size_t operator()(const T &Obj) const { + auto &Impl = sycl::detail::getSyclObjImpl(Obj); + return std::hash>{}(Impl); + } +}; + +} // namespace detail + +_LIBSYCL_END_NAMESPACE_SYCL + +#endif // _LIBSYCL___IMPL_DETAIL_OBJ_UTILS_HPP diff --git a/libsycl/include/sycl/__impl/exception.hpp b/libsycl/include/sycl/__impl/exception.hpp new file mode 100644 index 0000000000000..c2c1e7706a88a --- /dev/null +++ b/libsycl/include/sycl/__impl/exception.hpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include +#include +#include +#include +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +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 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::const_iterator; + using const_iterator = std::vector::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 MList; +}; + +_LIBSYCL_END_NAMESPACE_SYCL + +namespace std { +template <> struct is_error_code_enum : true_type {}; +} // namespace std + +#endif // _LIBSYCL___IMPL_EXCEPTION_HPP diff --git a/libsycl/include/sycl/__impl/info/desc_base.hpp b/libsycl/include/sycl/__impl/info/desc_base.hpp new file mode 100644 index 0000000000000..0fc4284d60b68 --- /dev/null +++ b/libsycl/include/sycl/__impl/info/desc_base.hpp @@ -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 + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +template struct info_desc_tag {}; + +template +struct is_info_desc : std::false_type {}; + +template +struct is_info_desc< + Desc, DescOf, + std::enable_if_t, Desc>>> + : std::true_type { + using return_type = typename Desc::return_type; +}; + +} // namespace detail + +_LIBSYCL_END_NAMESPACE_SYCL + +#endif // _LIBSYCL___IMPL_INFO_DESC_BASE_HPP diff --git a/libsycl/include/sycl/__impl/info/platform.hpp b/libsycl/include/sycl/__impl/info/platform.hpp new file mode 100644 index 0000000000000..8a4b071fae6b6 --- /dev/null +++ b/libsycl/include/sycl/__impl/info/platform.hpp @@ -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 +#include + +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +class platform; + +namespace detail { +template +using is_platform_info_desc_t = typename is_info_desc::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 { + using return_type = std::string; +}; +struct name : detail::info_desc_tag { + using return_type = std::string; +}; +struct vendor : detail::info_desc_tag { + using return_type = std::string; +}; +} // namespace platform +} // namespace info + +_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..9811ef2a341d1 100644 --- a/libsycl/include/sycl/__impl/platform.hpp +++ b/libsycl/include/sycl/__impl/platform.hpp @@ -15,17 +15,71 @@ #ifndef _LIBSYCL___IMPL_PLATFORM_HPP #define _LIBSYCL___IMPL_PLATFORM_HPP +#include #include +#include +#include + +#include +#include _LIBSYCL_BEGIN_NAMESPACE_SYCL +namespace detail { +class platform_impl; +} // 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 + detail::is_platform_info_desc_t get_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 get_platforms(); + +private: + platform(detail::platform_impl &Impl) : impl(&Impl) {} + detail::platform_impl *impl; + + friend sycl::detail::ImplUtils; }; // class platform _LIBSYCL_END_NAMESPACE_SYCL +template <> +struct std::hash + : public sycl::detail::HashBase {}; + #endif // _LIBSYCL___IMPL_PLATFORM_HPP 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 #include #endif // _LIBSYCL_SYCL_HPP diff --git a/libsycl/src/CMakeLists.txt b/libsycl/src/CMakeLists.txt index 206b85681cb84..5f4be546de38f 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}) @@ -15,21 +11,25 @@ function(add_sycl_rt_library LIB_TARGET_NAME LIB_OBJ_NAME LIB_OUTPUT_NAME) $<$:_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 $) add_dependencies(${LIB_OBJ_NAME} sycl-headers + LLVMOffload + ) + + target_include_directories( + ${LIB_OBJ_NAME} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBSYCL_BUILD_INCLUDE_DIR} + $ ) - set_target_properties(${LIB_TARGET_NAME} PROPERTIES LINKER_LANGUAGE CXX) + set_target_properties(${LIB_TARGET_NAME} PROPERTIES + LINKER_LANGUAGE CXX + POSITION_INDEPENDENT_CODE TRUE) if (CMAKE_SYSTEM_NAME STREQUAL Windows) # Install stripped PDB @@ -65,6 +65,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 +75,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..bf7a33ccf7a54 --- /dev/null +++ b/libsycl/src/detail/global_objects.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#ifdef _WIN32 +# include +#endif + +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL +namespace detail { + +std::vector &getOffloadTopologies() { + static std::vector Topologies( + OL_PLATFORM_BACKEND_LAST); + return Topologies; +} + +std::vector &getPlatformCache() { + static std::vector 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) { + // 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 libsycl +// 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..d826fcedefd45 --- /dev/null +++ b/libsycl/src/detail/global_objects.hpp @@ -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 +#include + +#include +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { +class platform_impl; + +/// 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 &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> &getPlatformCache(); + +} // namespace detail +_LIBSYCL_END_NAMESPACE_SYCL + +#endif // _LIBSYCL_GLOBAL_OBJECTS diff --git a/libsycl/src/detail/offload/offload_topology.cpp b/libsycl/src/detail/offload/offload_topology.cpp new file mode 100644 index 0000000000000..8749530389f04 --- /dev/null +++ b/libsycl/src/detail/offload/offload_topology.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +void discoverOffloadDevices() { + call_and_throw(olInit); + + using PerBackendDataType = + std::array, + 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(User); + ol_platform_handle_t Plat = nullptr; + ol_result_t Res = call_nocheck( + olGetDeviceInfo, Dev, OL_DEVICE_INFO_PLATFORM, sizeof(Plat), &Plat); + // If error occurs, 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 occurs, 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(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(I)); + Topo.registerNewPlatformsAndDevices(Mapping[I].first, Mapping[I].second); + } +} + +} // 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..86717b8a06c6c --- /dev/null +++ b/libsycl/src/detail/offload/offload_topology.hpp @@ -0,0 +1,121 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +#include + +#include +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +// Minimal span-like view. +template 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>; + +/// 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 set_backend(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 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 + devicesForPlatform(size_t PlatformId) const { + if (PlatformId >= MDevRangePerPlatformId.size()) { + 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 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 MPlatforms; + std::vector MDevices; // sorted by platform + + // Vector holding range of devices for each platform (index is platform index + // within MPlatforms) + std::vector> + MDevRangePerPlatformId; // MDevRangePerPlatformId.size() == + // MPlatforms.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..a2aa45e7102c1 --- /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 + +_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 diff --git a/libsycl/src/detail/offload/offload_utils.hpp b/libsycl/src/detail/offload/offload_utils.hpp new file mode 100644 index 0000000000000..73fcf485b9c59 --- /dev/null +++ b/libsycl/src/detail/offload/offload_utils.hpp @@ -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 +#include +#include + +#include + +_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 +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 +ol_result_t call_nocheck(FunctionType &Function, ArgsT &&...Args) { + return Function(std::forward(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 +void call_and_throw(FunctionType &Function, ArgsT &&...Args) { + auto Err = call_nocheck(Function, std::forward(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__INFO_. +/// +/// Typical usage: +/// \code +/// using Map = info_ol_mapping; +/// constexpr auto olInfo = map_info_desc( +/// Map::M{OL_FOO_INFO_VAL0}, +/// Map::M{OL_FOO_INFO_VAL1}, +/// ...) +/// \endcode +template struct info_ol_mapping { + template struct M { + To value; + constexpr M(To value) : value(value) {} + }; +}; +template +constexpr To map_info_desc(typename info_ol_mapping::template M... ms) { + return std::get::template M>( + std::tuple{ms...}) + .value; +} + +} // 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..d44d54b3a871c --- /dev/null +++ b/libsycl/src/detail/platform_impl.cpp @@ -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 +#include + +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +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"); +} + +const std::vector &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( + OffloadPlatform, PlatformIndex++, private_tag{})); + } + } + return true; + }(); + return getPlatformCache(); +} + +platform_impl::platform_impl(ol_platform_handle_t Platform, + size_t PlatformIndex, private_tag) + : 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..b3aa5730cc1e3 --- /dev/null +++ b/libsycl/src/detail/platform_impl.hpp @@ -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 +#include +#include + +#include + +#include + +#include +#include +#include +#include + +_LIBSYCL_BEGIN_NAMESPACE_SYCL + +namespace detail { + +using PlatformImplUPtr = std::unique_ptr; + +class platform_impl { + struct private_tag { + explicit private_tag() = default; + }; + +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). + /// All platform impls are created during first getPlatforms() call. + explicit platform_impl(ol_platform_handle_t Platform, size_t PlatformIndex, + private_tag); + + ~platform_impl() = 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 &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 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 platform_impl representing the offloading RT platform. + static platform_impl &getPlatformImpl(ol_platform_handle_t Platform); + + /// Queries this platform for info. + /// + /// The return type depends on information being queried. + template typename Param::return_type get_info() const { + // For now we have only std::string properties + static_assert(std::is_same_v); + + using namespace info::platform; + using Map = info_ol_mapping; + + constexpr ol_platform_info_t olInfo = + map_info_desc( + Map::M{OL_PLATFORM_INFO_VERSION}, + Map::M{OL_PLATFORM_INFO_NAME}, + Map::M{OL_PLATFORM_INFO_VENDOR_NAME}); + + size_t ExpectedSize = 0; + call_and_throw(olGetPlatformInfoSize, MOffloadPlatform, olInfo, + &ExpectedSize); + std::string Result; + Result.resize(ExpectedSize - 1); + call_and_throw(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 diff --git a/libsycl/src/exception.cpp b/libsycl/src/exception.cpp new file mode 100644 index 0000000000000..0b69c2a217fdc --- /dev/null +++ b/libsycl/src/exception.cpp @@ -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 +#include + +_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(Err), sycl_category()); +} + +// Exception methods implementation +exception::exception(std::error_code EC, const char *Msg) + : MMessage(std::make_shared(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 diff --git a/libsycl/src/exception_list.cpp b/libsycl/src/exception_list.cpp new file mode 100644 index 0000000000000..1c0a78bd33681 --- /dev/null +++ b/libsycl/src/exception_list.cpp @@ -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 +#include + +_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..d47af135dae3d 100644 --- a/libsycl/src/platform.cpp +++ b/libsycl/src/platform.cpp @@ -8,10 +8,37 @@ #include +#include + #include _LIBSYCL_BEGIN_NAMESPACE_SYCL -platform::platform() { throw std::runtime_error("Unimplemented"); } +backend platform::get_backend() const noexcept { return impl->getBackend(); } + +std::vector platform::get_platforms() { + auto &PlatformImpls = detail::platform_impl::getPlatforms(); + std::vector Platforms; + Platforms.reserve(PlatformImpls.size()); + for (auto &PlatformImpl : PlatformImpls) { + platform Platform = detail::createSyclObjFromImpl(*PlatformImpl); + Platforms.push_back(std::move(Platform)); + } + return Platforms; +} + +template +detail::is_platform_info_desc_t platform::get_info() const { + return impl->get_info(); +} + +#define _LIBSYCL_EXPORT_GET_INFO(Desc) \ + template _LIBSYCL_EXPORT \ + detail::is_platform_info_desc_t \ + platform::get_info() 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 diff --git a/libsycl/src/version.hpp.in b/libsycl/src/version.hpp.in index a7215761e9d4c..e4a4f957e3eca 100644 --- a/libsycl/src/version.hpp.in +++ b/libsycl/src/version.hpp.in @@ -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} 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..e0d9d349d9e98 --- /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 (NOT LLVM_ENABLE_RTTI AND 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..366a3d767121d --- /dev/null +++ b/libsycl/tools/sycl-ls/sycl-ls.cpp @@ -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 + +#include "llvm/Support/CommandLine.h" + +#include + +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 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(); + auto PlatformName = Platform.get_info(); + auto PlatformVendor = Platform.get_info(); + 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_SUCCESS; +}