| 1 | //===-- Dynamically loaded offload API ------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Dynamically loads the API provided by the LLVMOffload library. We need to do |
| 10 | // this dynamically because this tool is used before it is actually built and |
| 11 | // should be provided even when the user did not specify the offload runtime. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #ifndef LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H |
| 16 | #define LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H |
| 17 | |
| 18 | #include "llvm/Support/DynamicLibrary.h" |
| 19 | #include "llvm/Support/Error.h" |
| 20 | |
| 21 | typedef enum ol_alloc_type_t { |
| 22 | OL_ALLOC_TYPE_HOST = 0, |
| 23 | OL_ALLOC_TYPE_DEVICE = 1, |
| 24 | OL_ALLOC_TYPE_FORCE_UINT32 = 0x7fffffff |
| 25 | } ol_alloc_type_t; |
| 26 | |
| 27 | typedef enum ol_device_info_t { |
| 28 | OL_DEVICE_INFO_TYPE = 0, |
| 29 | OL_DEVICE_INFO_PLATFORM = 1, |
| 30 | OL_DEVICE_INFO_FORCE_UINT32 = 0x7fffffff |
| 31 | } ol_device_info_t; |
| 32 | |
| 33 | typedef enum ol_platform_info_t { |
| 34 | OL_PLATFORM_INFO_NAME = 0, |
| 35 | OL_PLATFORM_INFO_BACKEND = 3, |
| 36 | OL_PLATFORM_INFO_FORCE_UINT32 = 0x7fffffff |
| 37 | } ol_platform_info_t; |
| 38 | |
| 39 | typedef enum ol_symbol_kind_t { |
| 40 | OL_SYMBOL_KIND_KERNEL = 0, |
| 41 | OL_SYMBOL_KIND_GLOBAL_VARIABLE = 1, |
| 42 | OL_SYMBOL_KIND_FORCE_UINT32 = 0x7fffffff |
| 43 | } ol_symbol_kind_t; |
| 44 | |
| 45 | typedef enum ol_errc_t { |
| 46 | OL_ERRC_SUCCESS = 0, |
| 47 | OL_ERRC_FORCE_UINT32 = 0x7fffffff |
| 48 | } ol_errc_t; |
| 49 | |
| 50 | typedef struct ol_error_struct_t { |
| 51 | ol_errc_t Code; |
| 52 | const char *Details; |
| 53 | } ol_error_struct_t; |
| 54 | |
| 55 | typedef struct ol_dimensions_t { |
| 56 | uint32_t x; |
| 57 | uint32_t y; |
| 58 | uint32_t z; |
| 59 | } ol_dimensions_t; |
| 60 | |
| 61 | typedef struct ol_kernel_launch_size_args_t { |
| 62 | size_t Dimensions; |
| 63 | struct ol_dimensions_t NumGroups; |
| 64 | struct ol_dimensions_t GroupSize; |
| 65 | size_t DynSharedMemory; |
| 66 | } ol_kernel_launch_size_args_t; |
| 67 | |
| 68 | typedef enum ol_platform_backend_t { |
| 69 | OL_PLATFORM_BACKEND_UNKNOWN = 0, |
| 70 | OL_PLATFORM_BACKEND_CUDA = 1, |
| 71 | OL_PLATFORM_BACKEND_AMDGPU = 2, |
| 72 | OL_PLATFORM_BACKEND_LEVEL_ZERO = 3, |
| 73 | OL_PLATFORM_BACKEND_HOST = 4, |
| 74 | OL_PLATFORM_BACKEND_LAST = 5, |
| 75 | OL_PLATFORM_BACKEND_FORCE_UINT32 = 0x7fffffff |
| 76 | } ol_platform_backend_t; |
| 77 | |
| 78 | typedef enum ol_device_type_t { |
| 79 | OL_DEVICE_TYPE_DEFAULT = 0, |
| 80 | OL_DEVICE_TYPE_ALL = 1, |
| 81 | OL_DEVICE_TYPE_GPU = 2, |
| 82 | OL_DEVICE_TYPE_CPU = 3, |
| 83 | OL_DEVICE_TYPE_HOST = 4, |
| 84 | OL_DEVICE_TYPE_LAST = 5, |
| 85 | OL_DEVICE_TYPE_FORCE_UINT32 = 0x7fffffff |
| 86 | } ol_device_type_t; |
| 87 | |
| 88 | typedef struct ol_init_args_t { |
| 89 | size_t Size; |
| 90 | uint32_t NumPlatforms; |
| 91 | const ol_platform_backend_t *Platforms; |
| 92 | } ol_init_args_t; |
| 93 | |
| 94 | #define OL_INIT_ARGS_INIT {sizeof(ol_init_args_t), 0, NULL} |
| 95 | |
| 96 | typedef struct ol_device_impl_t *ol_device_handle_t; |
| 97 | typedef struct ol_platform_impl_t *ol_platform_handle_t; |
| 98 | typedef struct ol_program_impl_t *ol_program_handle_t; |
| 99 | typedef struct ol_queue_impl_t *ol_queue_handle_t; |
| 100 | typedef struct ol_symbol_impl_t *ol_symbol_handle_t; |
| 101 | typedef const struct ol_error_struct_t *ol_result_t; |
| 102 | |
| 103 | typedef bool (*ol_device_iterate_cb_t)(ol_device_handle_t Device, |
| 104 | void *UserData); |
| 105 | |
| 106 | ol_result_t (*olInit)(const ol_init_args_t *); |
| 107 | ol_result_t (*olShutDown)(); |
| 108 | |
| 109 | ol_result_t (*olIterateDevices)(ol_device_iterate_cb_t Callback, |
| 110 | void *UserData); |
| 111 | |
| 112 | ol_result_t (*olIsValidBinary)(ol_device_handle_t Device, const void *ProgData, |
| 113 | size_t ProgDataSize, bool *Valid); |
| 114 | |
| 115 | ol_result_t (*olCreateProgram)(ol_device_handle_t Device, const void *ProgData, |
| 116 | size_t ProgDataSize, |
| 117 | ol_program_handle_t *Program); |
| 118 | |
| 119 | ol_result_t (*olDestroyProgram)(ol_program_handle_t Program); |
| 120 | |
| 121 | ol_result_t (*olGetSymbol)(ol_program_handle_t Program, const char *Name, |
| 122 | ol_symbol_kind_t Kind, ol_symbol_handle_t *Symbol); |
| 123 | |
| 124 | ol_result_t (*olLaunchKernel)( |
| 125 | ol_queue_handle_t Queue, ol_device_handle_t Device, |
| 126 | ol_symbol_handle_t Kernel, const void *ArgumentsData, size_t ArgumentsSize, |
| 127 | const ol_kernel_launch_size_args_t *LaunchSizeArgs); |
| 128 | |
| 129 | ol_result_t (*olCreateQueue)(ol_device_handle_t Device, |
| 130 | ol_queue_handle_t *Queue); |
| 131 | |
| 132 | ol_result_t (*olDestroyQueue)(ol_queue_handle_t Queue); |
| 133 | |
| 134 | ol_result_t (*olSyncQueue)(ol_queue_handle_t Queue); |
| 135 | |
| 136 | ol_result_t (*olMemAlloc)(ol_device_handle_t Device, ol_alloc_type_t Type, |
| 137 | size_t Size, void **AllocationOut); |
| 138 | |
| 139 | ol_result_t (*olMemFree)(void *Address); |
| 140 | |
| 141 | ol_result_t (*olMemcpy)(ol_queue_handle_t Queue, void *DstPtr, |
| 142 | ol_device_handle_t DstDevice, const void *SrcPtr, |
| 143 | ol_device_handle_t SrcDevice, size_t Size); |
| 144 | |
| 145 | ol_result_t (*olGetDeviceInfo)(ol_device_handle_t Device, |
| 146 | ol_device_info_t PropName, size_t PropSize, |
| 147 | void *PropValue); |
| 148 | |
| 149 | ol_result_t (*olGetPlatformInfo)(ol_platform_handle_t Platform, |
| 150 | ol_platform_info_t PropName, size_t PropSize, |
| 151 | void *PropValue); |
| 152 | |
| 153 | llvm::Error loadLLVMOffload() { |
| 154 | constexpr const char *OffloadLibrary = "libLLVMOffload.so" ; |
| 155 | |
| 156 | std::string ErrMsg; |
| 157 | auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>( |
| 158 | args: llvm::sys::DynamicLibrary::getPermanentLibrary(filename: OffloadLibrary, errMsg: &ErrMsg)); |
| 159 | |
| 160 | if (!DynlibHandle->isValid()) |
| 161 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
| 162 | Fmt: "Failed to dlopen %s: %s" , Vals: OffloadLibrary, |
| 163 | Vals: ErrMsg.c_str()); |
| 164 | |
| 165 | #define DYNAMIC_INIT(SYM) \ |
| 166 | do { \ |
| 167 | void *Ptr = DynlibHandle->getAddressOfSymbol(#SYM); \ |
| 168 | if (!Ptr) \ |
| 169 | return llvm::createStringError( \ |
| 170 | llvm::inconvertibleErrorCode(), "Missing symbol '%s' in %s", \ |
| 171 | reinterpret_cast<const char *>(#SYM), OffloadLibrary); \ |
| 172 | SYM = reinterpret_cast<decltype(SYM)>(Ptr); \ |
| 173 | } while (0) |
| 174 | |
| 175 | DYNAMIC_INIT(olInit); |
| 176 | DYNAMIC_INIT(olShutDown); |
| 177 | DYNAMIC_INIT(olIterateDevices); |
| 178 | DYNAMIC_INIT(olIsValidBinary); |
| 179 | DYNAMIC_INIT(olCreateProgram); |
| 180 | DYNAMIC_INIT(olDestroyProgram); |
| 181 | DYNAMIC_INIT(olGetSymbol); |
| 182 | DYNAMIC_INIT(olLaunchKernel); |
| 183 | DYNAMIC_INIT(olCreateQueue); |
| 184 | DYNAMIC_INIT(olDestroyQueue); |
| 185 | DYNAMIC_INIT(olSyncQueue); |
| 186 | DYNAMIC_INIT(olMemAlloc); |
| 187 | DYNAMIC_INIT(olMemFree); |
| 188 | DYNAMIC_INIT(olMemcpy); |
| 189 | DYNAMIC_INIT(olGetDeviceInfo); |
| 190 | DYNAMIC_INIT(olGetPlatformInfo); |
| 191 | #undef DYNAMIC_INIT |
| 192 | |
| 193 | return llvm::Error::success(); |
| 194 | } |
| 195 | |
| 196 | #endif // LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H |
| 197 | |