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
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;
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*);
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
,
130 static FuncList::Node predefined_table
= {
131 { predefined_entries
, -1 },
136 FuncList
__offload_entries(&predefined_table
);
138 FuncList __offload_entries
;
139 #endif // !HOST_LIBRARY
143 // Set library version
144 void __offload_set_version(int v
)
146 offload_version_count
++;
147 if (offload_version_count
== 1)
153 // Mix of versions is not supported
154 if (v
!= offload_version
)
156 LIBOFFLOAD_ERROR(c_mixed_versions
);
163 // Function table. No predefined entries.
164 FuncList __offload_funcs
;
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;
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) {
191 // Given the function pointer returns the associtated function name
192 const char* FuncList::find_name(const void *func
)
194 const char* name
= 0;
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
) {
213 // Returns max name length from all tables
214 int64_t FuncList::max_name_length(void)
216 if (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
++) {
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
;
244 return m_max_name_len
;
248 void FuncList::dump(void)
250 OFFLOAD_DEBUG_TRACE(2, "Function table:\n");
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
++) {
258 OFFLOAD_DEBUG_TRACE(2, "%p %s\n", e
->func
, e
->name
);
267 void VarList::dump(void)
269 OFFLOAD_DEBUG_TRACE(2, "Var table:\n");
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
++) {
278 OFFLOAD_DEBUG_TRACE(2, "%s %p %ld\n", e
->name
, e
->addr
,
280 #else // HOST_LIBRARY
281 OFFLOAD_DEBUG_TRACE(2, "%s %p\n", e
->name
, e
->addr
);
282 #endif // HOST_LIBRARY
291 int64_t VarList::table_size(int64_t &nelems
)
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
++) {
302 length
+= strlen(e
->name
) + 1;
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
++) {
322 // name field contains offset to the name from the beginning
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');
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
);
347 // 16.0 and earlier compilers used the following VarTable
351 // uint64_t var_alloc_type missing in 16.0 and earlier
355 static void convert_OldVarTable_to_NewVarTable(VarList::Node
*vt_start
)
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) {
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;
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",
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.
423 if (offload_version
< OFFLOAD_VERSION_17
) {
424 convert_OldVarTable_to_NewVarTable(var_table
);
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",
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
);
448 if (offload_version
< OFFLOAD_VERSION_17
) {
449 // Free the malloced var_table created for backward compatiblity
450 delete var_table
->table
.entries
;
454 __offload_vars
.remove_table(var_table
);
459 MYOVarTableList __offload_myo_var_tables
;
460 MYOVarTableList __offload_myo_vtable_tables
;
461 MYOFuncTableList __offload_myo_func_tables
;
462 MYOInitTableList __offload_myo_init_tables
;
465 void MYOVarTableList::dump(void)
467 OFFLOAD_DEBUG_TRACE(2, "MYO Var tables:\n");
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
++) {
476 if (e
->varName
== 0) {
479 #endif // TARGET_WINNT
480 OFFLOAD_DEBUG_TRACE(2, " %s %p\n",
481 e
->varName
, e
->sharedAddr
);
488 // check if any shared variables
489 bool MYOVarTableList::is_empty()
491 OFFLOAD_DEBUG_TRACE(3, "Are MYO Var tables empty?\n");
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
++) {
499 if (e
->varName
== 0) {
502 #endif // TARGET_WINNT
504 OFFLOAD_DEBUG_TRACE(3, "No\n");
510 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
514 void MYOFuncTableList::dump(void)
516 OFFLOAD_DEBUG_TRACE(2, "MYO Func tables:\n");
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
++) {
525 if (e
->funcName
== 0) {
528 #endif // TARGET_WINNT
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
542 // check if any shared functions
543 bool MYOFuncTableList::is_empty()
545 OFFLOAD_DEBUG_TRACE(3, "Are MYO Func tables empty?\n");
549 for (Node
*n
= m_head
; n
!= 0; n
= n
->next
) {
551 for (const Table::Entry
*e
= n
->table
.entries
;
552 e
->funcName
!= MYO_TABLE_END_MARKER(); e
++) {
554 if (e
->funcName
== 0) {
557 #endif // TARGET_WINNT
561 OFFLOAD_DEBUG_TRACE(3, "No\n");
568 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
572 void MYOInitTableList::dump(void)
574 OFFLOAD_DEBUG_TRACE(2, "MYO Init tables:\n");
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
;
582 e
->funcName
!= MYO_TABLE_END_MARKER(); e
++) {
583 if (e
->funcName
== 0) {
586 OFFLOAD_DEBUG_TRACE(2, " %s %p\n", e
->funcName
, e
->func
);
587 #else // TARGET_WINNT
589 OFFLOAD_DEBUG_TRACE(2, " %p\n", e
->func
);
590 #endif // TARGET_WINNT
597 // check if any shared functions
598 bool MYOInitTableList::is_empty()
600 OFFLOAD_DEBUG_TRACE(3, "Are MYO Init tables empty?\n");
604 for (Node
*n
= m_head
; n
!= 0; n
= n
->next
) {
605 for (const Table::Entry
*e
= n
->table
.entries
;
607 e
->funcName
!= MYO_TABLE_END_MARKER(); e
++) {
608 if (e
->funcName
== 0) {
612 OFFLOAD_DEBUG_TRACE(3, "No\n");
614 #else // TARGET_WINNT
616 #endif // TARGET_WINNT
621 OFFLOAD_DEBUG_TRACE(3, "Yes\n");
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",
634 __offload_myo_var_tables
.add_table(shared_table
);
636 OFFLOAD_DEBUG_TRACE(2, "Registering MYO shared vtable table %p\n",
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",
658 __offload_myo_var_tables
.remove_table(shared_table
);
660 OFFLOAD_DEBUG_TRACE(2, "Removing MYO shared vtable table %p\n",
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