diff --git a/sycl/CMakeLists.txt b/sycl/CMakeLists.txt index 4629f32b65653..fd6c9ce22aad7 100644 --- a/sycl/CMakeLists.txt +++ b/sycl/CMakeLists.txt @@ -143,8 +143,37 @@ if (MSVC) list(APPEND SYCL_RT_LIBS sycld) endif() +# This function allows building multiple libraries with the same options. +# Currently used by sycl and plugins library. +# Currently handles linking with libcxx support and gcc workaround +function( add_common_options LIB_NAME) + if (SYCL_USE_LIBCXX) + if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR + (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) + target_compile_options(${LIB_NAME} PRIVATE -nostdinc++) + if ((NOT (DEFINED SYCL_LIBCXX_INCLUDE_PATH)) OR (NOT (DEFINED SYCL_LIBCXX_LIBRARY_PATH))) + message(FATAL_ERROR "When building with libc++ SYCL_LIBCXX_INCLUDE_PATHS and" + "SYCL_LIBCXX_LIBRARY_PATH should be set") + endif() + target_include_directories(${LIB_NAME} PRIVATE "${SYCL_LIBCXX_INCLUDE_PATH}") + target_link_libraries(${LIB_NAME} PRIVATE "-L${SYCL_LIBCXX_LIBRARY_PATH}" -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc) + else() + message(FATAL_ERROR "Build with libc++ is not yet supported for this compiler") + endif() + else() + +# Workaround for bug in GCC version 5 and higher. +# More information https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1568899 + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND + CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0) + target_link_libraries(${LIB_NAME} PRIVATE gcc_s gcc) + endif() + + endif() +endfunction(add_common_options) + # SYCL runtime library -add_subdirectory(source) +add_subdirectory( source ) # SYCL toolchain builds all components: compiler, libraries, headers, etc. add_custom_target( sycl-toolchain @@ -173,6 +202,10 @@ option(SYCL_INCLUDE_TESTS "Generate build targets for the SYCL unit tests." ${LLVM_INCLUDE_TESTS}) + +# Plugin Library +add_subdirectory( plugins ) + add_subdirectory(tools) if(SYCL_INCLUDE_TESTS) diff --git a/sycl/include/CL/sycl/detail/pi.hpp b/sycl/include/CL/sycl/detail/pi.hpp index 174992d86585a..b951a1329ff9e 100644 --- a/sycl/include/CL/sycl/detail/pi.hpp +++ b/sycl/include/CL/sycl/detail/pi.hpp @@ -14,168 +14,176 @@ #include #include +#include +#include + +// Function to load the shared library +// Implementation is OS dependent. +void *loadOsLibrary(const std::string &Library); + +// Function to get Address of a symbol defined in the shared +// library, implementation is OS dependent. +void *getOsLibraryFuncAddress(void *Library, const std::string &FunctionName); + namespace cl { namespace sycl { namespace detail { namespace pi { - // For selection of SYCL RT back-end, now manually through the "SYCL_BE" - // environment variable. - // - enum Backend { - SYCL_BE_PI_OPENCL, - SYCL_BE_PI_OTHER - }; - - // Check for manually selected BE at run-time. - bool useBackend(Backend Backend); - - using PiResult = ::pi_result; - using PiPlatform = ::pi_platform; - using PiDevice = ::pi_device; - using PiDeviceType = ::pi_device_type; - using PiDeviceInfo = ::pi_device_info; - using PiDeviceBinaryType = ::pi_device_binary_type; - using PiContext = ::pi_context; - using PiProgram = ::pi_program; - using PiKernel = ::pi_kernel; - using PiQueue = ::pi_queue; - using PiQueueProperties = ::pi_queue_properties; - using PiMem = ::pi_mem; - using PiMemFlags = ::pi_mem_flags; - using PiEvent = ::pi_event; - using PiSampler = ::pi_sampler; - using PiSamplerInfo = ::pi_sampler_info; - using PiSamplerProperties = ::pi_sampler_properties; - using PiSamplerAddressingMode = ::pi_sampler_addressing_mode; - using PiSamplerFilterMode = ::pi_sampler_filter_mode; - using PiMemImageFormat = ::pi_image_format; - using PiMemImageDesc = ::pi_image_desc; - using PiMemImageInfo = ::pi_image_info; - using PiMemObjectType = ::pi_mem_type; - using PiMemImageChannelOrder = ::pi_image_channel_order; - using PiMemImageChannelType = ::pi_image_channel_type; - - // Get a string representing a _pi_platform_info enum - std::string platformInfoToString(pi_platform_info info); - - // Report error and no return (keeps compiler happy about no return statements). - [[noreturn]] void die(const char *Message); - void assertion(bool Condition, const char *Message = nullptr); - - // Want all the needed casts be explicit, do not define conversion operators. - template - To cast(From value); - - // Forward declarations of the PI dispatch entries. +// For selection of SYCL RT back-end, now manually through the "SYCL_BE" +// environment variable. +// +enum Backend { SYCL_BE_PI_OPENCL, SYCL_BE_PI_OTHER }; + +#ifdef SYCL_RT_OS_WINDOWS +#define PLUGIN_NAME "pi_opencl.dll" +#else +#define PLUGIN_NAME "libpi_opencl.so" +#endif + +// Check for manually selected BE at run-time. +bool useBackend(Backend Backend); + +using PiResult = ::pi_result; +using PiPlatform = ::pi_platform; +using PiDevice = ::pi_device; +using PiDeviceType = ::pi_device_type; +using PiDeviceInfo = ::pi_device_info; +using PiDeviceBinaryType = ::pi_device_binary_type; +using PiContext = ::pi_context; +using PiProgram = ::pi_program; +using PiKernel = ::pi_kernel; +using PiQueue = ::pi_queue; +using PiQueueProperties = ::pi_queue_properties; +using PiMem = ::pi_mem; +using PiMemFlags = ::pi_mem_flags; +using PiEvent = ::pi_event; +using PiSampler = ::pi_sampler; +using PiSamplerInfo = ::pi_sampler_info; +using PiSamplerProperties = ::pi_sampler_properties; +using PiSamplerAddressingMode = ::pi_sampler_addressing_mode; +using PiSamplerFilterMode = ::pi_sampler_filter_mode; +using PiMemImageFormat = ::pi_image_format; +using PiMemImageDesc = ::pi_image_desc; +using PiMemImageInfo = ::pi_image_info; +using PiMemObjectType = ::pi_mem_type; +using PiMemImageChannelOrder = ::pi_image_channel_order; +using PiMemImageChannelType = ::pi_image_channel_type; + +// Get a string representing a _pi_platform_info enum +std::string platformInfoToString(pi_platform_info info); + +// Report error and no return (keeps compiler happy about no return statements). +[[noreturn]] void die(const char *Message); +void assertion(bool Condition, const char *Message = nullptr); + +// Want all the needed casts be explicit, do not define conversion operators. +template To cast(From value); + +// Forward declarations of the PI dispatch entries. #define _PI_API(api) __SYCL_EXPORTED extern decltype(::api) *(api); #include - // Performs PI one-time initialization. - void initialize(); - - // The PiCall helper structure facilitates performing a call to PI. - // It holds utilities to do the tracing and to check the returned result. - // TODO: implement a more mature and controllable tracing of PI calls. - class PiCall { - PiResult m_Result; - static bool m_TraceEnabled; - - public: - explicit PiCall(const char *Trace = nullptr); - ~PiCall(); - PiResult get(PiResult Result); - template - void check(PiResult Result); - }; - - // The run-time tracing of PI calls. - // TODO: replace PiCall completely with this one (PiTrace) - // - template inline - void print(T val) { - std::cout << " : " << val; - } +// Performs PI one-time initialization. +void initialize(); + +// The PiCall helper structure facilitates performing a call to PI. +// It holds utilities to do the tracing and to check the returned result. +// TODO: implement a more mature and controllable tracing of PI calls. +class PiCall { + PiResult m_Result; + static bool m_TraceEnabled; + +public: + explicit PiCall(const char *Trace = nullptr); + ~PiCall(); + PiResult get(PiResult Result); + template void check(PiResult Result); +}; + +// The run-time tracing of PI calls. +// TODO: replace PiCall completely with this one (PiTrace) +// +template inline void print(T val) { + std::cout << " : " << val; +} - template<> inline void print<> (PiPlatform val) { std::cout << "pi_platform : " << val; } - template<> inline void print<> (PiResult val) { - std::cout << "pi_result : "; - if (val == PI_SUCCESS) - std::cout << "PI_SUCCESS"; - else - std::cout << val; - } - - inline void printArgs(void) {} - template - void printArgs(Arg0 arg0, Args... args) { - std::cout << std::endl << " "; - print(arg0); - printArgs(std::forward(args)...); +template <> inline void print<>(PiPlatform val) { + std::cout << "pi_platform : " << val; +} +template <> inline void print<>(PiResult val) { + std::cout << "pi_result : "; + if (val == PI_SUCCESS) + std::cout << "PI_SUCCESS"; + else + std::cout << val; +} + +inline void printArgs(void) {} +template +void printArgs(Arg0 arg0, Args... args) { + std::cout << std::endl << " "; + print(arg0); + printArgs(std::forward(args)...); +} + +template class Trace { +private: + FnType m_FnPtr; + static bool m_TraceEnabled; + +public: + Trace(FnType FnPtr, const std::string &FnName) : m_FnPtr(FnPtr) { + if (m_TraceEnabled) + std::cout << "---> " << FnName << "("; } - - template - class Trace { - private: - FnType m_FnPtr; - static bool m_TraceEnabled; - public: - Trace(FnType FnPtr, const std::string &FnName) : m_FnPtr(FnPtr) { - if (m_TraceEnabled) - std::cout << "---> " << FnName << "("; - } - - template - typename std::result_of::type - operator() (Args... args) { - if (m_TraceEnabled) - printArgs(args...); - - initialize(); - auto r = m_FnPtr(args...); - - if (m_TraceEnabled) { - std::cout << ") ---> "; - std::cout << (print(r),"") << "\n"; - } - return r; + + template + typename std::result_of::type operator()(Args... args) { + if (m_TraceEnabled) + printArgs(args...); + + initialize(); + auto r = m_FnPtr(args...); + + if (m_TraceEnabled) { + std::cout << ") ---> "; + std::cout << (print(r), "") << "\n"; } - }; + return r; + } +}; - template - bool Trace::m_TraceEnabled = (std::getenv("SYCL_PI_TRACE") != nullptr); +template +bool Trace::m_TraceEnabled = (std::getenv("SYCL_PI_TRACE") != nullptr); } // namespace pi namespace RT = cl::sycl::detail::pi; -#define PI_ASSERT(cond, msg) \ - RT::assertion((cond), "assert: " msg); +#define PI_ASSERT(cond, msg) RT::assertion((cond), "assert: " msg); #define PI_TRACE(func) RT::Trace(func, #func) // This does the call, the trace and the check for no errors. -#define PI_CALL(pi) \ - RT::initialize(), \ - RT::PiCall(#pi).check( \ - RT::cast(pi)) +#define PI_CALL(pi) \ + RT::initialize(), RT::PiCall(#pi).check( \ + RT::cast(pi)) // This does the trace, the call, and returns the result -#define PI_CALL_RESULT(pi) \ - RT::PiCall(#pi).get(detail::RT::cast(pi)) +#define PI_CALL_RESULT(pi) \ + RT::PiCall(#pi).get(detail::RT::cast(pi)) // This does the check for no errors and possibly throws -#define PI_CHECK(pi) \ - RT::PiCall().check( \ - RT::cast(pi)) +#define PI_CHECK(pi) \ + RT::PiCall().check( \ + RT::cast(pi)) // This does the check for no errors and possibly throws x -#define PI_CHECK_THROW(pi, x) \ - RT::PiCall().check( \ - RT::cast(pi)) +#define PI_CHECK_THROW(pi, x) \ + RT::PiCall().check(RT::cast(pi)) // Want all the needed casts be explicit, do not define conversion operators. -template -To pi::cast(From value) { +template To pi::cast(From value) { // TODO: see if more sanity checks are possible. PI_ASSERT(sizeof(From) == sizeof(To), "cast failed size check"); return (To)(value); diff --git a/sycl/plugins/CMakeLists.txt b/sycl/plugins/CMakeLists.txt new file mode 100644 index 0000000000000..ac0ced6f26bd5 --- /dev/null +++ b/sycl/plugins/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(opencl) diff --git a/sycl/plugins/opencl/CMakeLists.txt b/sycl/plugins/opencl/CMakeLists.txt new file mode 100644 index 0000000000000..f9953bbed30cc --- /dev/null +++ b/sycl/plugins/opencl/CMakeLists.txt @@ -0,0 +1,39 @@ +#TODO: +#1. Figure out why CMP0057 has to be set. Should have been taken care of earlier in the build +#2. Use AddLLVM to modify the build and access config options +#cmake_policy(SET CMP0057 NEW) +#include(AddLLVM) + +# Plugin for OpenCL +# Create Shared library for libpi_opencl.so. +#TODO: remove dependency on pi.hpp in sycl project. +#TODO: Currently, the pi.hpp header is common between sycl and plugin library sources. +#This can be changed by copying the pi.hpp file in the plugins project. +add_library(pi_opencl SHARED + "${sycl_inc_dir}/CL/sycl/detail/pi.h" + "pi_opencl.cpp" + ) + +add_dependencies(pi_opencl + ocl-icd + ocl-headers +) + +add_dependencies(sycl-toolchain pi_opencl) + +set_target_properties(pi_opencl PROPERTIES LINKER_LANGUAGE CXX) + +#preprocessor definitions for compiling a target's sources. We do not need it for pi_opencl +target_include_directories(pi_opencl PRIVATE "${sycl_inc_dir}") + +#link pi_opencl with OpenCL headers and ICD Loader. +target_link_libraries( pi_opencl + PRIVATE OpenCL::Headers + PRIVATE ${OpenCL_LIBRARIES} +) + +add_common_options(pi_opencl) + +install(TARGETS pi_opencl + LIBRARY DESTINATION "lib" COMPONENT pi_opencl + RUNTIME DESTINATION "bin" COMPONENT pi_opencl) diff --git a/sycl/source/detail/pi_opencl.cpp b/sycl/plugins/opencl/pi_opencl.cpp old mode 100644 new mode 100755 similarity index 54% rename from sycl/source/detail/pi_opencl.cpp rename to sycl/plugins/opencl/pi_opencl.cpp index 1534ed89ba38c..0b9252d560798 --- a/sycl/source/detail/pi_opencl.cpp +++ b/sycl/plugins/opencl/pi_opencl.cpp @@ -6,63 +6,70 @@ // //===----------------------------------------------------------------------===// #include "CL/opencl.h" -#include +#include + #include #include +#include +#include + +#define CHECK_ERR_SET_NULL_RET(err, ptr, reterr) \ + if (err != CL_SUCCESS) { \ + if (ptr != nullptr) \ + *ptr = nullptr; \ + return cast(reterr); \ + } -namespace cl { -namespace sycl { -namespace detail { -namespace pi { +// Want all the needed casts be explicit, do not define conversion operators. +template To cast(From value) { + // TODO: see if more sanity checks are possible. + static_assert(sizeof(From) == sizeof(To), "cast failed size check"); + return (To)(value); +} -// Convinience macro makes source code search easier +extern "C" { + +// Convenience macro makes source code search easier #define OCL(pi_api) Ocl##pi_api // Example of a PI interface that does not map exactly to an OpenCL one. -pi_result OCL(piPlatformsGet)(pi_uint32 num_entries, - pi_platform * platforms, - pi_uint32 * num_platforms) { - cl_int result = - clGetPlatformIDs(cast (num_entries), - cast (platforms), - cast (num_platforms)); +pi_result OCL(piPlatformsGet)(pi_uint32 num_entries, pi_platform *platforms, + pi_uint32 *num_platforms) { + cl_int result = clGetPlatformIDs(cast(num_entries), + cast(platforms), + cast(num_platforms)); // Absorb the CL_PLATFORM_NOT_FOUND_KHR and just return 0 in num_platforms if (result == CL_PLATFORM_NOT_FOUND_KHR) { - assertion(num_platforms != 0); + assert(num_platforms != 0); *num_platforms = 0; result = PI_SUCCESS; } - return cast(result); + return static_cast(result); } - // Example of a PI interface that does not map exactly to an OpenCL one. -pi_result OCL(piDevicesGet)(pi_platform platform, - pi_device_type device_type, - pi_uint32 num_entries, - pi_device * devices, - pi_uint32 * num_devices) { - cl_int result = - clGetDeviceIDs(cast (platform), - cast (device_type), - cast (num_entries), - cast (devices), - cast (num_devices)); +pi_result OCL(piDevicesGet)(pi_platform platform, pi_device_type device_type, + pi_uint32 num_entries, pi_device *devices, + pi_uint32 *num_devices) { + cl_int result = clGetDeviceIDs( + cast(platform), cast(device_type), + cast(num_entries), cast(devices), + cast(num_devices)); // Absorb the CL_DEVICE_NOT_FOUND and just return 0 in num_devices if (result == CL_DEVICE_NOT_FOUND) { - assertion(num_devices != 0); + assert(num_devices != 0); *num_devices = 0; result = PI_SUCCESS; } return cast(result); } -pi_result OCL(piextDeviceSelectBinary)(pi_device device, - pi_device_binary *images, - pi_uint32 num_images, - pi_device_binary *selected_image) { +pi_result OCL(piextDeviceSelectBinary)( + pi_device device, // TODO: does this need to be context? + pi_device_binary *images, pi_uint32 num_images, + pi_device_binary *selected_image) { // TODO: this is a bare-bones implementation for choosing a device image // that would be compatible with the targeted device. An AOT-compiled @@ -70,7 +77,7 @@ pi_result OCL(piextDeviceSelectBinary)(pi_device device, // The implementation makes no effort to differentiate between multiple images // for the given device, and simply picks the first one compatible // Real implementaion will use the same mechanism OpenCL ICD dispatcher - // uses. Somthing like: + // uses. Something like: // PI_VALIDATE_HANDLE_RETURN_HANDLE(ctx, PI_INVALID_CONTEXT); // return context->dispatch->piextDeviceSelectIR( // ctx, images, num_images, selected_image); @@ -131,35 +138,26 @@ pi_result OCL(piextDeviceSelectBinary)(pi_device device, pi_result OCL(piQueueCreate)(pi_context context, pi_device device, pi_queue_properties properties, pi_queue *queue) { - PI_ASSERT(queue, "piQueueCreate failed, queue argument is null"); + assert(queue && "piQueueCreate failed, queue argument is null"); cl_platform_id curPlatform; - cl_int ret_err = clGetDeviceInfo(cast(device), - CL_DEVICE_PLATFORM, sizeof(cl_platform_id), - &curPlatform, NULL); + cl_int ret_err = + clGetDeviceInfo(cast(device), CL_DEVICE_PLATFORM, + sizeof(cl_platform_id), &curPlatform, nullptr); - if (ret_err != CL_SUCCESS) { - *queue = nullptr; - return cast(ret_err); - } + CHECK_ERR_SET_NULL_RET(ret_err, queue, ret_err); size_t platVerSize; - ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, 0, NULL, + ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, 0, nullptr, &platVerSize); - if (ret_err != CL_SUCCESS) { - *queue = nullptr; - return cast(ret_err); - } + CHECK_ERR_SET_NULL_RET(ret_err, queue, ret_err); std::string platVer(platVerSize, '\0'); ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, platVerSize, - &platVer.front(), NULL); + &platVer.front(), nullptr); - if (ret_err != CL_SUCCESS) { - *queue = nullptr; - return cast(ret_err); - } + CHECK_ERR_SET_NULL_RET(ret_err, queue, ret_err); if (platVer.find("OpenCL 1.0") != std::string::npos || platVer.find("OpenCL 1.1") != std::string::npos || @@ -171,12 +169,10 @@ pi_result OCL(piQueueCreate)(pi_context context, pi_device device, } cl_queue_properties CreationFlagProperties[] = { - CL_QUEUE_PROPERTIES, cast(properties), 0 - }; + CL_QUEUE_PROPERTIES, cast(properties), 0}; *queue = cast(clCreateCommandQueueWithProperties( - cast(context), - cast(device), - CreationFlagProperties, &ret_err)); + cast(context), cast(device), + CreationFlagProperties, &ret_err)); return cast(ret_err); } @@ -186,42 +182,36 @@ pi_result OCL(piProgramCreate)(pi_context context, const void *il, size_t deviceCount; cl_int ret_err = clGetContextInfo(cast(context), - CL_CONTEXT_DEVICES, 0, NULL, &deviceCount); + CL_CONTEXT_DEVICES, 0, nullptr, &deviceCount); std::vector devicesInCtx(deviceCount); - ret_err = clGetContextInfo(cast(context), CL_CONTEXT_DEVICES, - deviceCount * sizeof(cl_device_id), - devicesInCtx.data(), NULL); - if (ret_err != CL_SUCCESS || deviceCount < 1) { if (res_program != nullptr) *res_program = nullptr; return cast(CL_INVALID_CONTEXT); } + ret_err = clGetContextInfo(cast(context), CL_CONTEXT_DEVICES, + deviceCount * sizeof(cl_device_id), + devicesInCtx.data(), nullptr); + + CHECK_ERR_SET_NULL_RET(ret_err, res_program, CL_INVALID_CONTEXT); + cl_platform_id curPlatform; ret_err = clGetDeviceInfo(devicesInCtx[0], CL_DEVICE_PLATFORM, - sizeof(cl_platform_id), &curPlatform, NULL); + sizeof(cl_platform_id), &curPlatform, nullptr); - if (ret_err != CL_SUCCESS) { - if (res_program != nullptr) - *res_program = nullptr; - return cast(CL_INVALID_CONTEXT); - } + CHECK_ERR_SET_NULL_RET(ret_err, res_program, CL_INVALID_CONTEXT); size_t devVerSize; ret_err = - clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, 0, NULL, &devVerSize); + clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, 0, nullptr, &devVerSize); std::string devVer(devVerSize, '\0'); ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_VERSION, devVerSize, - &devVer.front(), NULL); + &devVer.front(), nullptr); - if (ret_err != CL_SUCCESS) { - if (res_program != nullptr) - *res_program = nullptr; - return cast(CL_INVALID_CONTEXT); - } + CHECK_ERR_SET_NULL_RET(ret_err, res_program, CL_INVALID_CONTEXT); pi_result err = PI_SUCCESS; if (devVer.find("OpenCL 1.0") == std::string::npos && @@ -235,11 +225,11 @@ pi_result OCL(piProgramCreate)(pi_context context, const void *il, } size_t extSize; - ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_EXTENSIONS, 0, NULL, - &extSize); + ret_err = + clGetPlatformInfo(curPlatform, CL_PLATFORM_EXTENSIONS, 0, nullptr, &extSize); std::string extStr(extSize, '\0'); - ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_EXTENSIONS, - extSize, &extStr.front(), NULL); + ret_err = clGetPlatformInfo(curPlatform, CL_PLATFORM_EXTENSIONS, extSize, + &extStr.front(), nullptr); if (ret_err != CL_SUCCESS || extStr.find("cl_khr_il_program") == std::string::npos) { @@ -254,10 +244,12 @@ pi_result OCL(piProgramCreate)(pi_context context, const void *il, reinterpret_cast(clGetExtensionFunctionAddressForPlatform( curPlatform, "clCreateProgramWithILKHR")); - assertion(funcPtr != nullptr); + assert(funcPtr != nullptr); if (res_program != nullptr) - *res_program = cast(funcPtr( - cast(context), il, length, cast(&err))); + *res_program = cast( + funcPtr(cast(context), il, length, cast(&err))); + else + err = PI_INVALID_VALUE; return err; } @@ -277,18 +269,19 @@ pi_result OCL(piSamplerCreate)(pi_context context, if (sampler_properties[i] == PI_SAMPLER_INFO_NORMALIZED_COORDS) { normalizedCoords = static_cast(sampler_properties[++i]); } else if (sampler_properties[i] == PI_SAMPLER_INFO_ADDRESSING_MODE) { - addressingMode = static_cast(sampler_properties[++i]); + addressingMode = + static_cast(sampler_properties[++i]); } else if (sampler_properties[i] == PI_SAMPLER_INFO_FILTER_MODE) { filterMode = static_cast(sampler_properties[++i]); } else { - PI_ASSERT(false, "Cannot recognize sampler property"); + assert(false && "Cannot recognize sampler property"); } } // Always call OpenCL 1.0 API - *result_sampler = cast(clCreateSampler(cast(context), - normalizedCoords, addressingMode, filterMode, - cast(&error_code))); + *result_sampler = cast( + clCreateSampler(cast(context), normalizedCoords, + addressingMode, filterMode, cast(&error_code))); return error_code; } @@ -297,21 +290,26 @@ pi_result OCL(piextGetDeviceFunctionPointer)(pi_device device, const char *func_name, pi_uint64 *function_pointer_ret) { pi_platform platform; - PI_CALL(piDeviceGetInfo(device, PI_DEVICE_INFO_PLATFORM, sizeof(platform), - &platform, nullptr)); + cl_int ret_err = + clGetDeviceInfo(cast(device), PI_DEVICE_INFO_PLATFORM, + sizeof(platform), &platform, nullptr); + + if (ret_err != CL_SUCCESS) { + return cast(ret_err); + } + using FuncT = cl_int(CL_API_CALL *)(cl_device_id, cl_program, const char *, cl_ulong *); // TODO: add check that device supports corresponding extension FuncT func_ptr = reinterpret_cast(clGetExtensionFunctionAddressForPlatform( - cast(platform), - "clGetDeviceFunctionPointerINTEL")); + cast(platform), "clGetDeviceFunctionPointerINTEL")); // TODO: once we have check that device supports corresponding extension, // we can insert an assertion that func_ptr is not nullptr. For now, let's // just return an error if failed to query such function - // PI_ASSERT( - // func_ptr != nullptr, + // assert( + // func_ptr != nullptr && // "Failed to get address of clGetDeviceFunctionPointerINTEL function"); if (!func_ptr) { @@ -320,100 +318,96 @@ pi_result OCL(piextGetDeviceFunctionPointer)(pi_device device, return PI_INVALID_DEVICE; } - return PI_CALL_RESULT(func_ptr(cast(device), - cast(program), func_name, - function_pointer_ret)); + return cast(func_ptr(cast(device), + cast(program), func_name, + function_pointer_ret)); } +// TODO: Remove the 'OclPtr' extension used with the PI_APIs. // Forward calls to OpenCL RT. -#define _PI_CL(pi_api, ocl_api) \ -decltype(::pi_api) * pi_api##OclPtr = \ - detail::pi::cast(&ocl_api); +#define _PI_CL(pi_api, ocl_api) \ + decltype(::pi_api) *pi_api##OclPtr = cast(&ocl_api); // Platform -_PI_CL(piPlatformsGet, OCL(piPlatformsGet)) -_PI_CL(piPlatformGetInfo, clGetPlatformInfo) +_PI_CL(piPlatformsGet, OCL(piPlatformsGet)) +_PI_CL(piPlatformGetInfo, clGetPlatformInfo) // Device -_PI_CL(piDevicesGet, OCL(piDevicesGet)) -_PI_CL(piDeviceGetInfo, clGetDeviceInfo) -_PI_CL(piDevicePartition, clCreateSubDevices) -_PI_CL(piDeviceRetain, clRetainDevice) -_PI_CL(piDeviceRelease, clReleaseDevice) +_PI_CL(piDevicesGet, OCL(piDevicesGet)) +_PI_CL(piDeviceGetInfo, clGetDeviceInfo) +_PI_CL(piDevicePartition, clCreateSubDevices) +_PI_CL(piDeviceRetain, clRetainDevice) +_PI_CL(piDeviceRelease, clReleaseDevice) _PI_CL(piextDeviceSelectBinary, OCL(piextDeviceSelectBinary)) _PI_CL(piextGetDeviceFunctionPointer, OCL(piextGetDeviceFunctionPointer)) // Context -_PI_CL(piContextCreate, clCreateContext) -_PI_CL(piContextGetInfo, clGetContextInfo) -_PI_CL(piContextRetain, clRetainContext) -_PI_CL(piContextRelease, clReleaseContext) +_PI_CL(piContextCreate, clCreateContext) +_PI_CL(piContextGetInfo, clGetContextInfo) +_PI_CL(piContextRetain, clRetainContext) +_PI_CL(piContextRelease, clReleaseContext) // Queue -_PI_CL(piQueueCreate, OCL(piQueueCreate)) -_PI_CL(piQueueGetInfo, clGetCommandQueueInfo) -_PI_CL(piQueueFinish, clFinish) -_PI_CL(piQueueRetain, clRetainCommandQueue) -_PI_CL(piQueueRelease, clReleaseCommandQueue) +_PI_CL(piQueueCreate, OCL(piQueueCreate)) +_PI_CL(piQueueGetInfo, clGetCommandQueueInfo) +_PI_CL(piQueueFinish, clFinish) +_PI_CL(piQueueRetain, clRetainCommandQueue) +_PI_CL(piQueueRelease, clReleaseCommandQueue) // Memory -_PI_CL(piMemBufferCreate, clCreateBuffer) -_PI_CL(piMemImageCreate, clCreateImage) -_PI_CL(piMemGetInfo, clGetMemObjectInfo) -_PI_CL(piMemImageGetInfo, clGetImageInfo) -_PI_CL(piMemRetain, clRetainMemObject) -_PI_CL(piMemRelease, clReleaseMemObject) +_PI_CL(piMemBufferCreate, clCreateBuffer) +_PI_CL(piMemImageCreate, clCreateImage) +_PI_CL(piMemGetInfo, clGetMemObjectInfo) +_PI_CL(piMemImageGetInfo, clGetImageInfo) +_PI_CL(piMemRetain, clRetainMemObject) +_PI_CL(piMemRelease, clReleaseMemObject) _PI_CL(piMemBufferPartition, clCreateSubBuffer) // Program -_PI_CL(piProgramCreate, OCL(piProgramCreate)) +_PI_CL(piProgramCreate, OCL(piProgramCreate)) _PI_CL(piclProgramCreateWithSource, clCreateProgramWithSource) _PI_CL(piclProgramCreateWithBinary, clCreateProgramWithBinary) -_PI_CL(piProgramGetInfo, clGetProgramInfo) -_PI_CL(piProgramCompile, clCompileProgram) -_PI_CL(piProgramBuild, clBuildProgram) -_PI_CL(piProgramLink, clLinkProgram) -_PI_CL(piProgramGetBuildInfo, clGetProgramBuildInfo) -_PI_CL(piProgramRetain, clRetainProgram) -_PI_CL(piProgramRelease, clReleaseProgram) +_PI_CL(piProgramGetInfo, clGetProgramInfo) +_PI_CL(piProgramCompile, clCompileProgram) +_PI_CL(piProgramBuild, clBuildProgram) +_PI_CL(piProgramLink, clLinkProgram) +_PI_CL(piProgramGetBuildInfo, clGetProgramBuildInfo) +_PI_CL(piProgramRetain, clRetainProgram) +_PI_CL(piProgramRelease, clReleaseProgram) // Kernel -_PI_CL(piKernelCreate, clCreateKernel) -_PI_CL(piKernelSetArg, clSetKernelArg) -_PI_CL(piKernelGetInfo, clGetKernelInfo) -_PI_CL(piKernelGetGroupInfo, clGetKernelWorkGroupInfo) +_PI_CL(piKernelCreate, clCreateKernel) +_PI_CL(piKernelSetArg, clSetKernelArg) +_PI_CL(piKernelGetInfo, clGetKernelInfo) +_PI_CL(piKernelGetGroupInfo, clGetKernelWorkGroupInfo) _PI_CL(piKernelGetSubGroupInfo, clGetKernelSubGroupInfo) -_PI_CL(piKernelRetain, clRetainKernel) -_PI_CL(piKernelRelease, clReleaseKernel) +_PI_CL(piKernelRetain, clRetainKernel) +_PI_CL(piKernelRelease, clReleaseKernel) // Event -_PI_CL(piEventCreate, clCreateUserEvent) -_PI_CL(piEventGetInfo, clGetEventInfo) +_PI_CL(piEventCreate, clCreateUserEvent) +_PI_CL(piEventGetInfo, clGetEventInfo) _PI_CL(piEventGetProfilingInfo, clGetEventProfilingInfo) -_PI_CL(piEventsWait, clWaitForEvents) -_PI_CL(piEventSetCallback, clSetEventCallback) -_PI_CL(piEventSetStatus, clSetUserEventStatus) -_PI_CL(piEventRetain, clRetainEvent) -_PI_CL(piEventRelease, clReleaseEvent) +_PI_CL(piEventsWait, clWaitForEvents) +_PI_CL(piEventSetCallback, clSetEventCallback) +_PI_CL(piEventSetStatus, clSetUserEventStatus) +_PI_CL(piEventRetain, clRetainEvent) +_PI_CL(piEventRelease, clReleaseEvent) // Sampler -_PI_CL(piSamplerCreate, OCL(piSamplerCreate)) -_PI_CL(piSamplerGetInfo, clGetSamplerInfo) -_PI_CL(piSamplerRetain, clRetainSampler) -_PI_CL(piSamplerRelease, clReleaseSampler) +_PI_CL(piSamplerCreate, OCL(piSamplerCreate)) +_PI_CL(piSamplerGetInfo, clGetSamplerInfo) +_PI_CL(piSamplerRetain, clRetainSampler) +_PI_CL(piSamplerRelease, clReleaseSampler) // Queue commands -_PI_CL(piEnqueueKernelLaunch, clEnqueueNDRangeKernel) -_PI_CL(piEnqueueNativeKernel, clEnqueueNativeKernel) -_PI_CL(piEnqueueEventsWait, clEnqueueMarkerWithWaitList) -_PI_CL(piEnqueueMemBufferRead, clEnqueueReadBuffer) -_PI_CL(piEnqueueMemBufferReadRect, clEnqueueReadBufferRect) -_PI_CL(piEnqueueMemBufferWrite, clEnqueueWriteBuffer) -_PI_CL(piEnqueueMemBufferWriteRect, clEnqueueWriteBufferRect) -_PI_CL(piEnqueueMemBufferCopy, clEnqueueCopyBuffer) -_PI_CL(piEnqueueMemBufferCopyRect, clEnqueueCopyBufferRect) -_PI_CL(piEnqueueMemBufferFill, clEnqueueFillBuffer) -_PI_CL(piEnqueueMemImageRead, clEnqueueReadImage) -_PI_CL(piEnqueueMemImageWrite, clEnqueueWriteImage) -_PI_CL(piEnqueueMemImageCopy, clEnqueueCopyImage) -_PI_CL(piEnqueueMemImageFill, clEnqueueFillImage) -_PI_CL(piEnqueueMemBufferMap, clEnqueueMapBuffer) -_PI_CL(piEnqueueMemUnmap, clEnqueueUnmapMemObject) +_PI_CL(piEnqueueKernelLaunch, clEnqueueNDRangeKernel) +_PI_CL(piEnqueueNativeKernel, clEnqueueNativeKernel) +_PI_CL(piEnqueueEventsWait, clEnqueueMarkerWithWaitList) +_PI_CL(piEnqueueMemBufferRead, clEnqueueReadBuffer) +_PI_CL(piEnqueueMemBufferReadRect, clEnqueueReadBufferRect) +_PI_CL(piEnqueueMemBufferWrite, clEnqueueWriteBuffer) +_PI_CL(piEnqueueMemBufferWriteRect, clEnqueueWriteBufferRect) +_PI_CL(piEnqueueMemBufferCopy, clEnqueueCopyBuffer) +_PI_CL(piEnqueueMemBufferCopyRect, clEnqueueCopyBufferRect) +_PI_CL(piEnqueueMemBufferFill, clEnqueueFillBuffer) +_PI_CL(piEnqueueMemImageRead, clEnqueueReadImage) +_PI_CL(piEnqueueMemImageWrite, clEnqueueWriteImage) +_PI_CL(piEnqueueMemImageCopy, clEnqueueCopyImage) +_PI_CL(piEnqueueMemImageFill, clEnqueueFillImage) +_PI_CL(piEnqueueMemBufferMap, clEnqueueMapBuffer) +_PI_CL(piEnqueueMemUnmap, clEnqueueUnmapMemObject) #undef _PI_CL - -} // namespace pi -} // namespace detail -} // namespace sycl -} // namespace cl +} diff --git a/sycl/source/CMakeLists.txt b/sycl/source/CMakeLists.txt index 4f61faa82e34f..574b7a38ba06d 100644 --- a/sycl/source/CMakeLists.txt +++ b/sycl/source/CMakeLists.txt @@ -8,6 +8,7 @@ function(add_sycl_rt_library LIB_NAME) add_library(${LIB_NAME} SHARED ${ARGN}) + #To-Do: Remove dependency on icd loader and opencl headers. add_dependencies(${LIB_NAME} ocl-icd ocl-headers @@ -23,30 +24,11 @@ function(add_sycl_rt_library LIB_NAME) target_link_libraries(${LIB_NAME} PRIVATE OpenCL::Headers PRIVATE ${OpenCL_LIBRARIES} + PRIVATE ${CMAKE_DL_LIBS} ) - if (SYCL_USE_LIBCXX) - if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR - (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) - target_compile_options(${LIB_NAME} PRIVATE -nostdinc++) - if ((NOT (DEFINED SYCL_LIBCXX_INCLUDE_PATH)) OR (NOT (DEFINED SYCL_LIBCXX_LIBRARY_PATH))) - message(FATAL_ERROR "When building with libc++ SYCL_LIBCXX_INCLUDE_PATHS and" - "SYCL_LIBCXX_LIBRARY_PATH should be set") - endif() - target_include_directories(${LIB_NAME} PRIVATE "${SYCL_LIBCXX_INCLUDE_PATH}") - target_link_libraries(${LIB_NAME} PRIVATE "-L${SYCL_LIBCXX_LIBRARY_PATH}" -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc) - else() - message(FATAL_ERROR "Build with libc++ is not yet supported for this compiler") - endif() - else() -# Workaround for bug in GCC version 5 and higher. -# More information https://bugs.launchpad.net/ubuntu/+source/gcc-5/+bug/1568899 - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND - CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0) - target_link_libraries(${LIB_NAME} PRIVATE gcc_s gcc) - endif() + add_common_options(${LIB_NAME}) - endif() endfunction(add_sycl_rt_library) set(SYCL_SOURCES @@ -57,7 +39,6 @@ set(SYCL_SOURCES "detail/builtins_math.cpp" "detail/builtins_relational.cpp" "detail/pi.cpp" - "detail/pi_opencl.cpp" "detail/common.cpp" "detail/context_impl.cpp" "detail/device_impl.cpp" @@ -101,6 +82,8 @@ set(SYCL_SOURCES "sampler.cpp" "stream.cpp" "spirv_ops.cpp" + "$<$:detail/windows_pi.cpp>" + "$<$:detail/linux_pi.cpp>" ) add_sycl_rt_library(sycl ${SYCL_SOURCES}) diff --git a/sycl/source/detail/linux_pi.cpp b/sycl/source/detail/linux_pi.cpp new file mode 100644 index 0000000000000..f8efe09f8f762 --- /dev/null +++ b/sycl/source/detail/linux_pi.cpp @@ -0,0 +1,12 @@ +#include +#include + +void *loadOsLibrary(const std::string &PluginPath) { + // TODO: Check if the option RTLD_NOW is correct. Explore using + // RTLD_DEEPBIND option when there are multiple plugins. + return dlopen(PluginPath.c_str(), RTLD_NOW); +} + +void *getOsLibraryFuncAddress(void *Library, const std::string &FunctionName) { + return dlsym(Library, FunctionName.c_str()); +} diff --git a/sycl/source/detail/pi.cpp b/sycl/source/detail/pi.cpp index 0ad31763b9846..78fa1afacc5ff 100644 --- a/sycl/source/detail/pi.cpp +++ b/sycl/source/detail/pi.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace cl { namespace sycl { @@ -37,22 +38,61 @@ std::string platformInfoToString(pi_platform_info info) { // Check for manually selected BE at run-time. bool useBackend(Backend TheBackend) { static const char *GetEnv = std::getenv("SYCL_BE"); + // Current default backend as SYCL_BE_PI_OPENCL + // Valid values of GetEnv are "PI_OPENCL" and "PI_OTHER" + std::string StringGetEnv = (GetEnv ? GetEnv : "PI_OPENCL"); static const Backend Use = - std::map{ - { "PI_OPENCL", SYCL_BE_PI_OPENCL }, - { "PI_OTHER", SYCL_BE_PI_OTHER } - // Any other value would yield PI_OPENCL (current default) - }[ GetEnv ? GetEnv : "PI_OPENCL"]; + (StringGetEnv == "PI_OTHER" ? SYCL_BE_PI_OTHER : SYCL_BE_PI_OPENCL); return TheBackend == Use; } // Definitions of the PI dispatch entries, they will be initialized // at their first use with piInitialize. -#define _PI_API(api) decltype(::api) * api = nullptr; +#define _PI_API(api) decltype(::api) *api = nullptr; #include -// TODO: implement real plugins (ICD-like?) -// For now this has the effect of redirecting to built-in PI OpenCL plugin. +// Find the plugin at the appropriate location and return the location. +// TODO: Change the function appropriately when there are multiple plugins. +std::string findPlugin() { + // TODO: Based on final design discussions, change the location where the + // plugin must be searched; how to identify the plugins etc. Currently the + // search is done for libpi_opencl.so/pi_opencl.dll file in LD_LIBRARY_PATH + // env only. + return PLUGIN_NAME; +} + +// Load the Plugin by calling the OS dependent library loading call. +// Return the handle to the Library. +void *loadPlugin(const std::string &PluginPath) { + return loadOsLibrary(PluginPath); +} + +// Binds all the PI Interface APIs to Plugin Library Function Addresses. +// TODO: Remove the 'OclPtr' extension to PI_API. +// TODO: Change the functionality such that a single getOsLibraryFuncAddress +// call is done to get all Interface API mapping. The plugin interface also +// needs to setup infrastructure to route PI_CALLs to the appropriate plugins. +// Currently, we bind to a singe plugin. +bool bindPlugin(void *Library) { +#define STRINGIZE(x) #x + +#define _PI_API(api) \ + decltype(&api) api##_ptr = ((decltype(&api))( \ + getOsLibraryFuncAddress(Library, STRINGIZE(api##OclPtr)))); \ + if (!api##_ptr) \ + return false; \ + api = *api##_ptr; +#include + +#undef STRINGIZE +#undef _PI_API + return true; +} + +// Load the plugin based on SYCL_BE. +// TODO: Currently only accepting OpenCL plugins. Edit it to identify and load +// other kinds of plugins, do the required changes in the findPlugin, loadPlugin +// and bindPlugin functions. void initialize() { static bool Initialized = false; if (Initialized) { @@ -61,10 +101,22 @@ void initialize() { if (!useBackend(SYCL_BE_PI_OPENCL)) { die("Unknown SYCL_BE"); } - #define _PI_API(api) \ - extern decltype(::api) * api##OclPtr; \ - api = api##OclPtr; - #include + + std::string PluginPath = findPlugin(); + if (PluginPath.empty()) + die("Plugin Not Found."); + + void *Library = loadPlugin(PluginPath); + if (!Library) { + std::string Message = + "Check if plugin is present. Failed to load plugin: " + PluginPath; + die(Message.c_str()); + } + + if (!bindPlugin(Library)) { + std::string Message = "Failed to bind PI APIs to the plugin: " + PluginPath; + die(Message.c_str()); + } Initialized = true; } @@ -102,8 +154,7 @@ RT::PiResult PiCall::get(RT::PiResult Result) { m_Result = Result; return Result; } -template -void PiCall::check(RT::PiResult Result) { +template void PiCall::check(RT::PiResult Result) { m_Result = Result; // TODO: remove dependency on CHECK_OCL_CODE_THROW. CHECK_OCL_CODE_THROW(Result, Exception); diff --git a/sycl/source/detail/windows_pi.cpp b/sycl/source/detail/windows_pi.cpp new file mode 100644 index 0000000000000..90ea0812c051b --- /dev/null +++ b/sycl/source/detail/windows_pi.cpp @@ -0,0 +1,11 @@ +#include +#include +#include + +void *loadOsLibrary(const std::string &PluginPath) { + return (void *)LoadLibraryA(PluginPath.c_str()); +} + +void *getOsLibraryFuncAddress(void *Library, const std::string &FunctionName) { + return GetProcAddress((HMODULE)Library, FunctionName.c_str()); +}