]> git.ipfire.org Git - thirdparty/gcc.git/blame - liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
Add OpenACC 2.6 `acc_get_property' support
[thirdparty/gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
CommitLineData
9d73ec14
IV
1/* Plugin for offload execution on Intel MIC devices.
2
df26a50d 3 Copyright (C) 2014-2016 Free Software Foundation, Inc.
9d73ec14
IV
4
5 Contributed by Ilya Verbin <ilya.verbin@intel.com>.
6
f1f3453e
TS
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
9d73ec14
IV
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>
a51df54e 37#include <map>
41dbbb37 38#include "libgomp-plugin.h"
9d73ec14
IV
39#include "compiler_if_host.h"
40#include "main_target_image.h"
8e87588a 41#include "gomp-constants.h"
9d73ec14 42
44799f87 43#define OFFLOAD_ACTIVE_WAIT_ENV "OFFLOAD_ACTIVE_WAIT"
9d73ec14
IV
44
45#ifdef DEBUG
46#define TRACE(...) \
47{ \
48fprintf (stderr, "HOST:\t%s:%s ", __FILE__, __FUNCTION__); \
49fprintf (stderr, __VA_ARGS__); \
50fprintf (stderr, "\n"); \
51}
52#else
53#define TRACE { }
54#endif
55
56
a51df54e
IV
57/* Start/end addresses of functions and global variables on a device. */
58typedef std::vector<addr_pair> AddrVect;
59
60/* Addresses for one image and all devices. */
61typedef std::vector<AddrVect> DevAddrVect;
62
63/* Addresses for all images and all devices. */
afb2d80b 64typedef std::map<const void *, DevAddrVect> ImgDevAddrMap;
a51df54e 65
4219ddb3
IV
66/* Image descriptor needed by __offload_[un]register_image. */
67struct TargetImageDesc {
68 int64_t size;
69 /* 10 characters is enough for max int value. */
70 char name[sizeof ("lib0000000000.so")];
71 char data[];
72};
73
74/* Image descriptors, indexed by a pointer obtained from libgomp. */
75typedef std::map<const void *, TargetImageDesc *> ImgDescMap;
76
a51df54e
IV
77
78/* Total number of available devices. */
79static int num_devices;
80
81/* Total number of shared libraries with offloading to Intel MIC. */
82static int num_images;
83
84/* Two dimensional array: one key is a pointer to image,
85 second key is number of device. Contains a vector of pointer pairs. */
86static ImgDevAddrMap *address_table;
87
4219ddb3
IV
88/* Descriptors of all images, registered in liboffloadmic. */
89static ImgDescMap *image_descriptors;
90
a51df54e
IV
91/* Thread-safe registration of the main image. */
92static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
93
9d73ec14
IV
94static VarDesc vd_host2tgt = {
95 { 1, 1 }, /* dst, src */
96 { 1, 0 }, /* in, out */
97 1, /* alloc_if */
98 1, /* free_if */
99 4, /* align */
100 0, /* mic_offset */
101 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
102 is_stack_buf, sink_addr, alloc_disp,
103 is_noncont_src, is_noncont_dst */
104 0, /* offset */
105 0, /* size */
106 1, /* count */
107 0, /* alloc */
108 0, /* into */
109 0 /* ptr */
110};
111
112static VarDesc vd_tgt2host = {
113 { 1, 1 }, /* dst, src */
114 { 0, 1 }, /* in, out */
115 1, /* alloc_if */
116 1, /* free_if */
117 4, /* align */
118 0, /* mic_offset */
119 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
120 is_stack_buf, sink_addr, alloc_disp,
121 is_noncont_src, is_noncont_dst */
122 0, /* offset */
123 0, /* size */
124 1, /* count */
125 0, /* alloc */
126 0, /* into */
127 0 /* ptr */
128};
129
130
9d73ec14
IV
131__attribute__((constructor))
132static void
a51df54e 133init (void)
9d73ec14 134{
44799f87
IV
135 const char *active_wait = getenv (OFFLOAD_ACTIVE_WAIT_ENV);
136
137 /* Disable active wait by default to avoid useless CPU usage. */
138 if (!active_wait)
139 setenv (OFFLOAD_ACTIVE_WAIT_ENV, "0", 0);
9d73ec14 140
a51df54e 141 address_table = new ImgDevAddrMap;
4219ddb3 142 image_descriptors = new ImgDescMap;
a51df54e 143 num_devices = _Offload_number_of_devices ();
9d73ec14
IV
144}
145
41dbbb37
TS
146extern "C" const char *
147GOMP_OFFLOAD_get_name (void)
148{
149 const char *res = "intelmic";
150 TRACE ("(): return %s", res);
151 return res;
152}
153
154extern "C" unsigned int
155GOMP_OFFLOAD_get_caps (void)
156{
157 unsigned int res = GOMP_OFFLOAD_CAP_OPENMP_400;
158 TRACE ("(): return %x", res);
159 return res;
160}
161
dced339c 162extern "C" int
9d73ec14
IV
163GOMP_OFFLOAD_get_type (void)
164{
165 enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
166 TRACE ("(): return %d", res);
167 return res;
168}
169
170extern "C" int
171GOMP_OFFLOAD_get_num_devices (void)
172{
a51df54e
IV
173 TRACE ("(): return %d", num_devices);
174 return num_devices;
9d73ec14
IV
175}
176
6c84c8bf
MR
177extern "C" union gomp_device_property_value
178GOMP_OFFLOAD_get_property (int n, int prop)
179{
180 union gomp_device_property_value nullval = { .val = 0 };
181
182 if (n >= num_devices)
183 {
184 GOMP_PLUGIN_error
185 ("Request for a property of a non-existing Intel MIC device %i", n);
186 return nullval;
187 }
188
189 switch (prop)
190 {
191 case GOMP_DEVICE_PROPERTY_VENDOR:
192 return (union gomp_device_property_value) { .ptr = "Intel" };
193 default:
194 return nullval;
195 }
196}
197
6ce13072 198static bool
9d73ec14 199offload (const char *file, uint64_t line, int device, const char *name,
4219ddb3 200 int num_vars, VarDesc *vars, const void **async_data)
9d73ec14
IV
201{
202 OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
203 if (ofld)
e4606348
JJ
204 {
205 if (async_data == NULL)
6ce13072
CLT
206 return __offload_offload1 (ofld, name, 0, num_vars, vars, NULL, 0,
207 NULL, NULL);
e4606348
JJ
208 else
209 {
210 OffloadFlags flags;
211 flags.flags = 0;
212 flags.bits.omp_async = 1;
6ce13072
CLT
213 return __offload_offload3 (ofld, name, 0, num_vars, vars, NULL, 0,
214 NULL, async_data, 0, NULL, flags, NULL);
e4606348
JJ
215 }
216 }
9d73ec14
IV
217 else
218 {
6ce13072
CLT
219 GOMP_PLUGIN_error ("%s:%d: Offload target acquire failed\n", file, line);
220 return false;
9d73ec14
IV
221 }
222}
223
224static void
225register_main_image ()
226{
4219ddb3
IV
227 /* Do not check the return value, because old versions of liboffloadmic did
228 not have return values. */
9d73ec14 229 __offload_register_image (&main_target_image);
e4606348
JJ
230
231 /* liboffloadmic will call GOMP_PLUGIN_target_task_completion when
232 asynchronous task on target is completed. */
233 __offload_register_task_callback (GOMP_PLUGIN_target_task_completion);
9d73ec14
IV
234}
235
a51df54e
IV
236/* liboffloadmic loads and runs offload_target_main on all available devices
237 during a first call to offload (). */
6ce13072 238extern "C" bool
9d73ec14
IV
239GOMP_OFFLOAD_init_device (int device)
240{
4219ddb3 241 TRACE ("(device = %d)", device);
9d73ec14 242 pthread_once (&main_image_is_registered, register_main_image);
6ce13072
CLT
243 return offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
244 NULL, NULL);
9d73ec14
IV
245}
246
6ce13072 247extern "C" bool
41dbbb37
TS
248GOMP_OFFLOAD_fini_device (int device)
249{
4219ddb3 250 TRACE ("(device = %d)", device);
d84ffc0a
IV
251
252 /* liboffloadmic will finalize target processes on all available devices. */
253 __offload_unregister_image (&main_target_image);
6ce13072 254 return true;
41dbbb37
TS
255}
256
6ce13072 257static bool
9d73ec14
IV
258get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
259{
260 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
261 vd1[0].ptr = &num_funcs;
262 vd1[0].size = sizeof (num_funcs);
263 vd1[1].ptr = &num_vars;
264 vd1[1].size = sizeof (num_vars);
9d73ec14 265
6ce13072
CLT
266 if (!offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
267 vd1, NULL))
268 return false;
9d73ec14
IV
269
270 int table_size = num_funcs + 2 * num_vars;
271 if (table_size > 0)
272 {
273 table = new void * [table_size];
274
275 VarDesc vd2;
276 vd2 = vd_tgt2host;
277 vd2.ptr = table;
278 vd2.size = table_size * sizeof (void *);
9d73ec14 279
6ce13072
CLT
280 return offload (__FILE__, __LINE__, device, "__offload_target_table_p2",
281 1, &vd2, NULL);
9d73ec14 282 }
6ce13072 283 return true;
9d73ec14
IV
284}
285
a51df54e
IV
286/* Offload TARGET_IMAGE to all available devices and fill address_table with
287 corresponding target addresses. */
288
6ce13072 289static bool
afb2d80b 290offload_image (const void *target_image)
9d73ec14 291{
a51df54e
IV
292 void *image_start = ((void **) target_image)[0];
293 void *image_end = ((void **) target_image)[1];
9d73ec14 294
a51df54e
IV
295 TRACE ("(target_image = %p { %p, %p })",
296 target_image, image_start, image_end);
9d73ec14
IV
297
298 int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
4219ddb3
IV
299 TargetImageDesc *image = (TargetImageDesc *) malloc (offsetof (TargetImageDesc, data)
300 + image_size);
9d73ec14
IV
301 if (!image)
302 {
6ce13072
CLT
303 GOMP_PLUGIN_error ("%s: Can't allocate memory\n", __FILE__);
304 return false;
9d73ec14
IV
305 }
306
307 image->size = image_size;
a51df54e 308 sprintf (image->name, "lib%010d.so", num_images++);
9d73ec14
IV
309 memcpy (image->data, image_start, image->size);
310
311 TRACE ("() __offload_register_image %s { %p, %d }",
312 image->name, image_start, image->size);
4219ddb3
IV
313 /* Do not check the return value, because old versions of liboffloadmic did
314 not have return values. */
9d73ec14
IV
315 __offload_register_image (image);
316
a51df54e
IV
317 /* Receive tables for target_image from all devices. */
318 DevAddrVect dev_table;
6ce13072 319 bool ret = true;
a51df54e 320 for (int dev = 0; dev < num_devices; dev++)
9d73ec14 321 {
a51df54e
IV
322 int num_funcs = 0;
323 int num_vars = 0;
324 void **table = NULL;
9d73ec14 325
6ce13072 326 ret &= get_target_table (dev, num_funcs, num_vars, table);
9d73ec14 327
a51df54e 328 AddrVect curr_dev_table;
9d73ec14 329
a51df54e
IV
330 for (int i = 0; i < num_funcs; i++)
331 {
332 addr_pair tgt_addr;
333 tgt_addr.start = (uintptr_t) table[i];
334 tgt_addr.end = tgt_addr.start + 1;
335 TRACE ("() func %d:\t0x%llx..0x%llx", i,
336 tgt_addr.start, tgt_addr.end);
337 curr_dev_table.push_back (tgt_addr);
338 }
9d73ec14 339
a51df54e
IV
340 for (int i = 0; i < num_vars; i++)
341 {
342 addr_pair tgt_addr;
343 tgt_addr.start = (uintptr_t) table[num_funcs+i*2];
344 tgt_addr.end = tgt_addr.start + (uintptr_t) table[num_funcs+i*2+1];
345 TRACE ("() var %d:\t0x%llx..0x%llx", i, tgt_addr.start, tgt_addr.end);
346 curr_dev_table.push_back (tgt_addr);
347 }
9d73ec14 348
a51df54e 349 dev_table.push_back (curr_dev_table);
4219ddb3 350 delete [] table;
9d73ec14
IV
351 }
352
a51df54e 353 address_table->insert (std::make_pair (target_image, dev_table));
4219ddb3 354 image_descriptors->insert (std::make_pair (target_image, image));
6ce13072 355 return ret;
9d73ec14
IV
356}
357
2a21ff19
NS
358/* Return the libgomp version number we're compatible with. There is
359 no requirement for cross-version compatibility. */
360
361extern "C" unsigned
362GOMP_OFFLOAD_version (void)
363{
364 return GOMP_VERSION;
365}
366
9d73ec14 367extern "C" int
2a21ff19 368GOMP_OFFLOAD_load_image (int device, const unsigned version,
dced339c 369 const void *target_image, addr_pair **result)
9d73ec14 370{
a51df54e 371 TRACE ("(device = %d, target_image = %p)", device, target_image);
9d73ec14 372
2a21ff19 373 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
6ce13072
CLT
374 {
375 GOMP_PLUGIN_error ("Offload data incompatible with intelmic plugin"
376 " (expected %u, received %u)",
377 GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
378 return -1;
379 }
2a21ff19 380
a51df54e
IV
381 /* If target_image is already present in address_table, then there is no need
382 to offload it. */
383 if (address_table->count (target_image) == 0)
6ce13072
CLT
384 {
385 /* If fail, return -1 as error code. */
386 if (!offload_image (target_image))
387 return -1;
388 }
9d73ec14 389
a51df54e
IV
390 AddrVect *curr_dev_table = &(*address_table)[target_image][device];
391 int table_size = curr_dev_table->size ();
392 addr_pair *table = (addr_pair *) malloc (table_size * sizeof (addr_pair));
393 if (table == NULL)
394 {
6ce13072
CLT
395 GOMP_PLUGIN_error ("%s: Can't allocate memory\n", __FILE__);
396 return -1;
a51df54e 397 }
9d73ec14 398
a51df54e
IV
399 std::copy (curr_dev_table->begin (), curr_dev_table->end (), table);
400 *result = table;
9d73ec14
IV
401 return table_size;
402}
403
6ce13072 404extern "C" bool
2a21ff19
NS
405GOMP_OFFLOAD_unload_image (int device, unsigned version,
406 const void *target_image)
a51df54e 407{
2a21ff19 408 if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
6ce13072
CLT
409 {
410 GOMP_PLUGIN_error ("Offload data incompatible with intelmic plugin"
411 " (expected %u, received %u)",
412 GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
413 return false;
414 }
2a21ff19 415
a51df54e
IV
416 TRACE ("(device = %d, target_image = %p)", device, target_image);
417
4219ddb3
IV
418 /* liboffloadmic unloads the image from all available devices. */
419 if (image_descriptors->count (target_image) > 0)
420 {
421 TargetImageDesc *image_desc = (*image_descriptors)[target_image];
422 __offload_unregister_image (image_desc);
423 free (image_desc);
a51df54e 424
4219ddb3
IV
425 address_table->erase (target_image);
426 image_descriptors->erase (target_image);
427 }
6ce13072 428 return true;
a51df54e
IV
429}
430
9d73ec14
IV
431extern "C" void *
432GOMP_OFFLOAD_alloc (int device, size_t size)
433{
4219ddb3 434 TRACE ("(device = %d, size = %d)", device, size);
9d73ec14
IV
435
436 void *tgt_ptr;
4219ddb3
IV
437 VarDesc vd[2] = { vd_host2tgt, vd_tgt2host };
438 vd[0].ptr = &size;
439 vd[0].size = sizeof (size);
440 vd[1].ptr = &tgt_ptr;
441 vd[1].size = sizeof (void *);
442
6ce13072
CLT
443 if (!offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2,
444 vd, NULL))
445 return NULL;
4219ddb3 446
9d73ec14
IV
447 return tgt_ptr;
448}
449
6ce13072 450extern "C" bool
9d73ec14
IV
451GOMP_OFFLOAD_free (int device, void *tgt_ptr)
452{
4219ddb3 453 TRACE ("(device = %d, tgt_ptr = %p)", device, tgt_ptr);
9d73ec14 454
4219ddb3
IV
455 VarDesc vd = vd_host2tgt;
456 vd.ptr = &tgt_ptr;
457 vd.size = sizeof (void *);
9d73ec14 458
6ce13072
CLT
459 return offload (__FILE__, __LINE__, device, "__offload_target_free", 1,
460 &vd, NULL);
9d73ec14
IV
461}
462
6ce13072 463extern "C" bool
9d73ec14
IV
464GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
465 size_t size)
466{
4219ddb3
IV
467 TRACE ("(device = %d, tgt_ptr = %p, host_ptr = %p, size = %d)",
468 device, tgt_ptr, host_ptr, size);
9d73ec14 469 if (!size)
6ce13072 470 return true;
9d73ec14
IV
471
472 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
473 vd1[0].ptr = &tgt_ptr;
474 vd1[0].size = sizeof (void *);
475 vd1[1].ptr = &size;
476 vd1[1].size = sizeof (size);
9d73ec14 477
6ce13072
CLT
478 if (!offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
479 vd1, NULL))
480 return false;
9d73ec14
IV
481
482 VarDesc vd2 = vd_host2tgt;
483 vd2.ptr = (void *) host_ptr;
484 vd2.size = size;
9d73ec14 485
6ce13072
CLT
486 return offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
487 &vd2, NULL);
9d73ec14
IV
488}
489
6ce13072 490extern "C" bool
9d73ec14
IV
491GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
492 size_t size)
493{
4219ddb3
IV
494 TRACE ("(device = %d, host_ptr = %p, tgt_ptr = %p, size = %d)",
495 device, host_ptr, tgt_ptr, size);
9d73ec14 496 if (!size)
6ce13072 497 return true;
9d73ec14
IV
498
499 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
500 vd1[0].ptr = &tgt_ptr;
501 vd1[0].size = sizeof (void *);
502 vd1[1].ptr = &size;
503 vd1[1].size = sizeof (size);
9d73ec14 504
6ce13072
CLT
505 if (!offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
506 vd1, NULL))
507 return false;
9d73ec14
IV
508
509 VarDesc vd2 = vd_tgt2host;
510 vd2.ptr = (void *) host_ptr;
511 vd2.size = size;
9d73ec14 512
6ce13072
CLT
513 return offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
514 &vd2, NULL);
9d73ec14
IV
515}
516
6ce13072 517extern "C" bool
d9a6bd32
JJ
518GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr,
519 size_t size)
520{
4219ddb3
IV
521 TRACE ("(device = %d, dst_ptr = %p, src_ptr = %p, size = %d)",
522 device, dst_ptr, src_ptr, size);
d9a6bd32 523 if (!size)
6ce13072 524 return true;
d9a6bd32 525
4219ddb3
IV
526 VarDesc vd[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
527 vd[0].ptr = &dst_ptr;
528 vd[0].size = sizeof (void *);
529 vd[1].ptr = &src_ptr;
530 vd[1].size = sizeof (void *);
531 vd[2].ptr = &size;
532 vd[2].size = sizeof (size);
d9a6bd32 533
6ce13072
CLT
534 return offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3,
535 vd, NULL);
d9a6bd32
JJ
536}
537
9d73ec14 538extern "C" void
e4606348 539GOMP_OFFLOAD_async_run (int device, void *tgt_fn, void *tgt_vars,
b2b40051 540 void **, void *async_data)
9d73ec14 541{
e4606348
JJ
542 TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p, async_data = %p)", device,
543 tgt_fn, tgt_vars, async_data);
9d73ec14 544
e4606348
JJ
545 VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
546 vd[0].ptr = &tgt_fn;
547 vd[0].size = sizeof (void *);
548 vd[1].ptr = &tgt_vars;
549 vd[1].size = sizeof (void *);
550
4219ddb3 551 offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd,
e4606348
JJ
552 (const void **) async_data);
553}
554
555extern "C" void
b2b40051 556GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars, void **)
e4606348
JJ
557{
558 TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p)", device, tgt_fn, tgt_vars);
9d73ec14 559
23a80f4d 560 GOMP_OFFLOAD_async_run (device, tgt_fn, tgt_vars, NULL, NULL);
9d73ec14 561}