2018-01-12 Richard Biener <rguenther@suse.de>
[official-gcc.git] / liboffloadmic / runtime / offload_table.cpp
blob09c4d206e58df51670a493582a798d93c8800495
1 /*
2 Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved.
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
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.
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.
31 #include "offload_table.h"
32 #include "offload_common.h"
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;
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*);
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*);
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*);
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*);
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,
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,
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,
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,
126 (const char*) -1,
127 (void*) -1
130 static FuncList::Node predefined_table = {
131 { predefined_entries, -1 },
132 0, 0
135 // Entry table
136 FuncList __offload_entries(&predefined_table);
137 #else
138 FuncList __offload_entries;
139 #endif // !HOST_LIBRARY
141 extern "C" {
143 // Set library version
144 void __offload_set_version(int v)
146 offload_version_count++;
147 if (offload_version_count == 1)
149 offload_version = v;
151 else
153 // Mix of versions is not supported
154 if (v != offload_version)
156 LIBOFFLOAD_ERROR(c_mixed_versions);
157 exit(1);
162 } // extern "C"
163 // Function table. No predefined entries.
164 FuncList __offload_funcs;
166 // Var table
167 VarList __offload_vars;
169 // Given the function name returns the associtated function pointer
170 const void* FuncList::find_addr(const char *name)
172 const void* func = 0;
174 m_lock.lock();
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;
186 m_lock.unlock();
188 return func;
191 // Given the function pointer returns the associtated function name
192 const char* FuncList::find_name(const void *func)
194 const char* name = 0;
196 m_lock.lock();
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;
208 m_lock.unlock();
210 return name;
213 // Returns max name length from all tables
214 int64_t FuncList::max_name_length(void)
216 if (m_max_name_len < 0) {
217 m_lock.lock();
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;
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;
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;
242 m_lock.unlock();
244 return m_max_name_len;
247 // Debugging dump
248 void FuncList::dump(void)
250 OFFLOAD_DEBUG_TRACE(2, "Function table:\n");
252 m_lock.lock();
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);
263 m_lock.unlock();
266 // Debugging dump
267 void VarList::dump(void)
269 OFFLOAD_DEBUG_TRACE(2, "Var table:\n");
271 m_lock.lock();
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
287 m_lock.unlock();
291 int64_t VarList::table_size(int64_t &nelems)
293 int64_t length = 0;
295 nelems = 0;
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++;
308 return nelems * sizeof(BufEntry) + length;
311 // copy table to the gven buffer
312 void VarList::table_copy(void *buf, int64_t nelems)
314 BufEntry* elems = static_cast<BufEntry*>(buf);
315 char* names = reinterpret_cast<char*>(elems + nelems);
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);
327 // copy name to string table
328 const char *name = e->name;
329 while ((*names++ = *name++) != '\0');
331 elems++;
337 // patch name offsets in a buffer
338 void VarList::table_patch_names(void *buf, int64_t nelems)
340 BufEntry* elems = static_cast<BufEntry*>(buf);
341 for (int i = 0; i < nelems; i++) {
342 elems[i].name += reinterpret_cast<intptr_t>(buf);
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;
355 static void convert_OldVarTable_to_NewVarTable(VarList::Node *vt_start)
357 int table_size = 0;
358 char * new_var_table;
359 OldVarTable *old_var_table;
361 OFFLOAD_DEBUG_TRACE(2,
362 "Converting old var table to new var table to support backward compatiblity\n");
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++;
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];
376 if (new_var_table == NULL)
377 LIBOFFLOAD_ERROR(c_malloc);
379 old_var_table = (OldVarTable *) vt_start->table.entries;
381 // Update VarList with new table
382 vt_start->table.entries = new_var_table;
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++;
396 new_var_table->name = (const char *)-1;
400 #endif //HOST_LIBRARY
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
409 OFFLOAD_DEBUG_TRACE(2, "Registering offload function entry table %p\n",
410 entry_table);
411 __offload_entries.add_table(entry_table);
413 OFFLOAD_DEBUG_TRACE(2, "Registering function table %p\n", func_table);
414 __offload_funcs.add_table(func_table);
416 OFFLOAD_DEBUG_TRACE(2, "Registering var table %p\n", var_table);
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);
426 #endif
427 #endif
428 __offload_vars.add_table(var_table);
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
438 OFFLOAD_DEBUG_TRACE(2, "Unregistering offload function entry table %p\n",
439 entry_table);
440 __offload_entries.remove_table(entry_table);
442 OFFLOAD_DEBUG_TRACE(2, "Unregistering function table %p\n", func_table);
443 __offload_funcs.remove_table(func_table);
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;
452 #endif
453 #endif
454 __offload_vars.remove_table(var_table);
457 #ifdef MYO_SUPPORT
459 MYOVarTableList __offload_myo_var_tables;
460 MYOVarTableList __offload_myo_vtable_tables;
461 MYOFuncTableList __offload_myo_func_tables;
462 MYOInitTableList __offload_myo_init_tables;
464 // Debugging dump
465 void MYOVarTableList::dump(void)
467 OFFLOAD_DEBUG_TRACE(2, "MYO Var tables:\n");
469 m_lock.lock();
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;
479 #endif // TARGET_WINNT
480 OFFLOAD_DEBUG_TRACE(2, " %s %p\n",
481 e->varName, e->sharedAddr);
485 m_lock.unlock();
488 // check if any shared variables
489 bool MYOVarTableList::is_empty()
491 OFFLOAD_DEBUG_TRACE(3, "Are MYO Var tables empty?\n");
493 m_lock.lock();
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;
502 #endif // TARGET_WINNT
503 m_lock.unlock();
504 OFFLOAD_DEBUG_TRACE(3, "No\n");
505 return false;
509 m_lock.unlock();
510 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
511 return true;
514 void MYOFuncTableList::dump(void)
516 OFFLOAD_DEBUG_TRACE(2, "MYO Func tables:\n");
518 m_lock.lock();
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;
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
539 m_lock.unlock();
542 // check if any shared functions
543 bool MYOFuncTableList::is_empty()
545 OFFLOAD_DEBUG_TRACE(3, "Are MYO Func tables empty?\n");
547 m_lock.lock();
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;
557 #endif // TARGET_WINNT
558 count++;
559 if (count > 1) {
560 m_lock.unlock();
561 OFFLOAD_DEBUG_TRACE(3, "No\n");
562 return false;
567 m_lock.unlock();
568 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
569 return true;
572 void MYOInitTableList::dump(void)
574 OFFLOAD_DEBUG_TRACE(2, "MYO Init tables:\n");
576 m_lock.lock();
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;
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
594 m_lock.unlock();
597 // check if any shared functions
598 bool MYOInitTableList::is_empty()
600 OFFLOAD_DEBUG_TRACE(3, "Are MYO Init tables empty?\n");
602 m_lock.lock();
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;
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
620 m_lock.unlock();
621 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
622 return true;
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
632 OFFLOAD_DEBUG_TRACE(2, "Registering MYO shared var table %p\n",
633 shared_table);
634 __offload_myo_var_tables.add_table(shared_table);
636 OFFLOAD_DEBUG_TRACE(2, "Registering MYO shared vtable table %p\n",
637 shared_vtable);
638 __offload_myo_vtable_tables.add_table(shared_vtable);
640 OFFLOAD_DEBUG_TRACE(2, "Registering MYO function table %p\n", fptr_table);
641 __offload_myo_func_tables.add_table(fptr_table);
643 OFFLOAD_DEBUG_TRACE(2, "Registering MYO init table %p\n", init_table);
644 __offload_myo_init_tables.add_table(init_table);
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
654 OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
656 OFFLOAD_DEBUG_TRACE(2, "Removing MYO shared var table %p\n",
657 shared_table);
658 __offload_myo_var_tables.remove_table(shared_table);
660 OFFLOAD_DEBUG_TRACE(2, "Removing MYO shared vtable table %p\n",
661 shared_vtable);
662 __offload_myo_vtable_tables.remove_table(shared_vtable);
664 OFFLOAD_DEBUG_TRACE(2, "Removing MYO function table %p\n", fptr_table);
665 __offload_myo_func_tables.remove_table(fptr_table);
667 OFFLOAD_DEBUG_TRACE(2, "Removing MYO init table %p\n", init_table);
668 __offload_myo_init_tables.remove_table(init_table);
671 #endif // MYO_SUPPORT