123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /* Plugin for offload execution on Intel MIC devices.
- Copyright (C) 2014 Free Software Foundation, Inc.
- Contributed by Ilya Verbin <ilya.verbin@intel.com>.
- This file is part of the GNU Offloading and Multi Processing Library
- (libgomp).
- Libgomp is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
- Under Section 7 of GPL version 3, you are granted additional
- permissions described in the GCC Runtime Library Exception, version
- 3.1, as published by the Free Software Foundation.
- You should have received a copy of the GNU General Public License and
- a copy of the GCC Runtime Library Exception along with this program;
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
- <http://www.gnu.org/licenses/>. */
- /* Target side part of a libgomp plugin. */
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "compiler_if_target.h"
- #ifdef DEBUG
- #define TRACE(...) \
- { \
- fprintf (stderr, "TARGET:\t%s:%s ", __FILE__, __FUNCTION__); \
- fprintf (stderr, __VA_ARGS__); \
- fprintf (stderr, "\n"); \
- }
- #else
- #define TRACE { }
- #endif
- static VarDesc vd_host2tgt = {
- { 1, 1 }, /* dst, src */
- { 1, 0 }, /* in, out */
- 1, /* alloc_if */
- 1, /* free_if */
- 4, /* align */
- 0, /* mic_offset */
- { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
- is_stack_buf, sink_addr, alloc_disp,
- is_noncont_src, is_noncont_dst */
- 0, /* offset */
- 0, /* size */
- 1, /* count */
- 0, /* alloc */
- 0, /* into */
- 0 /* ptr */
- };
- static VarDesc vd_tgt2host = {
- { 1, 1 }, /* dst, src */
- { 0, 1 }, /* in, out */
- 1, /* alloc_if */
- 1, /* free_if */
- 4, /* align */
- 0, /* mic_offset */
- { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length,
- is_stack_buf, sink_addr, alloc_disp,
- is_noncont_src, is_noncont_dst */
- 0, /* offset */
- 0, /* size */
- 1, /* count */
- 0, /* alloc */
- 0, /* into */
- 0 /* ptr */
- };
- /* Pointer to the descriptor of the last loaded shared library. */
- static void *last_loaded_library = NULL;
- /* Pointer and size of the variable, used in __offload_target_host2tgt_p[12]
- and __offload_target_tgt2host_p[12]. */
- static void *last_var_ptr = NULL;
- static int last_var_size = 0;
- /* Override the corresponding functions from libgomp. */
- extern "C" int
- omp_is_initial_device (void) __GOMP_NOTHROW
- {
- return 0;
- }
- extern "C" int32_t
- omp_is_initial_device_ (void)
- {
- return omp_is_initial_device ();
- }
- /* Dummy function needed for the initialization of target process during the
- first call to __offload_offload1. */
- static void
- __offload_target_init_proc (OFFLOAD ofldt)
- {
- TRACE ("");
- }
- /* Collect addresses of the offload functions and of the global variables from
- the library descriptor and send them to host.
- Part 1: Send num_funcs and num_vars to host. */
- static void
- __offload_target_table_p1 (OFFLOAD ofldt)
- {
- void ***lib_descr = (void ***) last_loaded_library;
- if (lib_descr == NULL)
- {
- TRACE ("");
- fprintf (stderr, "Error! No shared libraries loaded on target.\n");
- return;
- }
- void **func_table_begin = lib_descr[0];
- void **func_table_end = lib_descr[1];
- void **var_table_begin = lib_descr[2];
- void **var_table_end = lib_descr[3];
- /* The func table contains only addresses, the var table contains addresses
- and corresponding sizes. */
- int num_funcs = func_table_end - func_table_begin;
- int num_vars = (var_table_end - var_table_begin) / 2;
- TRACE ("(num_funcs = %d, num_vars = %d)", num_funcs, num_vars);
- VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
- vd1[0].ptr = &num_funcs;
- vd1[0].size = sizeof (num_funcs);
- vd1[1].ptr = &num_vars;
- vd1[1].size = sizeof (num_vars);
- VarDesc2 vd2[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
- __offload_target_enter (ofldt, 2, vd1, vd2);
- __offload_target_leave (ofldt);
- }
- /* Part 2: Send the table with addresses to host. */
- static void
- __offload_target_table_p2 (OFFLOAD ofldt)
- {
- void ***lib_descr = (void ***) last_loaded_library;
- void **func_table_begin = lib_descr[0];
- void **func_table_end = lib_descr[1];
- void **var_table_begin = lib_descr[2];
- void **var_table_end = lib_descr[3];
- int num_funcs = func_table_end - func_table_begin;
- int num_vars = (var_table_end - var_table_begin) / 2;
- int table_size = (num_funcs + 2 * num_vars) * sizeof (void *);
- void **table = (void **) malloc (table_size);
- TRACE ("(table_size = %d)", table_size);
- VarDesc vd1;
- vd1 = vd_tgt2host;
- vd1.ptr = table;
- vd1.size = table_size;
- VarDesc2 vd2 = { "table", 0 };
- __offload_target_enter (ofldt, 1, &vd1, &vd2);
- void **p;
- int i = 0;
- for (p = func_table_begin; p < func_table_end; p++, i++)
- table[i] = *p;
- for (p = var_table_begin; p < var_table_end; p++, i++)
- table[i] = *p;
- __offload_target_leave (ofldt);
- free (table);
- }
- /* Allocate size bytes and send a pointer to the allocated memory to host. */
- static void
- __offload_target_alloc (OFFLOAD ofldt)
- {
- size_t size = 0;
- void *ptr = NULL;
- VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
- vd1[0].ptr = &size;
- vd1[0].size = sizeof (size);
- vd1[1].ptr = &ptr;
- vd1[1].size = sizeof (void *);
- VarDesc2 vd2[2] = { { "size", 0 }, { "ptr", 0 } };
- __offload_target_enter (ofldt, 2, vd1, vd2);
- ptr = malloc (size);
- TRACE ("(size = %d): ptr = %p", size, ptr);
- __offload_target_leave (ofldt);
- }
- /* Free the memory space pointed to by ptr. */
- static void
- __offload_target_free (OFFLOAD ofldt)
- {
- void *ptr = 0;
- VarDesc vd1 = vd_host2tgt;
- vd1.ptr = &ptr;
- vd1.size = sizeof (void *);
- VarDesc2 vd2 = { "ptr", 0 };
- __offload_target_enter (ofldt, 1, &vd1, &vd2);
- TRACE ("(ptr = %p)", ptr);
- free (ptr);
- __offload_target_leave (ofldt);
- }
- /* Receive var_size bytes from host and store to var_ptr.
- Part 1: Receive var_ptr and var_size from host. */
- static void
- __offload_target_host2tgt_p1 (OFFLOAD ofldt)
- {
- void *var_ptr = NULL;
- size_t var_size = 0;
- VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
- vd1[0].ptr = &var_ptr;
- vd1[0].size = sizeof (void *);
- vd1[1].ptr = &var_size;
- vd1[1].size = sizeof (var_size);
- VarDesc2 vd2[2] = { { "var_ptr", 0 }, { "var_size", 0 } };
- __offload_target_enter (ofldt, 2, vd1, vd2);
- TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size);
- last_var_ptr = var_ptr;
- last_var_size = var_size;
- __offload_target_leave (ofldt);
- }
- /* Part 2: Receive the data from host. */
- static void
- __offload_target_host2tgt_p2 (OFFLOAD ofldt)
- {
- TRACE ("(last_var_ptr = %p, last_var_size = %d)",
- last_var_ptr, last_var_size);
- VarDesc vd1 = vd_host2tgt;
- vd1.ptr = last_var_ptr;
- vd1.size = last_var_size;
- VarDesc2 vd2 = { "var", 0 };
- __offload_target_enter (ofldt, 1, &vd1, &vd2);
- __offload_target_leave (ofldt);
- }
- /* Send var_size bytes from var_ptr to host.
- Part 1: Receive var_ptr and var_size from host. */
- static void
- __offload_target_tgt2host_p1 (OFFLOAD ofldt)
- {
- void *var_ptr = NULL;
- size_t var_size = 0;
- VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
- vd1[0].ptr = &var_ptr;
- vd1[0].size = sizeof (void *);
- vd1[1].ptr = &var_size;
- vd1[1].size = sizeof (var_size);
- VarDesc2 vd2[2] = { { "var_ptr", 0 }, { "var_size", 0 } };
- __offload_target_enter (ofldt, 2, vd1, vd2);
- TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size);
- last_var_ptr = var_ptr;
- last_var_size = var_size;
- __offload_target_leave (ofldt);
- }
- /* Part 2: Send the data to host. */
- static void
- __offload_target_tgt2host_p2 (OFFLOAD ofldt)
- {
- TRACE ("(last_var_ptr = %p, last_var_size = %d)",
- last_var_ptr, last_var_size);
- VarDesc vd1 = vd_tgt2host;
- vd1.ptr = last_var_ptr;
- vd1.size = last_var_size;
- VarDesc2 vd2 = { "var", 0 };
- __offload_target_enter (ofldt, 1, &vd1, &vd2);
- __offload_target_leave (ofldt);
- }
- /* Call offload function by the address fn_ptr and pass vars_ptr to it. */
- static void
- __offload_target_run (OFFLOAD ofldt)
- {
- void *fn_ptr;
- void *vars_ptr;
- VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
- vd1[0].ptr = &fn_ptr;
- vd1[0].size = sizeof (void *);
- vd1[1].ptr = &vars_ptr;
- vd1[1].size = sizeof (void *);
- VarDesc2 vd2[2] = { { "fn_ptr", 0 }, { "vars_ptr", 0 } };
- __offload_target_enter (ofldt, 2, vd1, vd2);
- TRACE ("(fn_ptr = %p, vars_ptr = %p)", fn_ptr, vars_ptr);
- void (*fn)(void *) = (void (*)(void *)) fn_ptr;
- fn (vars_ptr);
- __offload_target_leave (ofldt);
- }
- /* This should be called from every library with offloading. */
- extern "C" void
- target_register_lib (const void *target_table)
- {
- TRACE ("(target_table = %p { %p, %p, %p, %p })", target_table,
- ((void **) target_table)[0], ((void **) target_table)[1],
- ((void **) target_table)[2], ((void **) target_table)[3]);
- last_loaded_library = (void *) target_table;
- }
- /* Use __offload_target_main from liboffload. */
- int
- main (int argc, char **argv)
- {
- __offload_target_main ();
- return 0;
- }
- /* Register offload_target_main's functions in the liboffload. */
- struct Entry {
- const char *name;
- void *func;
- };
- #define REGISTER(f) \
- extern "C" const Entry __offload_target_##f##_$entry \
- __attribute__ ((section(".OffloadEntryTable."))) = { \
- "__offload_target_"#f, \
- (void *) __offload_target_##f \
- }
- REGISTER (init_proc);
- REGISTER (table_p1);
- REGISTER (table_p2);
- REGISTER (alloc);
- REGISTER (free);
- REGISTER (host2tgt_p1);
- REGISTER (host2tgt_p2);
- REGISTER (tgt2host_p1);
- REGISTER (tgt2host_p2);
- REGISTER (run);
- #undef REGISTER
|