Fortran] Use proper type for hidden is-present argument
[gcc.git] / liboffloadmic / runtime / offload_table.cpp
1 /*
2 Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of Intel Corporation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30
31 #include "offload_table.h"
32 #include "offload_common.h"
33
34 // Offload Library versioning
35 // We initialize version to OFFLOAD_VERSION_16
36 // 15.0 application downgrades this to 1500 for MYO to use the older version.
37 // 15.0 pragma works without needing version-specific code.
38 // 16.0-U2 added a call from ofldbegin.cpp to set the version explicitly.
39 // Pre-16.0-U2 application will find pre-initialized version number as 1600.
40 // Post 16.0-U2 application will set its own version explicitly.
41 int offload_version = OFFLOAD_VERSION_16;
42 int offload_version_count = 0;
43
44 #if !HOST_LIBRARY
45 // Predefined offload entries
46 extern void omp_set_num_threads_lrb(void*);
47 extern void omp_get_max_threads_lrb(void*);
48 extern void omp_get_num_procs_lrb(void*);
49 extern void omp_set_dynamic_lrb(void*);
50 extern void omp_get_dynamic_lrb(void*);
51 extern void omp_set_nested_lrb(void*);
52 extern void omp_get_nested_lrb(void*);
53 extern void omp_set_schedule_lrb(void*);
54 extern void omp_get_schedule_lrb(void*);
55
56 extern void omp_init_lock_lrb(void*);
57 extern void omp_destroy_lock_lrb(void*);
58 extern void omp_set_lock_lrb(void*);
59 extern void omp_unset_lock_lrb(void*);
60 extern void omp_test_lock_lrb(void*);
61
62 extern void omp_init_nest_lock_lrb(void*);
63 extern void omp_destroy_nest_lock_lrb(void*);
64 extern void omp_set_nest_lock_lrb(void*);
65 extern void omp_unset_nest_lock_lrb(void*);
66 extern void omp_test_nest_lock_lrb(void*);
67
68 // OpenMP 4.5 APIs
69 extern void omp_target_alloc_target(void*);
70 extern void omp_target_free_target(void*);
71 extern void omp_target_memcpy_target(void*);
72 extern void omp_target_memcpy_rect_target(void*);
73
74 // Predefined entries on the target side
75 static FuncTable::Entry predefined_entries[] = {
76 "omp_set_num_threads_target",
77 (void*) &omp_set_num_threads_lrb,
78 "omp_get_max_threads_target",
79 (void*) &omp_get_max_threads_lrb,
80 "omp_get_num_procs_target",
81 (void*) &omp_get_num_procs_lrb,
82 "omp_set_dynamic_target",
83 (void*) &omp_set_dynamic_lrb,
84 "omp_get_dynamic_target",
85 (void*) &omp_get_dynamic_lrb,
86 "omp_set_nested_target",
87 (void*) &omp_set_nested_lrb,
88 "omp_get_nested_target",
89 (void*) &omp_get_nested_lrb,
90 "omp_set_schedule_target",
91 (void*) &omp_set_schedule_lrb,
92 "omp_get_schedule_target",
93 (void*) &omp_get_schedule_lrb,
94
95 "omp_init_lock_target",
96 (void*) &omp_init_lock_lrb,
97 "omp_destroy_lock_target",
98 (void*) &omp_destroy_lock_lrb,
99 "omp_set_lock_target",
100 (void*) &omp_set_lock_lrb,
101 "omp_unset_lock_target",
102 (void*) &omp_unset_lock_lrb,
103 "omp_test_lock_target",
104 (void*) &omp_test_lock_lrb,
105
106 "omp_init_nest_lock_target",
107 (void*) &omp_init_nest_lock_lrb,
108 "omp_destroy_nest_lock_target",
109 (void*) &omp_destroy_nest_lock_lrb,
110 "omp_set_nest_lock_target",
111 (void*) &omp_set_nest_lock_lrb,
112 "omp_unset_nest_lock_target",
113 (void*) &omp_unset_nest_lock_lrb,
114 "omp_test_nest_lock_target",
115 (void*) &omp_test_nest_lock_lrb,
116
117 "omp_target_alloc_target",
118 (void*) &omp_target_alloc_target,
119 "omp_target_free_target",
120 (void*) &omp_target_free_target,
121 "omp_target_memcpy_target",
122 (void*) &omp_target_memcpy_target,
123 "omp_target_memcpy_rect_target",
124 (void*) &omp_target_memcpy_rect_target,
125
126 (const char*) -1,
127 (void*) -1
128 };
129
130 static FuncList::Node predefined_table = {
131 { predefined_entries, -1 },
132 0, 0
133 };
134
135 // Entry table
136 FuncList __offload_entries(&predefined_table);
137 #else
138 FuncList __offload_entries;
139 #endif // !HOST_LIBRARY
140
141 extern "C" {
142
143 // Set library version
144 void __offload_set_version(int v)
145 {
146 offload_version_count++;
147 if (offload_version_count == 1)
148 {
149 offload_version = v;
150 }
151 else
152 {
153 // Mix of versions is not supported
154 if (v != offload_version)
155 {
156 LIBOFFLOAD_ERROR(c_mixed_versions);
157 exit(1);
158 }
159 }
160 }
161
162 } // extern "C"
163 // Function table. No predefined entries.
164 FuncList __offload_funcs;
165
166 // Var table
167 VarList __offload_vars;
168
169 // Given the function name returns the associtated function pointer
170 const void* FuncList::find_addr(const char *name)
171 {
172 const void* func = 0;
173
174 m_lock.lock();
175
176 for (Node *n = m_head; n != 0; n = n->next) {
177 for (const Table::Entry *e = n->table.entries;
178 e->name != (const char*) -1; e++) {
179 if (e->name != 0 && strcmp(e->name, name) == 0) {
180 func = e->func;
181 break;
182 }
183 }
184 }
185
186 m_lock.unlock();
187
188 return func;
189 }
190
191 // Given the function pointer returns the associtated function name
192 const char* FuncList::find_name(const void *func)
193 {
194 const char* name = 0;
195
196 m_lock.lock();
197
198 for (Node *n = m_head; n != 0; n = n->next) {
199 for (const Table::Entry *e = n->table.entries;
200 e->name != (const char*) -1; e++) {
201 if (e->func == func) {
202 name = e->name;
203 break;
204 }
205 }
206 }
207
208 m_lock.unlock();
209
210 return name;
211 }
212
213 // Returns max name length from all tables
214 int64_t FuncList::max_name_length(void)
215 {
216 if (m_max_name_len < 0) {
217 m_lock.lock();
218
219 m_max_name_len = 0;
220 for (Node *n = m_head; n != 0; n = n->next) {
221 if (n->table.max_name_len < 0) {
222 n->table.max_name_len = 0;
223
224 // calculate max name length in a single table
225 for (const Table::Entry *e = n->table.entries;
226 e->name != (const char*) -1; e++) {
227 if (e->name != 0) {
228 size_t len = strlen(e->name) + 1;
229 if (n->table.max_name_len < len) {
230 n->table.max_name_len = len;
231 }
232 }
233 }
234 }
235
236 // select max from all tables
237 if (m_max_name_len < n->table.max_name_len) {
238 m_max_name_len = n->table.max_name_len;
239 }
240 }
241
242 m_lock.unlock();
243 }
244 return m_max_name_len;
245 }
246
247 // Debugging dump
248 void FuncList::dump(void)
249 {
250 OFFLOAD_DEBUG_TRACE(2, "Function table:\n");
251
252 m_lock.lock();
253
254 for (Node *n = m_head; n != 0; n = n->next) {
255 for (const Table::Entry *e = n->table.entries;
256 e->name != (const char*) -1; e++) {
257 if (e->name != 0) {
258 OFFLOAD_DEBUG_TRACE(2, "%p %s\n", e->func, e->name);
259 }
260 }
261 }
262
263 m_lock.unlock();
264 }
265
266 // Debugging dump
267 void VarList::dump(void)
268 {
269 OFFLOAD_DEBUG_TRACE(2, "Var table:\n");
270
271 m_lock.lock();
272
273 for (Node *n = m_head; n != 0; n = n->next) {
274 for (const Table::Entry *e = n->table.entries;
275 e->name != (const char*) -1; e++) {
276 if (e->name != 0) {
277 #if HOST_LIBRARY
278 OFFLOAD_DEBUG_TRACE(2, "%s %p %ld\n", e->name, e->addr,
279 e->size);
280 #else // HOST_LIBRARY
281 OFFLOAD_DEBUG_TRACE(2, "%s %p\n", e->name, e->addr);
282 #endif // HOST_LIBRARY
283 }
284 }
285 }
286
287 m_lock.unlock();
288 }
289
290 //
291 int64_t VarList::table_size(int64_t &nelems)
292 {
293 int64_t length = 0;
294
295 nelems = 0;
296
297 // calculate string table size and number of elements
298 for (Node *n = m_head; n != 0; n = n->next) {
299 for (const Table::Entry *e = n->table.entries;
300 e->name != (const char*) -1; e++) {
301 if (e->name != 0) {
302 length += strlen(e->name) + 1;
303 nelems++;
304 }
305 }
306 }
307
308 return nelems * sizeof(BufEntry) + length;
309 }
310
311 // copy table to the gven buffer
312 void VarList::table_copy(void *buf, int64_t nelems)
313 {
314 BufEntry* elems = static_cast<BufEntry*>(buf);
315 char* names = reinterpret_cast<char*>(elems + nelems);
316
317 // copy entries to buffer
318 for (Node *n = m_head; n != 0; n = n->next) {
319 for (const Table::Entry *e = n->table.entries;
320 e->name != (const char*) -1; e++) {
321 if (e->name != 0) {
322 // name field contains offset to the name from the beginning
323 // of the buffer
324 elems->name = names - static_cast<char*>(buf);
325 elems->addr = reinterpret_cast<intptr_t>(e->addr);
326
327 // copy name to string table
328 const char *name = e->name;
329 while ((*names++ = *name++) != '\0');
330
331 elems++;
332 }
333 }
334 }
335 }
336
337 // patch name offsets in a buffer
338 void VarList::table_patch_names(void *buf, int64_t nelems)
339 {
340 BufEntry* elems = static_cast<BufEntry*>(buf);
341 for (int i = 0; i < nelems; i++) {
342 elems[i].name += reinterpret_cast<intptr_t>(buf);
343 }
344 }
345
346 #if HOST_LIBRARY
347 // 16.0 and earlier compilers used the following VarTable
348 struct OldVarTable {
349 const char* name;
350 void* addr;
351 // uint64_t var_alloc_type missing in 16.0 and earlier
352 uint64_t size;
353 };
354
355 static void convert_OldVarTable_to_NewVarTable(VarList::Node *vt_start)
356 {
357 int table_size = 0;
358 char * new_var_table;
359 OldVarTable *old_var_table;
360
361 OFFLOAD_DEBUG_TRACE(2,
362 "Converting old var table to new var table to support backward compatiblity\n");
363
364 // Calculate size of memory to be malloced
365 old_var_table = (OldVarTable *) vt_start->table.entries;
366 while (old_var_table->name != (const char*) -1) {
367 table_size++;
368 old_var_table++;
369 }
370
371 if (table_size != 0) {
372 // Add 1 to table_size for end of table signature
373 VarTable::Entry *new_var_table =
374 new VarTable::Entry[table_size+1];
375
376 if (new_var_table == NULL)
377 LIBOFFLOAD_ERROR(c_malloc);
378
379 old_var_table = (OldVarTable *) vt_start->table.entries;
380
381 // Update VarList with new table
382 vt_start->table.entries = new_var_table;
383
384 // Fix up the new table value from old table
385 for (int i=0; i< table_size; i++) {
386 new_var_table->name = old_var_table->name;
387 new_var_table->addr = old_var_table->addr;
388 new_var_table->size = old_var_table->size;
389 // Assign value of 0 for the missing field.
390 // Implying it is neither IMPLICIT or LINK variable as
391 // they were not supported in earlier compilers
392 new_var_table->var_alloc_type = 0;
393 old_var_table++;
394 new_var_table++;
395 }
396 new_var_table->name = (const char *)-1;
397 }
398
399 }
400 #endif //HOST_LIBRARY
401
402 // Adds given list element to the global lookup table list
403 extern "C" void __offload_register_tables(
404 FuncList::Node *entry_table,
405 FuncList::Node *func_table,
406 VarList::Node *var_table
407 )
408 {
409 OFFLOAD_DEBUG_TRACE(2, "Registering offload function entry table %p\n",
410 entry_table);
411 __offload_entries.add_table(entry_table);
412
413 OFFLOAD_DEBUG_TRACE(2, "Registering function table %p\n", func_table);
414 __offload_funcs.add_table(func_table);
415
416 OFFLOAD_DEBUG_TRACE(2, "Registering var table %p\n", var_table);
417
418 // Compiler earlier than 17.0 used a different var_table.
419 // Convert the old table to new var_table format.
420 // Only the host table for LINUX has changed.
421 #ifndef TARGET_WINNT
422 #if HOST_LIBRARY
423 if (offload_version < OFFLOAD_VERSION_17) {
424 convert_OldVarTable_to_NewVarTable(var_table);
425 }
426 #endif
427 #endif
428 __offload_vars.add_table(var_table);
429 }
430
431 // Removes given list element from the global lookup table list
432 extern "C" void __offload_unregister_tables(
433 FuncList::Node *entry_table,
434 FuncList::Node *func_table,
435 VarList::Node *var_table
436 )
437 {
438 OFFLOAD_DEBUG_TRACE(2, "Unregistering offload function entry table %p\n",
439 entry_table);
440 __offload_entries.remove_table(entry_table);
441
442 OFFLOAD_DEBUG_TRACE(2, "Unregistering function table %p\n", func_table);
443 __offload_funcs.remove_table(func_table);
444
445 OFFLOAD_DEBUG_TRACE(2, "Unregistering var table %p\n", var_table);
446 #ifndef TARGET_WINNT
447 #if HOST_LIBRARY
448 if (offload_version < OFFLOAD_VERSION_17) {
449 // Free the malloced var_table created for backward compatiblity
450 delete var_table->table.entries;
451 }
452 #endif
453 #endif
454 __offload_vars.remove_table(var_table);
455 }
456
457 #ifdef MYO_SUPPORT
458
459 MYOVarTableList __offload_myo_var_tables;
460 MYOVarTableList __offload_myo_vtable_tables;
461 MYOFuncTableList __offload_myo_func_tables;
462 MYOInitTableList __offload_myo_init_tables;
463
464 // Debugging dump
465 void MYOVarTableList::dump(void)
466 {
467 OFFLOAD_DEBUG_TRACE(2, "MYO Var tables:\n");
468
469 m_lock.lock();
470
471 for (Node *n = m_head; n != 0; n = n->next) {
472 OFFLOAD_DEBUG_TRACE(2, " MYO Var table:\n");
473 for (const Table::Entry *e = n->table.entries;
474 e->varName != MYO_TABLE_END_MARKER(); e++) {
475 #ifdef TARGET_WINNT
476 if (e->varName == 0) {
477 continue;
478 }
479 #endif // TARGET_WINNT
480 OFFLOAD_DEBUG_TRACE(2, " %s %p\n",
481 e->varName, e->sharedAddr);
482 }
483 }
484
485 m_lock.unlock();
486 }
487
488 // check if any shared variables
489 bool MYOVarTableList::is_empty()
490 {
491 OFFLOAD_DEBUG_TRACE(3, "Are MYO Var tables empty?\n");
492
493 m_lock.lock();
494
495 for (Node *n = m_head; n != 0; n = n->next) {
496 for (const Table::Entry *e = n->table.entries;
497 e->varName != MYO_TABLE_END_MARKER(); e++) {
498 #ifdef TARGET_WINNT
499 if (e->varName == 0) {
500 continue;
501 }
502 #endif // TARGET_WINNT
503 m_lock.unlock();
504 OFFLOAD_DEBUG_TRACE(3, "No\n");
505 return false;
506 }
507 }
508
509 m_lock.unlock();
510 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
511 return true;
512 }
513
514 void MYOFuncTableList::dump(void)
515 {
516 OFFLOAD_DEBUG_TRACE(2, "MYO Func tables:\n");
517
518 m_lock.lock();
519
520 for (Node *n = m_head; n != 0; n = n->next) {
521 OFFLOAD_DEBUG_TRACE(2, " MYO Func table:\n");
522 for (const Table::Entry *e = n->table.entries;
523 e->funcName != MYO_TABLE_END_MARKER(); e++) {
524 #ifdef TARGET_WINNT
525 if (e->funcName == 0) {
526 continue;
527 }
528 #endif // TARGET_WINNT
529 #if HOST_LIBRARY
530 OFFLOAD_DEBUG_TRACE(2, " %s %p %p\n",
531 e->funcName, e->funcAddr, e->localThunkAddr);
532 #else // HOST_LIBRARY
533 OFFLOAD_DEBUG_TRACE(2, " %s %p %p %p\n",
534 e->funcName, e->funcAddr, e->wrapFuncAddr, e->localThunkAddr);
535 #endif // HOST_LIBRARY
536 }
537 }
538
539 m_lock.unlock();
540 }
541
542 // check if any shared functions
543 bool MYOFuncTableList::is_empty()
544 {
545 OFFLOAD_DEBUG_TRACE(3, "Are MYO Func tables empty?\n");
546
547 m_lock.lock();
548
549 for (Node *n = m_head; n != 0; n = n->next) {
550 int count = 0;
551 for (const Table::Entry *e = n->table.entries;
552 e->funcName != MYO_TABLE_END_MARKER(); e++) {
553 #ifdef TARGET_WINNT
554 if (e->funcName == 0) {
555 continue;
556 }
557 #endif // TARGET_WINNT
558 count++;
559 if (count > 1) {
560 m_lock.unlock();
561 OFFLOAD_DEBUG_TRACE(3, "No\n");
562 return false;
563 }
564 }
565 }
566
567 m_lock.unlock();
568 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
569 return true;
570 }
571
572 void MYOInitTableList::dump(void)
573 {
574 OFFLOAD_DEBUG_TRACE(2, "MYO Init tables:\n");
575
576 m_lock.lock();
577
578 for (Node *n = m_head; n != 0; n = n->next) {
579 OFFLOAD_DEBUG_TRACE(2, " MYO Init table:\n");
580 for (const Table::Entry *e = n->table.entries;
581 #ifdef TARGET_WINNT
582 e->funcName != MYO_TABLE_END_MARKER(); e++) {
583 if (e->funcName == 0) {
584 continue;
585 }
586 OFFLOAD_DEBUG_TRACE(2, " %s %p\n", e->funcName, e->func);
587 #else // TARGET_WINNT
588 e->func != 0; e++) {
589 OFFLOAD_DEBUG_TRACE(2, " %p\n", e->func);
590 #endif // TARGET_WINNT
591 }
592 }
593
594 m_lock.unlock();
595 }
596
597 // check if any shared functions
598 bool MYOInitTableList::is_empty()
599 {
600 OFFLOAD_DEBUG_TRACE(3, "Are MYO Init tables empty?\n");
601
602 m_lock.lock();
603
604 for (Node *n = m_head; n != 0; n = n->next) {
605 for (const Table::Entry *e = n->table.entries;
606 #ifdef TARGET_WINNT
607 e->funcName != MYO_TABLE_END_MARKER(); e++) {
608 if (e->funcName == 0) {
609 continue;
610 }
611 m_lock.unlock();
612 OFFLOAD_DEBUG_TRACE(3, "No\n");
613 return false;
614 #else // TARGET_WINNT
615 e->func != 0; e++) {
616 #endif // TARGET_WINNT
617 }
618 }
619
620 m_lock.unlock();
621 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
622 return true;
623 }
624
625 extern "C" void __offload_myoRegisterTables1(
626 MYOInitTableList::Node *init_table,
627 MYOVarTableList::Node *shared_table,
628 MYOVarTableList::Node *shared_vtable,
629 MYOFuncTableList::Node *fptr_table
630 )
631 {
632 OFFLOAD_DEBUG_TRACE(2, "Registering MYO shared var table %p\n",
633 shared_table);
634 __offload_myo_var_tables.add_table(shared_table);
635
636 OFFLOAD_DEBUG_TRACE(2, "Registering MYO shared vtable table %p\n",
637 shared_vtable);
638 __offload_myo_vtable_tables.add_table(shared_vtable);
639
640 OFFLOAD_DEBUG_TRACE(2, "Registering MYO function table %p\n", fptr_table);
641 __offload_myo_func_tables.add_table(fptr_table);
642
643 OFFLOAD_DEBUG_TRACE(2, "Registering MYO init table %p\n", init_table);
644 __offload_myo_init_tables.add_table(init_table);
645 }
646
647 extern "C" void __offload_myoRemoveTables(
648 MYOInitTableList::Node *init_table,
649 MYOVarTableList::Node *shared_table,
650 MYOVarTableList::Node *shared_vtable,
651 MYOFuncTableList::Node *fptr_table
652 )
653 {
654 OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
655
656 OFFLOAD_DEBUG_TRACE(2, "Removing MYO shared var table %p\n",
657 shared_table);
658 __offload_myo_var_tables.remove_table(shared_table);
659
660 OFFLOAD_DEBUG_TRACE(2, "Removing MYO shared vtable table %p\n",
661 shared_vtable);
662 __offload_myo_vtable_tables.remove_table(shared_vtable);
663
664 OFFLOAD_DEBUG_TRACE(2, "Removing MYO function table %p\n", fptr_table);
665 __offload_myo_func_tables.remove_table(fptr_table);
666
667 OFFLOAD_DEBUG_TRACE(2, "Removing MYO init table %p\n", init_table);
668 __offload_myo_init_tables.remove_table(init_table);
669 }
670
671 #endif // MYO_SUPPORT