Skip to content
18 changes: 14 additions & 4 deletions libsycl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -117,10 +115,22 @@ add_custom_command(
install(DIRECTORY "${LIBSYCL_SOURCE_INCLUDE_DIR}/sycl" DESTINATION ${LIBSYCL_INCLUDE_DIR} COMPONENT sycl-headers)
install(DIRECTORY "${LIBSYCL_SOURCE_INCLUDE_DIR}/CL" DESTINATION ${LIBSYCL_INCLUDE_DIR} COMPONENT sycl-headers)

set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
set(LIBSYCL_LIB_NAME "sycl")
set(LIBSYCL_SHARED_OUTPUT_NAME "${LIBSYCL_LIB_NAME}")
if (CMAKE_SYSTEM_NAME STREQUAL Windows)
if (CMAKE_MSVC_RUNTIME_LIBRARY AND (NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "DLL$"))
message(FATAL_ERROR "libsycl requires a DLL version of the MSVC CRT.")
endif()
if ((NOT CMAKE_MSVC_RUNTIME_LIBRARY AND uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
OR (CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDebugDLL"))
set(LIBSYCL_SHARED_OUTPUT_NAME "${LIBSYCL_SHARED_OUTPUT_NAME}d")
endif()
endif()

add_subdirectory(src)

set(LIBSYCL_RT_LIBS ${LIBSYCL_SHARED_OUTPUT_NAME})
add_custom_target(libsycl-runtime-libraries
DEPENDS ${LIBSYCL_RT_LIBS}
)
add_subdirectory(tools)
12 changes: 9 additions & 3 deletions libsycl/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,17 @@ To build LLVM with libsycl runtime enabled the following script can be used.
mkdir -p $installprefix
cmake -G Ninja -S $llvm/llvm -B $build_llvm \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
-DLLVM_ENABLE_PROJECTS="clang" \
-DLLVM_INSTALL_UTILS=ON \
-DCMAKE_INSTALL_PREFIX=$installprefix \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libsycl;libunwind" \
-DLLVM_ENABLE_RUNTIMES="offload;openmp;libsycl" \
-DCMAKE_BUILD_TYPE=Release
ninja -C $build_llvm install
Limitations
========

SYCL runtime is not tested and is not guaranteed to work on Windows because offloading runtime (liboffload) used by SYCL runtime doesn't currently support Windows.
The limitation to be revised once liboffload will add support for Windows.
70 changes: 70 additions & 0 deletions libsycl/include/sycl/__impl/backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of the SYCL enum class backend that is
/// implementation-defined and is populated with a unique identifier for each
/// SYCL backend that the SYCL implementation can support.
///
//===----------------------------------------------------------------------===//

#ifndef _LIBSYCL___IMPL_BACKEND_HPP
#define _LIBSYCL___IMPL_BACKEND_HPP

#include <sycl/__impl/detail/config.hpp>

#include <string_view>
#include <type_traits>

_LIBSYCL_BEGIN_NAMESPACE_SYCL

// 4.1. Backends
enum class backend : char {
opencl = 1,
level_zero = 2,
cuda = 3,
hip = 4,
all = 5,
};

namespace detail {
template <typename T> struct is_backend_info_desc : std::false_type {};
} // namespace detail

// 4.5.1.1. Type traits backend_traits
template <backend Backend> class backend_traits;

template <backend Backend, typename SYCLObjectT>
using backend_input_t =
typename backend_traits<Backend>::template input_type<SYCLObjectT>;
template <backend Backend, typename SYCLObjectT>
using backend_return_t =
typename backend_traits<Backend>::template return_type<SYCLObjectT>;

namespace detail {
inline std::string_view get_backend_name(const backend &Backend) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to use something like _LIBCPP_HIDE_FROM_ABI here, if I understand the idea behind it correctly.

Copy link
Contributor Author

@KseniyaTikhomirova KseniyaTikhomirova Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave questions about ABI till the time I will add ABI tests

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, in intel/llvm this function is defined in headers only because we want to use it in the sycl-ls tool so the tool is always aligned on "known" backend with the SYCL RT.

If this intent still stands, I would add a comment about it, or otherwise this function should not exist here at all, because we don't use it anywhere else in the headers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is still used in sycl-ls.
added tiny comment
b15b6c0

switch (Backend) {
case backend::opencl:
return "opencl";
case backend::level_zero:
return "level_zero";
case backend::cuda:
return "cuda";
case backend::hip:
return "hip";
case backend::all:
return "all";
}

return "";
}
} // namespace detail

_LIBSYCL_END_NAMESPACE_SYCL

#endif // _LIBSYCL___IMPL_BACKEND_HPP
4 changes: 2 additions & 2 deletions libsycl/include/sycl/__impl/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 52 additions & 0 deletions libsycl/include/sycl/__impl/detail/macro_definitions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains macro definitions used in SYCL implementation.
///
//===----------------------------------------------------------------------===//

#ifndef _LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP
#define _LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP

#ifndef __SYCL2020_DEPRECATED
# if SYCL_LANGUAGE_VERSION == 202012L && \
!defined(SYCL2020_DISABLE_DEPRECATION_WARNINGS)
# define __SYCL2020_DEPRECATED(message) [[deprecated(message)]]
# else
# define __SYCL2020_DEPRECATED(message)
# endif
#endif // __SYCL2020_DEPRECATED

static_assert(__cplusplus >= 201703L,
"SYCL RT does not support C++ version earlier than C++17.");

#if defined(_WIN32) && !defined(_DLL) && !defined(__SYCL_DEVICE_ONLY__)
// SYCL library is designed such a way that STL objects cross DLL boundary,
// which is guaranteed to work properly only when the application uses the same
// C++ runtime that SYCL library uses.
// The appplications using sycl.dll must be linked with dynamic/release C++ MSVC
// runtime, i.e. be compiled with /MD switch. Similarly, the applications using
// sycld.dll must be linked with dynamic/debug C++ runtime and be compiled with
// /MDd switch.
// Compiler automatically adds /MD or /MDd when -fsycl switch is used.
// The options /MD and /MDd that make the code to use dynamic runtime also
// define the _DLL macro.
# define ERROR_MESSAGE \
"SYCL library is designed to work safely with dynamic C++ runtime." \
"Please use /MD switch with sycl.dll, /MDd switch with sycld.dll, " \
"or -fsycl switch to set C++ runtime automatically."
# if defined(_MSC_VER)
# pragma message(ERROR_MESSAGE)
# else
# warning ERROR_MESSAGE
# endif
# undef ERROR_MESSAGE
#endif // defined(_WIN32) && !defined(_DLL) && !defined(__SYCL_DEVICE_ONLY__)

#endif //_LIBSYCL___IMPL_DETAIL_MACRO_DEFINITIONS_HPP
64 changes: 64 additions & 0 deletions libsycl/include/sycl/__impl/detail/obj_base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains helper functions for tranformation between implementation
/// and SYCL's interface objects.
///
//===----------------------------------------------------------------------===//

#ifndef _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP
#define _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP

#include <sycl/__impl/detail/config.hpp>

#include <cassert>
#include <type_traits>
#include <utility>

_LIBSYCL_BEGIN_NAMESPACE_SYCL

namespace detail {

template <class Impl, class SyclObject> class ObjBase {
public:
using ImplType = Impl;
using Base = ObjBase<Impl, SyclObject>;

protected:
ImplType &impl;

explicit ObjBase(ImplType &pImpl) : impl(pImpl) {}
ObjBase() = default;

static SyclObject createSyclProxy(ImplType &impl) { return SyclObject(impl); }

template <class Obj>
friend const typename Obj::ImplType &getSyclObjImpl(const Obj &Object);

template <class Obj>
friend Obj createSyclObjFromImpl(
std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj);
};

template <class Obj>
const typename Obj::ImplType &getSyclObjImpl(const Obj &Object) {
return Object.impl;
}

template <class Obj>
Obj createSyclObjFromImpl(
std::add_lvalue_reference_t<typename Obj::ImplType> ImplObj) {
return Obj::Base::createSyclProxy(ImplObj);
}

} // namespace detail

_LIBSYCL_END_NAMESPACE_SYCL

#endif // _LIBSYCL___IMPL_DETAIL_OBJ_BASE_HPP
116 changes: 116 additions & 0 deletions libsycl/include/sycl/__impl/exception.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of the SYCL 2020 Exception class
/// interface (4.13.2.)
///
//===----------------------------------------------------------------------===//

#ifndef _LIBSYCL___IMPL_EXCEPTION_HPP
#define _LIBSYCL___IMPL_EXCEPTION_HPP

#include <sycl/__impl/detail/config.hpp>

#include <exception>
#include <memory>
#include <string>
#include <system_error>
#include <type_traits>
#include <vector>

_LIBSYCL_BEGIN_NAMESPACE_SYCL

class context;

enum class errc : int {
success = 0,
runtime = 1,
kernel = 2,
accessor = 3,
nd_range = 4,
event = 5,
kernel_argument = 6,
build = 7,
invalid = 8,
memory_allocation = 9,
platform = 10,
profiling = 11,
feature_not_supported = 12,
kernel_not_supported = 13,
backend_mismatch = 14,
};

/// Constructs an error code using E and sycl_category()
_LIBSYCL_EXPORT std::error_code make_error_code(sycl::errc E) noexcept;

/// Obtains a reference to the static error category object for SYCL errors.
_LIBSYCL_EXPORT const std::error_category &sycl_category() noexcept;

// Derive from std::exception so uncaught exceptions are printed in c++ default
// exception handler.
// Virtual inheritance is mandated by SYCL 2020.
// 4.13.2. Exception class interface
class _LIBSYCL_EXPORT exception : public virtual std::exception {
public:
exception(std::error_code, const char *);
exception(std::error_code Ec, const std::string &Msg)
: exception(Ec, Msg.c_str()) {}

exception(std::error_code EC) : exception(EC, "") {}
exception(int EV, const std::error_category &ECat, const std::string &WhatArg)
: exception(EV, ECat, WhatArg.c_str()) {}
exception(int EV, const std::error_category &ECat, const char *WhatArg)
: exception({EV, ECat}, WhatArg) {}
exception(int EV, const std::error_category &ECat)
: exception({EV, ECat}, "") {}

virtual ~exception();

const std::error_code &code() const noexcept;
const std::error_category &category() const noexcept;

const char *what() const noexcept final;

bool has_context() const noexcept;

private:
// Exceptions must be noexcept copy constructible, so cannot use std::string
// directly.
std::shared_ptr<std::string> MMessage;
Comment on lines +83 to +85
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great opportunity to start conversation with libcxx developers (@ldionne to start that, I think) on how/if we can share some of their implementation details. __libcpp_refstring would be perfect here.

Another potential opportunity (in a not so distant future PR) would be related to the implementation of std::shared_ptr. In a nutshell, some of the SYCL objects would probably be implemented (simplified) like this:

class event_impl; // defined inside libsycl.so, not exposed to the public headers
class event {
public:
  /* ... */
private:
  std::shared_ptr<event_impl> pImpl;
};

Ideally, we'd want to inherit event_impl from std::enable_shared_from_this. The problem we saw is that inheritance by itself slowed down construction of event_impl because even if know that we always create them via make_shared<event_iml> the implementation still had to initialize the std::enable_shared_from_this subobject with atomic operations resulting in a measurable overhead. If we could somehow use most the libc++'s implementation of these but with a way to communicate extra guarantees of how those objects are created and not to pay the price of these initialization atomics, that would be great, but I'm not sure if that's possible/worth maintenance efforts.

std::error_code MErrC = make_error_code(sycl::errc::invalid);
};

/// Used as a container for a list of asynchronous exceptions
///
class _LIBSYCL_EXPORT exception_list {
Comment on lines +89 to +91
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need it in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need exception in this PR and since exception_list can be almost fully implemented at the same time - I just did it.

public:
using value_type = std::exception_ptr;
using reference = value_type &;
using const_reference = const value_type &;
using size_type = std::size_t;
using iterator = std::vector<std::exception_ptr>::const_iterator;
using const_iterator = std::vector<std::exception_ptr>::const_iterator;

size_type size() const;
// first asynchronous exception
iterator begin() const;
// refer to past-the-end last asynchronous exception
iterator end() const;

private:
std::vector<std::exception_ptr> MList;
};

_LIBSYCL_END_NAMESPACE_SYCL

namespace std {
template <> struct is_error_code_enum<sycl::errc> : true_type {};
} // namespace std

#endif // _LIBSYCL___IMPL_EXCEPTION_HPP
8 changes: 8 additions & 0 deletions libsycl/include/sycl/__impl/info/platform.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef __SYCL_PARAM_TRAITS_SPEC
static_assert(false, "__SYCL_PARAM_TRAITS_SPEC is required but not defined");
#endif

// 4.6.2.4. Information descriptors
__SYCL_PARAM_TRAITS_SPEC(platform, version, std::string, OL_PLATFORM_INFO_VERSION)
__SYCL_PARAM_TRAITS_SPEC(platform, name, std::string, OL_PLATFORM_INFO_NAME)
__SYCL_PARAM_TRAITS_SPEC(platform, vendor, std::string, OL_PLATFORM_INFO_VENDOR_NAME)
Copy link
Contributor

@aelovikov-intel aelovikov-intel Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective, but I'm not a fan of this approach for two reasons:

  1. Smart use of preprocessor in distributable header files (i.e., libsycl/include instead of libsycl/source/**).
  2. OL_* are implementation details and don't need to be present in those distributable headers.

I think avoiding it doesn't result in too much code duplication: 823c765, but I understand that this is subjective.

Macro in exports can be avoided too, but that's probably too much magic:

// sycl.hpp
#define _EXPORT __attribute__((visibility("default")))
struct S {
  template <typename> _EXPORT void foo();
};

// libsycl.so
template <typename> [[gnu::used]] _EXPORT void S::foo() {}

template _EXPORT void S::foo<char>(); // current approach

// "Clever" helper, needs `[[gnu::used]]` above.
template <typename... Ts> void instantiate_helper() {
  (((void)(&S::foo<Ts>), ...));
}
static void instantiate() { instantiate_helper<int, float, double>(); }
$ clang++ a.cpp -c -fvisibility=hidden -fvisibility-inlines-hidden -O0 ; nm a.o | c++filt
0000000000000000 W void S::foo<char>()                                                   
0000000000000000 W void S::foo<double>()                                                 
0000000000000000 W void S::foo<float>()                                                  
0000000000000000 W void S::foo<int>()                                                    

$ clang++ a.cpp -c -fvisibility=hidden -fvisibility-inlines-hidden -O3 ; nm a.o | c++filt
0000000000000000 W void foo<char>()                                                      
0000000000000000 W void foo<double>()                                                    
0000000000000000 W void foo<float>()                                                     
0000000000000000 W void foo<int>()                                                       

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to ask other folks for opinion here. The benefit that .def file provides is necessity in update of only one place in the code to add info or property (we use the same approach there) if there is no special handling.

@sergey-semenov, @bader, @vinser52, @tahonermann, @AlexeySachkov do you have any preference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective, but I'm not a fan of this approach for two reasons:

  1. Smart use of preprocessor in distributable header files (i.e., libsycl/include instead of libsycl/source/**).
  2. OL_* are implementation details and don't need to be present in those distributable headers.

I don't understand the problem with using pre-processor in distributed header files, but I agree that mapping from SYCL API to liboffload API should be done in the library source code.

Loading
Loading