libgomp updates.
[official-gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
blob0428b79b3e8ccad544312b1c5a0801c31fd48124
1 /* Plugin for offload execution on Intel MIC devices.
3 Copyright (C) 2014 Free Software Foundation, Inc.
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
10 Libgomp is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
15 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
29 /* Host side part of a libgomp plugin. */
31 #include <stdint.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <utility>
36 #include <vector>
37 #include <libgomp_target.h>
38 #include "compiler_if_host.h"
39 #include "main_target_image.h"
41 #define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
42 #define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
44 #ifdef DEBUG
45 #define TRACE(...) \
46 { \
47 fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
48 fprintf (stderr, __VA_ARGS__); \
49 fprintf (stderr, "\n"); \
51 #else
52 #define TRACE { }
53 #endif
56 static VarDesc vd_host2tgt = {
57 { 1, 1 }, /* dst, src */
58 { 1, 0 }, /* in, out */
59 1, /* alloc_if */
60 1, /* free_if */
61 4, /* align */
62 0, /* mic_offset */
63 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
64 is_stack_buf, sink_addr, alloc_disp,
65 is_noncont_src, is_noncont_dst */
66 0, /* offset */
67 0, /* size */
68 1, /* count */
69 0, /* alloc */
70 0, /* into */
71 0 /* ptr */
74 static VarDesc vd_tgt2host = {
75 { 1, 1 }, /* dst, src */
76 { 0, 1 }, /* in, out */
77 1, /* alloc_if */
78 1, /* free_if */
79 4, /* align */
80 0, /* mic_offset */
81 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
82 is_stack_buf, sink_addr, alloc_disp,
83 is_noncont_src, is_noncont_dst */
84 0, /* offset */
85 0, /* size */
86 1, /* count */
87 0, /* alloc */
88 0, /* into */
89 0 /* ptr */
93 /* Total number of shared libraries with offloading to Intel MIC. */
94 static int num_libraries;
96 /* Pointers to the descriptors, containing pointers to host-side tables and to
97 target images. */
98 static std::vector< std::pair<void *, void *> > lib_descrs;
100 /* Thread-safe registration of the main image. */
101 static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
104 /* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
105 required by liboffloadmic. */
106 __attribute__((constructor))
107 static void
108 set_mic_lib_path (void)
110 const char *ld_lib_path = getenv (LD_LIBRARY_PATH_ENV);
111 const char *mic_lib_path = getenv (MIC_LD_LIBRARY_PATH_ENV);
113 if (!ld_lib_path)
114 return;
116 if (!mic_lib_path)
117 setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
118 else
120 size_t len = strlen (mic_lib_path) + strlen (ld_lib_path) + 2;
121 bool use_alloca = len <= 2048;
122 char *mic_lib_path_new = (char *) (use_alloca ? alloca (len)
123 : malloc (len));
124 if (!mic_lib_path_new)
126 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
127 exit (1);
130 sprintf (mic_lib_path_new, "%s:%s", mic_lib_path, ld_lib_path);
131 setenv (MIC_LD_LIBRARY_PATH_ENV, mic_lib_path_new, 1);
133 if (!use_alloca)
134 free (mic_lib_path_new);
138 extern "C" enum offload_target_type
139 GOMP_OFFLOAD_get_type (void)
141 enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
142 TRACE ("(): return %d", res);
143 return res;
146 extern "C" int
147 GOMP_OFFLOAD_get_num_devices (void)
149 int res = _Offload_number_of_devices ();
150 TRACE ("(): return %d", res);
151 return res;
154 /* This should be called from every shared library with offloading. */
155 extern "C" void
156 GOMP_OFFLOAD_register_image (void *host_table, void *target_image)
158 TRACE ("(host_table = %p, target_image = %p)", host_table, target_image);
159 lib_descrs.push_back (std::make_pair (host_table, target_image));
160 num_libraries++;
163 static void
164 offload (const char *file, uint64_t line, int device, const char *name,
165 int num_vars, VarDesc *vars, VarDesc2 *vars2)
167 OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
168 if (ofld)
169 __offload_offload1 (ofld, name, 0, num_vars, vars, vars2, 0, NULL, NULL);
170 else
172 fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
173 exit (1);
177 static void
178 register_main_image ()
180 __offload_register_image (&main_target_image);
183 /* Load offload_target_main on target. */
184 extern "C" void
185 GOMP_OFFLOAD_init_device (int device)
187 TRACE ("");
188 pthread_once (&main_image_is_registered, register_main_image);
189 offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
190 NULL, NULL);
193 static void
194 get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
196 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
197 vd1[0].ptr = &num_funcs;
198 vd1[0].size = sizeof (num_funcs);
199 vd1[1].ptr = &num_vars;
200 vd1[1].size = sizeof (num_vars);
201 VarDesc2 vd1g[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
203 offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
204 vd1, vd1g);
206 int table_size = num_funcs + 2 * num_vars;
207 if (table_size > 0)
209 table = new void * [table_size];
211 VarDesc vd2;
212 vd2 = vd_tgt2host;
213 vd2.ptr = table;
214 vd2.size = table_size * sizeof (void *);
215 VarDesc2 vd2g = { "table", 0 };
217 offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1,
218 &vd2, &vd2g);
222 static void
223 load_lib_and_get_table (int device, int lib_num, mapping_table *&table,
224 int &table_size)
226 struct TargetImage {
227 int64_t size;
228 /* 10 characters is enough for max int value. */
229 char name[sizeof ("lib0000000000.so")];
230 char data[];
231 } __attribute__ ((packed));
233 void ***host_table_descr = (void ***) lib_descrs[lib_num].first;
234 void **host_func_start = host_table_descr[0];
235 void **host_func_end = host_table_descr[1];
236 void **host_var_start = host_table_descr[2];
237 void **host_var_end = host_table_descr[3];
239 void **target_image_descr = (void **) lib_descrs[lib_num].second;
240 void *image_start = target_image_descr[0];
241 void *image_end = target_image_descr[1];
243 TRACE ("() host_table_descr { %p, %p, %p, %p }", host_func_start,
244 host_func_end, host_var_start, host_var_end);
245 TRACE ("() target_image_descr { %p, %p }", image_start, image_end);
247 int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
248 TargetImage *image
249 = (TargetImage *) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
250 + image_size);
251 if (!image)
253 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
254 exit (1);
257 image->size = image_size;
258 sprintf (image->name, "lib%010d.so", lib_num);
259 memcpy (image->data, image_start, image->size);
261 TRACE ("() __offload_register_image %s { %p, %d }",
262 image->name, image_start, image->size);
263 __offload_register_image (image);
265 int tgt_num_funcs = 0;
266 int tgt_num_vars = 0;
267 void **tgt_table = NULL;
268 get_target_table (device, tgt_num_funcs, tgt_num_vars, tgt_table);
269 free (image);
271 /* The func table contains only addresses, the var table contains addresses
272 and corresponding sizes. */
273 int host_num_funcs = host_func_end - host_func_start;
274 int host_num_vars = (host_var_end - host_var_start) / 2;
275 TRACE ("() host_num_funcs = %d, tgt_num_funcs = %d",
276 host_num_funcs, tgt_num_funcs);
277 TRACE ("() host_num_vars = %d, tgt_num_vars = %d",
278 host_num_vars, tgt_num_vars);
279 if (host_num_funcs != tgt_num_funcs)
281 fprintf (stderr, "%s: Can't map target functions\n", __FILE__);
282 exit (1);
284 if (host_num_vars != tgt_num_vars)
286 fprintf (stderr, "%s: Can't map target variables\n", __FILE__);
287 exit (1);
290 table = (mapping_table *) realloc (table, (table_size + host_num_funcs
291 + host_num_vars)
292 * sizeof (mapping_table));
293 if (table == NULL)
295 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
296 exit (1);
299 for (int i = 0; i < host_num_funcs; i++)
301 mapping_table t;
302 t.host_start = (uintptr_t) host_func_start[i];
303 t.host_end = t.host_start + 1;
304 t.tgt_start = (uintptr_t) tgt_table[i];
305 t.tgt_end = t.tgt_start + 1;
307 TRACE ("() lib %d, func %d:\t0x%llx -- 0x%llx",
308 lib_num, i, t.host_start, t.tgt_start);
310 table[table_size++] = t;
313 for (int i = 0; i < host_num_vars * 2; i += 2)
315 mapping_table t;
316 t.host_start = (uintptr_t) host_var_start[i];
317 t.host_end = t.host_start + (uintptr_t) host_var_start[i+1];
318 t.tgt_start = (uintptr_t) tgt_table[tgt_num_funcs+i];
319 t.tgt_end = t.tgt_start + (uintptr_t) tgt_table[tgt_num_funcs+i+1];
321 TRACE ("() lib %d, var %d:\t0x%llx (%d) -- 0x%llx (%d)", lib_num, i/2,
322 t.host_start, t.host_end - t.host_start,
323 t.tgt_start, t.tgt_end - t.tgt_start);
325 table[table_size++] = t;
328 delete [] tgt_table;
331 extern "C" int
332 GOMP_OFFLOAD_get_table (int device, void *result)
334 TRACE ("(num_libraries = %d)", num_libraries);
336 mapping_table *table = NULL;
337 int table_size = 0;
339 for (int i = 0; i < num_libraries; i++)
340 load_lib_and_get_table (device, i, table, table_size);
342 *(void **) result = table;
343 return table_size;
346 extern "C" void *
347 GOMP_OFFLOAD_alloc (int device, size_t size)
349 TRACE ("(size = %d)", size);
351 void *tgt_ptr;
352 VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
353 vd1[0].ptr = &size;
354 vd1[0].size = sizeof (size);
355 vd1[1].ptr = &tgt_ptr;
356 vd1[1].size = sizeof (void *);
357 VarDesc2 vd1g[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
359 offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2, vd1, vd1g);
361 return tgt_ptr;
364 extern "C" void
365 GOMP_OFFLOAD_free (int device, void *tgt_ptr)
367 TRACE ("(tgt_ptr = %p)", tgt_ptr);
369 VarDesc vd1 = vd_host2tgt;
370 vd1.ptr = &tgt_ptr;
371 vd1.size = sizeof (void *);
372 VarDesc2 vd1g = { "tgt_ptr", 0 };
374 offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd1, &vd1g);
377 extern "C" void *
378 GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
379 size_t size)
381 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr, host_ptr, size);
382 if (!size)
383 return tgt_ptr;
385 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
386 vd1[0].ptr = &tgt_ptr;
387 vd1[0].size = sizeof (void *);
388 vd1[1].ptr = &size;
389 vd1[1].size = sizeof (size);
390 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
392 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
393 vd1, vd1g);
395 VarDesc vd2 = vd_host2tgt;
396 vd2.ptr = (void *) host_ptr;
397 vd2.size = size;
398 VarDesc2 vd2g = { "var", 0 };
400 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
401 &vd2, &vd2g);
403 return tgt_ptr;
406 extern "C" void *
407 GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
408 size_t size)
410 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr, tgt_ptr, size);
411 if (!size)
412 return host_ptr;
414 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
415 vd1[0].ptr = &tgt_ptr;
416 vd1[0].size = sizeof (void *);
417 vd1[1].ptr = &size;
418 vd1[1].size = sizeof (size);
419 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
421 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
422 vd1, vd1g);
424 VarDesc vd2 = vd_tgt2host;
425 vd2.ptr = (void *) host_ptr;
426 vd2.size = size;
427 VarDesc2 vd2g = { "var", 0 };
429 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
430 &vd2, &vd2g);
432 return host_ptr;
435 extern "C" void
436 GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars)
438 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn, tgt_vars);
440 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
441 vd1[0].ptr = &tgt_fn;
442 vd1[0].size = sizeof (void *);
443 vd1[1].ptr = &tgt_vars;
444 vd1[1].size = sizeof (void *);
445 VarDesc2 vd1g[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
447 offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd1, vd1g);