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/* Target side part of a libgomp plugin. */ 30 31#include <stdint.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include "compiler_if_target.h" 35 36 37#ifdef DEBUG 38#define TRACE(...) \ 39{ \ 40fprintf (stderr, "TARGET:\t%s:%s ", __FILE__, __FUNCTION__); \ 41fprintf (stderr, __VA_ARGS__); \ 42fprintf (stderr, "\n"); \ 43} 44#else 45#define TRACE { } 46#endif 47 48 49static VarDesc vd_host2tgt = { 50 { 1, 1 }, /* dst, src */ 51 { 1, 0 }, /* in, out */ 52 1, /* alloc_if */ 53 1, /* free_if */ 54 4, /* align */ 55 0, /* mic_offset */ 56 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length, 57 is_stack_buf, sink_addr, alloc_disp, 58 is_noncont_src, is_noncont_dst */ 59 0, /* offset */ 60 0, /* size */ 61 1, /* count */ 62 0, /* alloc */ 63 0, /* into */ 64 0 /* ptr */ 65}; 66 67static VarDesc vd_tgt2host = { 68 { 1, 1 }, /* dst, src */ 69 { 0, 1 }, /* in, out */ 70 1, /* alloc_if */ 71 1, /* free_if */ 72 4, /* align */ 73 0, /* mic_offset */ 74 { 0, 0, 0, 0, 0, 0, 0, 0 }, /* is_static, is_static_dstn, has_length, 75 is_stack_buf, sink_addr, alloc_disp, 76 is_noncont_src, is_noncont_dst */ 77 0, /* offset */ 78 0, /* size */ 79 1, /* count */ 80 0, /* alloc */ 81 0, /* into */ 82 0 /* ptr */ 83}; 84 85/* Pointer to the descriptor of the last loaded shared library. */ 86static void *last_loaded_library = NULL; 87 88/* Pointer and size of the variable, used in __offload_target_host2tgt_p[12] 89 and __offload_target_tgt2host_p[12]. */ 90static void *last_var_ptr = NULL; 91static int last_var_size = 0; 92 93 94/* Override the corresponding functions from libgomp. */ 95extern "C" int 96omp_is_initial_device (void) __GOMP_NOTHROW 97{ 98 return 0; 99} 100 101extern "C" int32_t 102omp_is_initial_device_ (void) 103{ 104 return omp_is_initial_device (); 105} 106 107 108/* Dummy function needed for the initialization of target process during the 109 first call to __offload_offload1. */ 110static void 111__offload_target_init_proc (OFFLOAD ofldt) 112{ 113 TRACE (""); 114} 115 116/* Collect addresses of the offload functions and of the global variables from 117 the library descriptor and send them to host. 118 Part 1: Send num_funcs and num_vars to host. */ 119static void 120__offload_target_table_p1 (OFFLOAD ofldt) 121{ 122 void ***lib_descr = (void ***) last_loaded_library; 123 124 if (lib_descr == NULL) 125 { 126 TRACE (""); 127 fprintf (stderr, "Error! No shared libraries loaded on target.\n"); 128 return; 129 } 130 131 void **func_table_begin = lib_descr[0]; 132 void **func_table_end = lib_descr[1]; 133 void **var_table_begin = lib_descr[2]; 134 void **var_table_end = lib_descr[3]; 135 136 /* The func table contains only addresses, the var table contains addresses 137 and corresponding sizes. */ 138 int num_funcs = func_table_end - func_table_begin; 139 int num_vars = (var_table_end - var_table_begin) / 2; 140 TRACE ("(num_funcs = %d, num_vars = %d)", num_funcs, num_vars); 141 142 VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host }; 143 vd1[0].ptr = &num_funcs; 144 vd1[0].size = sizeof (num_funcs); 145 vd1[1].ptr = &num_vars; 146 vd1[1].size = sizeof (num_vars); 147 VarDesc2 vd2[2] = { { "num_funcs", 0 }, { "num_vars", 0 } }; 148 149 __offload_target_enter (ofldt, 2, vd1, vd2); 150 __offload_target_leave (ofldt); 151} 152 153/* Part 2: Send the table with addresses to host. */ 154static void 155__offload_target_table_p2 (OFFLOAD ofldt) 156{ 157 void ***lib_descr = (void ***) last_loaded_library; 158 void **func_table_begin = lib_descr[0]; 159 void **func_table_end = lib_descr[1]; 160 void **var_table_begin = lib_descr[2]; 161 void **var_table_end = lib_descr[3]; 162 163 int num_funcs = func_table_end - func_table_begin; 164 int num_vars = (var_table_end - var_table_begin) / 2; 165 int table_size = (num_funcs + 2 * num_vars) * sizeof (void *); 166 void **table = (void **) malloc (table_size); 167 TRACE ("(table_size = %d)", table_size); 168 169 VarDesc vd1; 170 vd1 = vd_tgt2host; 171 vd1.ptr = table; 172 vd1.size = table_size; 173 VarDesc2 vd2 = { "table", 0 }; 174 175 __offload_target_enter (ofldt, 1, &vd1, &vd2); 176 177 void **p; 178 int i = 0; 179 for (p = func_table_begin; p < func_table_end; p++, i++) 180 table[i] = *p; 181 182 for (p = var_table_begin; p < var_table_end; p++, i++) 183 table[i] = *p; 184 185 __offload_target_leave (ofldt); 186 free (table); 187} 188 189/* Allocate size bytes and send a pointer to the allocated memory to host. */ 190static void 191__offload_target_alloc (OFFLOAD ofldt) 192{ 193 size_t size = 0; 194 void *ptr = NULL; 195 196 VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host }; 197 vd1[0].ptr = &size; 198 vd1[0].size = sizeof (size); 199 vd1[1].ptr = &ptr; 200 vd1[1].size = sizeof (void *); 201 VarDesc2 vd2[2] = { { "size", 0 }, { "ptr", 0 } }; 202 203 __offload_target_enter (ofldt, 2, vd1, vd2); 204 ptr = malloc (size); 205 TRACE ("(size = %d): ptr = %p", size, ptr); 206 __offload_target_leave (ofldt); 207} 208 209/* Free the memory space pointed to by ptr. */ 210static void 211__offload_target_free (OFFLOAD ofldt) 212{ 213 void *ptr = 0; 214 215 VarDesc vd1 = vd_host2tgt; 216 vd1.ptr = &ptr; 217 vd1.size = sizeof (void *); 218 VarDesc2 vd2 = { "ptr", 0 }; 219 220 __offload_target_enter (ofldt, 1, &vd1, &vd2); 221 TRACE ("(ptr = %p)", ptr); 222 free (ptr); 223 __offload_target_leave (ofldt); 224} 225 226/* Receive var_size bytes from host and store to var_ptr. 227 Part 1: Receive var_ptr and var_size from host. */ 228static void 229__offload_target_host2tgt_p1 (OFFLOAD ofldt) 230{ 231 void *var_ptr = NULL; 232 size_t var_size = 0; 233 234 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt }; 235 vd1[0].ptr = &var_ptr; 236 vd1[0].size = sizeof (void *); 237 vd1[1].ptr = &var_size; 238 vd1[1].size = sizeof (var_size); 239 VarDesc2 vd2[2] = { { "var_ptr", 0 }, { "var_size", 0 } }; 240 241 __offload_target_enter (ofldt, 2, vd1, vd2); 242 TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size); 243 last_var_ptr = var_ptr; 244 last_var_size = var_size; 245 __offload_target_leave (ofldt); 246} 247 248/* Part 2: Receive the data from host. */ 249static void 250__offload_target_host2tgt_p2 (OFFLOAD ofldt) 251{ 252 TRACE ("(last_var_ptr = %p, last_var_size = %d)", 253 last_var_ptr, last_var_size); 254 255 VarDesc vd1 = vd_host2tgt; 256 vd1.ptr = last_var_ptr; 257 vd1.size = last_var_size; 258 VarDesc2 vd2 = { "var", 0 }; 259 260 __offload_target_enter (ofldt, 1, &vd1, &vd2); 261 __offload_target_leave (ofldt); 262} 263 264/* Send var_size bytes from var_ptr to host. 265 Part 1: Receive var_ptr and var_size from host. */ 266static void 267__offload_target_tgt2host_p1 (OFFLOAD ofldt) 268{ 269 void *var_ptr = NULL; 270 size_t var_size = 0; 271 272 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt }; 273 vd1[0].ptr = &var_ptr; 274 vd1[0].size = sizeof (void *); 275 vd1[1].ptr = &var_size; 276 vd1[1].size = sizeof (var_size); 277 VarDesc2 vd2[2] = { { "var_ptr", 0 }, { "var_size", 0 } }; 278 279 __offload_target_enter (ofldt, 2, vd1, vd2); 280 TRACE ("(var_ptr = %p, var_size = %d)", var_ptr, var_size); 281 last_var_ptr = var_ptr; 282 last_var_size = var_size; 283 __offload_target_leave (ofldt); 284} 285 286/* Part 2: Send the data to host. */ 287static void 288__offload_target_tgt2host_p2 (OFFLOAD ofldt) 289{ 290 TRACE ("(last_var_ptr = %p, last_var_size = %d)", 291 last_var_ptr, last_var_size); 292 293 VarDesc vd1 = vd_tgt2host; 294 vd1.ptr = last_var_ptr; 295 vd1.size = last_var_size; 296 VarDesc2 vd2 = { "var", 0 }; 297 298 __offload_target_enter (ofldt, 1, &vd1, &vd2); 299 __offload_target_leave (ofldt); 300} 301 302/* Call offload function by the address fn_ptr and pass vars_ptr to it. */ 303static void 304__offload_target_run (OFFLOAD ofldt) 305{ 306 void *fn_ptr; 307 void *vars_ptr; 308 309 VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt }; 310 vd1[0].ptr = &fn_ptr; 311 vd1[0].size = sizeof (void *); 312 vd1[1].ptr = &vars_ptr; 313 vd1[1].size = sizeof (void *); 314 VarDesc2 vd2[2] = { { "fn_ptr", 0 }, { "vars_ptr", 0 } }; 315 316 __offload_target_enter (ofldt, 2, vd1, vd2); 317 TRACE ("(fn_ptr = %p, vars_ptr = %p)", fn_ptr, vars_ptr); 318 void (*fn)(void *) = (void (*)(void *)) fn_ptr; 319 fn (vars_ptr); 320 __offload_target_leave (ofldt); 321} 322 323 324/* This should be called from every library with offloading. */ 325extern "C" void 326target_register_lib (const void *target_table) 327{ 328 TRACE ("(target_table = %p { %p, %p, %p, %p })", target_table, 329 ((void **) target_table)[0], ((void **) target_table)[1], 330 ((void **) target_table)[2], ((void **) target_table)[3]); 331 332 last_loaded_library = (void *) target_table; 333} 334 335/* Use __offload_target_main from liboffload. */ 336int 337main (int argc, char **argv) 338{ 339 __offload_target_main (); 340 return 0; 341} 342 343 344/* Register offload_target_main's functions in the liboffload. */ 345 346struct Entry { 347 const char *name; 348 void *func; 349}; 350 351#define REGISTER(f) \ 352extern "C" const Entry __offload_target_##f##_$entry \ 353__attribute__ ((section(".OffloadEntryTable."))) = { \ 354 "__offload_target_"#f, \ 355 (void *) __offload_target_##f \ 356} 357REGISTER (init_proc); 358REGISTER (table_p1); 359REGISTER (table_p2); 360REGISTER (alloc); 361REGISTER (free); 362REGISTER (host2tgt_p1); 363REGISTER (host2tgt_p2); 364REGISTER (tgt2host_p1); 365REGISTER (tgt2host_p2); 366REGISTER (run); 367#undef REGISTER 368