]> git.ipfire.org Git - thirdparty/gcc.git/blob - liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
Merge current set of OpenACC changes from gomp-4_0-branch.
[thirdparty/gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
1 /* Plugin for offload execution on Intel MIC devices.
2
3 Copyright (C) 2014 Free Software Foundation, Inc.
4
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
6
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
9
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.
14
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.
19
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.
23
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/>. */
28
29 /* Host side part of a libgomp plugin. */
30
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-plugin.h"
38 #include "compiler_if_host.h"
39 #include "main_target_image.h"
40
41 #define LD_LIBRARY_PATH_ENV "LD_LIBRARY_PATH"
42 #define MIC_LD_LIBRARY_PATH_ENV "MIC_LD_LIBRARY_PATH"
43
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"); \
50 }
51 #else
52 #define TRACE { }
53 #endif
54
55
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 */
72 };
73
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 */
90 };
91
92
93 /* Total number of shared libraries with offloading to Intel MIC. */
94 static int num_libraries;
95
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;
99
100 /* Thread-safe registration of the main image. */
101 static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
102
103
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)
109 {
110 const char *ld_lib_path = getenv (LD_LIBRARY_PATH_ENV);
111 const char *mic_lib_path = getenv (MIC_LD_LIBRARY_PATH_ENV);
112
113 if (!ld_lib_path)
114 return;
115
116 if (!mic_lib_path)
117 setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
118 else
119 {
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)
125 {
126 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
127 exit (1);
128 }
129
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);
132
133 if (!use_alloca)
134 free (mic_lib_path_new);
135 }
136 }
137
138 extern "C" const char *
139 GOMP_OFFLOAD_get_name (void)
140 {
141 const char *res = "intelmic";
142 TRACE ("(): return %s", res);
143 return res;
144 }
145
146 extern "C" unsigned int
147 GOMP_OFFLOAD_get_caps (void)
148 {
149 unsigned int res = GOMP_OFFLOAD_CAP_OPENMP_400;
150 TRACE ("(): return %x", res);
151 return res;
152 }
153
154 extern "C" enum offload_target_type
155 GOMP_OFFLOAD_get_type (void)
156 {
157 enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
158 TRACE ("(): return %d", res);
159 return res;
160 }
161
162 extern "C" int
163 GOMP_OFFLOAD_get_num_devices (void)
164 {
165 int res = _Offload_number_of_devices ();
166 TRACE ("(): return %d", res);
167 return res;
168 }
169
170 /* This should be called from every shared library with offloading. */
171 extern "C" void
172 GOMP_OFFLOAD_register_image (void *host_table, void *target_image)
173 {
174 TRACE ("(host_table = %p, target_image = %p)", host_table, target_image);
175 lib_descrs.push_back (std::make_pair (host_table, target_image));
176 num_libraries++;
177 }
178
179 static void
180 offload (const char *file, uint64_t line, int device, const char *name,
181 int num_vars, VarDesc *vars, VarDesc2 *vars2)
182 {
183 OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
184 if (ofld)
185 __offload_offload1 (ofld, name, 0, num_vars, vars, vars2, 0, NULL, NULL);
186 else
187 {
188 fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
189 exit (1);
190 }
191 }
192
193 static void
194 register_main_image ()
195 {
196 __offload_register_image (&main_target_image);
197 }
198
199 /* Load offload_target_main on target. */
200 extern "C" void
201 GOMP_OFFLOAD_init_device (int device)
202 {
203 TRACE ("");
204 pthread_once (&main_image_is_registered, register_main_image);
205 offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
206 NULL, NULL);
207 }
208
209 extern "C" void
210 GOMP_OFFLOAD_fini_device (int device)
211 {
212 TRACE ("");
213 /* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
214 abort ();
215 }
216
217 static void
218 get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
219 {
220 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
221 vd1[0].ptr = &num_funcs;
222 vd1[0].size = sizeof (num_funcs);
223 vd1[1].ptr = &num_vars;
224 vd1[1].size = sizeof (num_vars);
225 VarDesc2 vd1g[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
226
227 offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
228 vd1, vd1g);
229
230 int table_size = num_funcs + 2 * num_vars;
231 if (table_size > 0)
232 {
233 table = new void * [table_size];
234
235 VarDesc vd2;
236 vd2 = vd_tgt2host;
237 vd2.ptr = table;
238 vd2.size = table_size * sizeof (void *);
239 VarDesc2 vd2g = { "table", 0 };
240
241 offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1,
242 &vd2, &vd2g);
243 }
244 }
245
246 static void
247 load_lib_and_get_table (int device, int lib_num, mapping_table *&table,
248 int &table_size)
249 {
250 struct TargetImage {
251 int64_t size;
252 /* 10 characters is enough for max int value. */
253 char name[sizeof ("lib0000000000.so")];
254 char data[];
255 } __attribute__ ((packed));
256
257 void ***host_table_descr = (void ***) lib_descrs[lib_num].first;
258 void **host_func_start = host_table_descr[0];
259 void **host_func_end = host_table_descr[1];
260 void **host_var_start = host_table_descr[2];
261 void **host_var_end = host_table_descr[3];
262
263 void **target_image_descr = (void **) lib_descrs[lib_num].second;
264 void *image_start = target_image_descr[0];
265 void *image_end = target_image_descr[1];
266
267 TRACE ("() host_table_descr { %p, %p, %p, %p }", host_func_start,
268 host_func_end, host_var_start, host_var_end);
269 TRACE ("() target_image_descr { %p, %p }", image_start, image_end);
270
271 int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
272 TargetImage *image
273 = (TargetImage *) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
274 + image_size);
275 if (!image)
276 {
277 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
278 exit (1);
279 }
280
281 image->size = image_size;
282 sprintf (image->name, "lib%010d.so", lib_num);
283 memcpy (image->data, image_start, image->size);
284
285 TRACE ("() __offload_register_image %s { %p, %d }",
286 image->name, image_start, image->size);
287 __offload_register_image (image);
288
289 int tgt_num_funcs = 0;
290 int tgt_num_vars = 0;
291 void **tgt_table = NULL;
292 get_target_table (device, tgt_num_funcs, tgt_num_vars, tgt_table);
293 free (image);
294
295 /* The func table contains only addresses, the var table contains addresses
296 and corresponding sizes. */
297 int host_num_funcs = host_func_end - host_func_start;
298 int host_num_vars = (host_var_end - host_var_start) / 2;
299 TRACE ("() host_num_funcs = %d, tgt_num_funcs = %d",
300 host_num_funcs, tgt_num_funcs);
301 TRACE ("() host_num_vars = %d, tgt_num_vars = %d",
302 host_num_vars, tgt_num_vars);
303 if (host_num_funcs != tgt_num_funcs)
304 {
305 fprintf (stderr, "%s: Can't map target functions\n", __FILE__);
306 exit (1);
307 }
308 if (host_num_vars != tgt_num_vars)
309 {
310 fprintf (stderr, "%s: Can't map target variables\n", __FILE__);
311 exit (1);
312 }
313
314 table = (mapping_table *) realloc (table, (table_size + host_num_funcs
315 + host_num_vars)
316 * sizeof (mapping_table));
317 if (table == NULL)
318 {
319 fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
320 exit (1);
321 }
322
323 for (int i = 0; i < host_num_funcs; i++)
324 {
325 mapping_table t;
326 t.host_start = (uintptr_t) host_func_start[i];
327 t.host_end = t.host_start + 1;
328 t.tgt_start = (uintptr_t) tgt_table[i];
329 t.tgt_end = t.tgt_start + 1;
330
331 TRACE ("() lib %d, func %d:\t0x%llx -- 0x%llx",
332 lib_num, i, t.host_start, t.tgt_start);
333
334 table[table_size++] = t;
335 }
336
337 for (int i = 0; i < host_num_vars * 2; i += 2)
338 {
339 mapping_table t;
340 t.host_start = (uintptr_t) host_var_start[i];
341 t.host_end = t.host_start + (uintptr_t) host_var_start[i+1];
342 t.tgt_start = (uintptr_t) tgt_table[tgt_num_funcs+i];
343 t.tgt_end = t.tgt_start + (uintptr_t) tgt_table[tgt_num_funcs+i+1];
344
345 TRACE ("() lib %d, var %d:\t0x%llx (%d) -- 0x%llx (%d)", lib_num, i/2,
346 t.host_start, t.host_end - t.host_start,
347 t.tgt_start, t.tgt_end - t.tgt_start);
348
349 table[table_size++] = t;
350 }
351
352 delete [] tgt_table;
353 }
354
355 extern "C" int
356 GOMP_OFFLOAD_get_table (int device, void *result)
357 {
358 TRACE ("(num_libraries = %d)", num_libraries);
359
360 mapping_table *table = NULL;
361 int table_size = 0;
362
363 for (int i = 0; i < num_libraries; i++)
364 load_lib_and_get_table (device, i, table, table_size);
365
366 *(void **) result = table;
367 return table_size;
368 }
369
370 extern "C" void *
371 GOMP_OFFLOAD_alloc (int device, size_t size)
372 {
373 TRACE ("(size = %d)", size);
374
375 void *tgt_ptr;
376 VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
377 vd1[0].ptr = &size;
378 vd1[0].size = sizeof (size);
379 vd1[1].ptr = &tgt_ptr;
380 vd1[1].size = sizeof (void *);
381 VarDesc2 vd1g[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
382
383 offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2, vd1, vd1g);
384
385 return tgt_ptr;
386 }
387
388 extern "C" void
389 GOMP_OFFLOAD_free (int device, void *tgt_ptr)
390 {
391 TRACE ("(tgt_ptr = %p)", tgt_ptr);
392
393 VarDesc vd1 = vd_host2tgt;
394 vd1.ptr = &tgt_ptr;
395 vd1.size = sizeof (void *);
396 VarDesc2 vd1g = { "tgt_ptr", 0 };
397
398 offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd1, &vd1g);
399 }
400
401 extern "C" void *
402 GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
403 size_t size)
404 {
405 TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr, host_ptr, size);
406 if (!size)
407 return tgt_ptr;
408
409 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
410 vd1[0].ptr = &tgt_ptr;
411 vd1[0].size = sizeof (void *);
412 vd1[1].ptr = &size;
413 vd1[1].size = sizeof (size);
414 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
415
416 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
417 vd1, vd1g);
418
419 VarDesc vd2 = vd_host2tgt;
420 vd2.ptr = (void *) host_ptr;
421 vd2.size = size;
422 VarDesc2 vd2g = { "var", 0 };
423
424 offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
425 &vd2, &vd2g);
426
427 return tgt_ptr;
428 }
429
430 extern "C" void *
431 GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
432 size_t size)
433 {
434 TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr, tgt_ptr, size);
435 if (!size)
436 return host_ptr;
437
438 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
439 vd1[0].ptr = &tgt_ptr;
440 vd1[0].size = sizeof (void *);
441 vd1[1].ptr = &size;
442 vd1[1].size = sizeof (size);
443 VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
444
445 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
446 vd1, vd1g);
447
448 VarDesc vd2 = vd_tgt2host;
449 vd2.ptr = (void *) host_ptr;
450 vd2.size = size;
451 VarDesc2 vd2g = { "var", 0 };
452
453 offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
454 &vd2, &vd2g);
455
456 return host_ptr;
457 }
458
459 extern "C" void
460 GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars)
461 {
462 TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn, tgt_vars);
463
464 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
465 vd1[0].ptr = &tgt_fn;
466 vd1[0].size = sizeof (void *);
467 vd1[1].ptr = &tgt_vars;
468 vd1[1].size = sizeof (void *);
469 VarDesc2 vd1g[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
470
471 offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd1, vd1g);
472 }