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
21typedef 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
27typedef 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
33typedef 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
39typedef 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
45typedef enum ol_errc_t {
46 OL_ERRC_SUCCESS = 0,
47 OL_ERRC_FORCE_UINT32 = 0x7fffffff
48} ol_errc_t;
49
50typedef struct ol_error_struct_t {
51 ol_errc_t Code;
52 const char *Details;
53} ol_error_struct_t;
54
55typedef struct ol_dimensions_t {
56 uint32_t x;
57 uint32_t y;
58 uint32_t z;
59} ol_dimensions_t;
60
61typedef 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
68typedef enum ol_kernel_launch_prop_type_t {
69 OL_KERNEL_LAUNCH_PROP_TYPE_NONE = 0,
70 OL_KERNEL_LAUNCH_PROP_TYPE_FORCE_UINT32 = 0x7fffffff
71} ol_kernel_launch_prop_type_t;
72
73typedef struct ol_kernel_launch_prop_t {
74 ol_kernel_launch_prop_type_t type;
75 void *data;
76} ol_kernel_launch_prop_t;
77
78typedef enum ol_platform_backend_t {
79 OL_PLATFORM_BACKEND_UNKNOWN = 0,
80 OL_PLATFORM_BACKEND_CUDA = 1,
81 OL_PLATFORM_BACKEND_AMDGPU = 2,
82 OL_PLATFORM_BACKEND_LEVEL_ZERO = 3,
83 OL_PLATFORM_BACKEND_HOST = 4,
84 OL_PLATFORM_BACKEND_LAST = 5,
85 OL_PLATFORM_BACKEND_FORCE_UINT32 = 0x7fffffff
86} ol_platform_backend_t;
87
88typedef enum ol_device_type_t {
89 OL_DEVICE_TYPE_DEFAULT = 0,
90 OL_DEVICE_TYPE_ALL = 1,
91 OL_DEVICE_TYPE_GPU = 2,
92 OL_DEVICE_TYPE_CPU = 3,
93 OL_DEVICE_TYPE_HOST = 4,
94 OL_DEVICE_TYPE_LAST = 5,
95 OL_DEVICE_TYPE_FORCE_UINT32 = 0x7fffffff
96} ol_device_type_t;
97
98typedef struct ol_init_args_t {
99 size_t Size;
100 uint32_t NumPlatforms;
101 const ol_platform_backend_t *Platforms;
102} ol_init_args_t;
103
104#define OL_INIT_ARGS_INIT {sizeof(ol_init_args_t), 0, NULL}
105
106typedef struct ol_device_impl_t *ol_device_handle_t;
107typedef struct ol_platform_impl_t *ol_platform_handle_t;
108typedef struct ol_program_impl_t *ol_program_handle_t;
109typedef struct ol_queue_impl_t *ol_queue_handle_t;
110typedef struct ol_symbol_impl_t *ol_symbol_handle_t;
111typedef const struct ol_error_struct_t *ol_result_t;
112
113typedef bool (*ol_device_iterate_cb_t)(ol_device_handle_t Device,
114 void *UserData);
115
116ol_result_t (*olInit)(const ol_init_args_t *);
117ol_result_t (*olShutDown)();
118
119ol_result_t (*olIterateDevices)(ol_device_iterate_cb_t Callback,
120 void *UserData);
121
122ol_result_t (*olIsValidBinary)(ol_device_handle_t Device, const void *ProgData,
123 size_t ProgDataSize, bool *Valid);
124
125ol_result_t (*olCreateProgram)(ol_device_handle_t Device, const void *ProgData,
126 size_t ProgDataSize,
127 ol_program_handle_t *Program);
128
129ol_result_t (*olDestroyProgram)(ol_program_handle_t Program);
130
131ol_result_t (*olGetSymbol)(ol_program_handle_t Program, const char *Name,
132 ol_symbol_kind_t Kind, ol_symbol_handle_t *Symbol);
133
134ol_result_t (*olLaunchKernel)(
135 ol_queue_handle_t Queue, ol_device_handle_t Device,
136 ol_symbol_handle_t Kernel,
137 const ol_kernel_launch_size_args_t *LaunchSizeArgs,
138 const ol_kernel_launch_prop_t *Properties, size_t NumArgs, void **ArgPtrs,
139 const size_t *ArgSizes);
140
141ol_result_t (*olCreateQueue)(ol_device_handle_t Device,
142 ol_queue_handle_t *Queue);
143
144ol_result_t (*olDestroyQueue)(ol_queue_handle_t Queue);
145
146ol_result_t (*olSyncQueue)(ol_queue_handle_t Queue);
147
148ol_result_t (*olMemAlloc)(ol_device_handle_t Device, ol_alloc_type_t Type,
149 size_t Size, void **AllocationOut);
150
151ol_result_t (*olMemFree)(void *Address);
152
153ol_result_t (*olMemcpy)(ol_queue_handle_t Queue, void *DstPtr,
154 ol_device_handle_t DstDevice, const void *SrcPtr,
155 ol_device_handle_t SrcDevice, size_t Size);
156
157ol_result_t (*olGetDeviceInfo)(ol_device_handle_t Device,
158 ol_device_info_t PropName, size_t PropSize,
159 void *PropValue);
160
161ol_result_t (*olGetPlatformInfo)(ol_platform_handle_t Platform,
162 ol_platform_info_t PropName, size_t PropSize,
163 void *PropValue);
164
165llvm::Error loadLLVMOffload() {
166 constexpr const char *OffloadLibrary = "libLLVMOffload.so";
167
168 std::string ErrMsg;
169 auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
170 args: llvm::sys::DynamicLibrary::getPermanentLibrary(filename: OffloadLibrary, errMsg: &ErrMsg));
171
172 if (!DynlibHandle->isValid())
173 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
174 Fmt: "Failed to dlopen %s: %s", Vals: OffloadLibrary,
175 Vals: ErrMsg.c_str());
176
177#define DYNAMIC_INIT(SYM) \
178 do { \
179 void *Ptr = DynlibHandle->getAddressOfSymbol(#SYM); \
180 if (!Ptr) \
181 return llvm::createStringError( \
182 llvm::inconvertibleErrorCode(), "Missing symbol '%s' in %s", \
183 reinterpret_cast<const char *>(#SYM), OffloadLibrary); \
184 SYM = reinterpret_cast<decltype(SYM)>(Ptr); \
185 } while (0)
186
187 DYNAMIC_INIT(olInit);
188 DYNAMIC_INIT(olShutDown);
189 DYNAMIC_INIT(olIterateDevices);
190 DYNAMIC_INIT(olIsValidBinary);
191 DYNAMIC_INIT(olCreateProgram);
192 DYNAMIC_INIT(olDestroyProgram);
193 DYNAMIC_INIT(olGetSymbol);
194 DYNAMIC_INIT(olLaunchKernel);
195 DYNAMIC_INIT(olCreateQueue);
196 DYNAMIC_INIT(olDestroyQueue);
197 DYNAMIC_INIT(olSyncQueue);
198 DYNAMIC_INIT(olMemAlloc);
199 DYNAMIC_INIT(olMemFree);
200 DYNAMIC_INIT(olMemcpy);
201 DYNAMIC_INIT(olGetDeviceInfo);
202 DYNAMIC_INIT(olGetPlatformInfo);
203#undef DYNAMIC_INIT
204
205 return llvm::Error::success();
206}
207
208#endif // LLVM_TOOLS_LLVM_GPU_LOADER_LLVM_GPU_LOADER_H
209