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 /*! \file
32     \brief Function and Variable tables used by the runtime library
33 */
34 
35 #ifndef OFFLOAD_TABLE_H_INCLUDED
36 #define OFFLOAD_TABLE_H_INCLUDED
37 
38 #include "offload_util.h"
39 
40 #define OFFLOAD_VERSION_16   1600
41 #define OFFLOAD_VERSION_17   1700
42 
43 // Template representing double linked list of tables
44 template <typename T> class TableList {
45 public:
46     // table type
47     typedef T Table;
48 
49     // List node
50     struct Node {
51         Table   table;
52         Node*   prev;
53         Node*   next;
54     };
55 
56 public:
m_head(node)57     explicit TableList(Node *node = 0) : m_head(node) {}
58 
add_table(Node * node)59     void add_table(Node *node) {
60         m_lock.lock();
61         if (m_head != 0) {
62             node->next = m_head;
63             m_head->prev = node;
64         }
65         m_head = node;
66 
67         m_lock.unlock();
68     }
69 
remove_table(Node * node)70     void remove_table(Node *node) {
71         if (node->next != 0) {
72             node->next->prev = node->prev;
73         }
74         if (node->prev != 0) {
75             node->prev->next = node->next;
76         }
77         if (m_head == node) {
78             m_head = node->next;
79         }
80     }
81 
82 protected:
83     Node*           m_head;
84     mutex_t         m_lock;
85 };
86 
87 // Function lookup table.
88 struct FuncTable {
89     //! Function table entry
90     /*! This table contains functions created from offload regions.   */
91     /*! Each entry consists of a pointer to the function's "key"
92         and the function address.                                     */
93     /*! Each shared library or executable may contain one such table. */
94     /*! The end of the table is marked with an entry whose name field
95         has value -1.                                                 */
96     struct Entry {
97         const char* name; //!< Name of the function
98         void*       func; //!< Address of the function
99     };
100 
101     // entries
102     const Entry *entries;
103 
104     // max name length
105     int64_t max_name_len;
106 };
107 
108 // Function table
109 class DLL_LOCAL FuncList : public TableList<FuncTable> {
110 public:
111     explicit FuncList(Node *node = 0) : TableList<Table>(node),
112                                         m_max_name_len(-1)
113     {}
114 
115     // add table to the list
add_table(Node * node)116     void add_table(Node *node) {
117         // recalculate max function name length
118         m_max_name_len = -1;
119 
120         // add table
121         TableList<Table>::add_table(node);
122     }
123 
124     // find function address for the given name
125     const void* find_addr(const char *name);
126 
127     // find function name for the given address
128     const char* find_name(const void *addr);
129 
130     // max name length from all tables in the list
131     int64_t max_name_length(void);
132 
133     // debug dump
134     void dump(void);
135 
136 private:
137     // max name length within from all tables
138     int64_t m_max_name_len;
139 };
140 
141 #define VAR_ALLOC_TYPE  uint64_t
142 #define OPENMP_IMPLICIT   1    // Compiler promoted openmp declare var
143                                // due to implicit use without openmp declare
144 #define OPENMP_LINK       2    // Openmp link clause in openmp declare
145 
146 #define IS_OPENMP_IMPLICIT(var_alloc_type)         (var_alloc_type & 1)
147 #define IS_OPENMP_LINK(var_alloc_type)             (var_alloc_type & 2)
148 #define IS_OPENMP_IMPLICIT_OR_LINK(var_alloc_type) (var_alloc_type & 3)
149 
150 // Table entry for static variables
151 struct VarTable {
152     //! Variable table entry
153     /*! This table contains statically allocated variables marked with
154         __declspec(target(mic) or #pragma omp declare target.           */
155     /*! Each entry consists of a pointer to the variable's "key",
156         the variable address and its size in bytes.                     */
157     /*! Because memory allocation is done from the host,
158         the MIC table does not need the size of the variable.           */
159     /*! Padding to make the table entry size a power of 2 is necessary
160         to avoid "holes" between table contributions from different object
161         files on Windows when debug information is specified with /Zi.  */
162     struct Entry {
163         const char* name; //!< Name of the variable
164         void*       addr; //!< Address of the variable
165 
166 #if HOST_LIBRARY
167         VAR_ALLOC_TYPE  var_alloc_type;
168         uint64_t    size;
169 #endif
170     };
171 
172     // Table terminated by an entry with name == -1
173     const Entry *entries;
174 };
175 
176 // List of var tables
177 class DLL_LOCAL VarList : public TableList<VarTable> {
178 public:
VarList()179     VarList() : TableList<Table>()
180     {}
181 
182     // debug dump
183     void dump();
184 
185 public:
186 
get_head()187     Node * get_head() {
188         return m_head;
189     }
190 
191 public:
192     // Entry representation in a copy buffer
193     struct BufEntry {
194         intptr_t name;
195         intptr_t addr;
196     };
197 
198     // Calculate the number of elements in the table and
199     // returns the size of buffer for the table
200     int64_t table_size(int64_t &nelems);
201 
202     // Copy table contents to given buffer. It is supposed to be large
203     // enough to hold all elements as string table.
204     void table_copy(void *buf, int64_t nelems);
205 
206     // Patch name offsets in a table after it's been copied to other side
207     static void table_patch_names(void *buf, int64_t nelems);
208 };
209 
210 DLL_LOCAL extern FuncList __offload_entries;
211 DLL_LOCAL extern FuncList __offload_funcs;
212 DLL_LOCAL extern VarList  __offload_vars;
213 
214 // Section names where the lookup tables are stored
215 #ifdef TARGET_WINNT
216 #define OFFLOAD_ENTRY_TABLE_SECTION_START   ".OffloadEntryTable$a"
217 #define OFFLOAD_ENTRY_TABLE_SECTION_END     ".OffloadEntryTable$z"
218 
219 #define OFFLOAD_FUNC_TABLE_SECTION_START    ".OffloadFuncTable$a"
220 #define OFFLOAD_FUNC_TABLE_SECTION_END      ".OffloadFuncTable$z"
221 
222 #define OFFLOAD_VAR_TABLE_SECTION_START     ".OffloadVarTable$a"
223 #define OFFLOAD_VAR_TABLE_SECTION_END       ".OffloadVarTable$z"
224 
225 #define OFFLOAD_CRTINIT_SECTION_START       ".CRT$XCT"
226 
227 #pragma section(OFFLOAD_CRTINIT_SECTION_START, read)
228 
229 #else  // TARGET_WINNT
230 
231 #define OFFLOAD_ENTRY_TABLE_SECTION_START   ".OffloadEntryTable."
232 #define OFFLOAD_ENTRY_TABLE_SECTION_END     ".OffloadEntryTable."
233 
234 #define OFFLOAD_FUNC_TABLE_SECTION_START    ".OffloadFuncTable."
235 #define OFFLOAD_FUNC_TABLE_SECTION_END      ".OffloadFuncTable."
236 
237 #define OFFLOAD_VAR_TABLE_SECTION_START     ".OffloadVarTable."
238 #define OFFLOAD_VAR_TABLE_SECTION_END       ".OffloadVarTable."
239 #endif // TARGET_WINNT
240 
241 #pragma section(OFFLOAD_ENTRY_TABLE_SECTION_START, read, write)
242 #pragma section(OFFLOAD_ENTRY_TABLE_SECTION_END, read, write)
243 
244 #pragma section(OFFLOAD_FUNC_TABLE_SECTION_START, read, write)
245 #pragma section(OFFLOAD_FUNC_TABLE_SECTION_END, read, write)
246 
247 #pragma section(OFFLOAD_VAR_TABLE_SECTION_START, read, write)
248 #pragma section(OFFLOAD_VAR_TABLE_SECTION_END, read, write)
249 
250 
251 // Set library version
252 extern "C" void __offload_set_version(int v);
253 
254 // register/unregister given tables
255 extern "C" void __offload_register_tables(
256     FuncList::Node *entry_table,
257     FuncList::Node *func_table,
258     VarList::Node *var_table
259 );
260 
261 extern "C" void __offload_unregister_tables(
262     FuncList::Node *entry_table,
263     FuncList::Node *func_table,
264     VarList::Node *var_table
265 );
266 
267 
268 #ifdef MYO_SUPPORT
269 
270 #include <myotypes.h>
271 #include <myoimpl.h>
272 #include <myo.h>
273 
274 #ifdef TARGET_WINNT
275 #define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(-1)
276 #else // TARGET_WINNT
277 #define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(0)
278 #endif // TARGET_WINNT
279 
280 // Host and Target-side MYO shared variable table entry layout
281 typedef MyoiSharedVarEntry SharedTableEntry;
282 
283 #if HOST_LIBRARY
284 
285 // Host-side MYO function table entry layout
286 typedef struct {
287     //! Function Name
288     const char *funcName;
289     //! Function Address
290     void *funcAddr;
291     //! Local Thunk Address
292     void *localThunkAddr;
293 #ifdef TARGET_WINNT
294     // Dummy to pad up to 32 bytes
295     void *dummy;
296 #endif // TARGET_WINNT
297 } FptrTableEntry;
298 
299 // Host-side MYO init routine table entry layout
300 typedef struct {
301 #ifdef TARGET_WINNT
302     // Dummy to pad up to 16 bytes
303     // Function Name
304     const char *funcName;
305 #endif // TARGET_WINNT
306     void (*func)(MyoArena);
307 } InitTableEntry;
308 
309 #else // HOST_LIBRARY
310 
311 // Target-side MYO function table entry layout
312 typedef MyoiTargetSharedFptrEntry   FptrTableEntry;
313 
314 // Target-side MYO init routine table entry layout
315 struct InitTableEntry {
316     void (*func)(void);
317 };
318 
319 #endif // HOST_LIBRARY
320 
321 #ifdef TARGET_WINNT
322 
323 #define OFFLOAD_MYO_SHARED_TABLE_SECTION_START          ".MyoSharedTable$a"
324 #define OFFLOAD_MYO_SHARED_TABLE_SECTION_END            ".MyoSharedTable$z"
325 
326 #define OFFLOAD_MYO_SHARED_VTABLE_SECTION_START         ".MyoSharedVTable$a"
327 #define OFFLOAD_MYO_SHARED_VTABLE_SECTION_END           ".MyoSharedVTable$z"
328 
329 #define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START     ".MyoSharedInitTable$a"
330 #define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END       ".MyoSharedInitTable$z"
331 
332 #define OFFLOAD_MYO_FPTR_TABLE_SECTION_START            ".MyoFptrTable$a"
333 #define OFFLOAD_MYO_FPTR_TABLE_SECTION_END              ".MyoFptrTable$z"
334 
335 #else  // TARGET_WINNT
336 
337 #define OFFLOAD_MYO_SHARED_TABLE_SECTION_START          ".MyoSharedTable."
338 #define OFFLOAD_MYO_SHARED_TABLE_SECTION_END            ".MyoSharedTable."
339 
340 #define OFFLOAD_MYO_SHARED_VTABLE_SECTION_START         ".MyoSharedVTable."
341 #define OFFLOAD_MYO_SHARED_VTABLE_SECTION_END           ".MyoSharedVTable."
342 
343 #define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START     ".MyoSharedInitTable."
344 #define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END       ".MyoSharedInitTable."
345 
346 #define OFFLOAD_MYO_FPTR_TABLE_SECTION_START            ".MyoFptrTable."
347 #define OFFLOAD_MYO_FPTR_TABLE_SECTION_END              ".MyoFptrTable."
348 
349 #endif // TARGET_WINNT
350 
351 #pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_START, read, write)
352 #pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_END, read, write)
353 
354 #pragma section(OFFLOAD_MYO_SHARED_VTABLE_SECTION_START, read, write)
355 #pragma section(OFFLOAD_MYO_SHARED_VTABLE_SECTION_END, read, write)
356 
357 #pragma section(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START, read, write)
358 #pragma section(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END, read, write)
359 
360 #pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_START, read, write)
361 #pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_END, read, write)
362 
363 // List of MYO shared variable tables
364 struct MYOVarTable {
365     typedef SharedTableEntry Entry;
366     const Entry *entries;
367 };
368 
369 class MYOVarTableList : public TableList<MYOVarTable> {
370 public:
MYOVarTableList()371     MYOVarTableList() : TableList<Table>()
372     {}
373 
374     // add table to the list
add_table(Node * node)375     void add_table(Node *node) {
376         // add table
377         TableList<Table>::add_table(node);
378     }
379 
380     // debug dump
381     void dump(void);
382 
383     // check if any shared variables
384     bool is_empty();
385 
386     // process the table contents for ordinary variables
387     void process();
388 
389     // process the table contents for vtable objects
390     void process_vtable();
391 };
392 
393 // List of MYO shared function tables
394 struct MYOFuncTable {
395     typedef FptrTableEntry Entry;
396     const Entry *entries;
397 };
398 
399 class MYOFuncTableList : public TableList<MYOFuncTable> {
400 public:
MYOFuncTableList()401     MYOFuncTableList() : TableList<Table>()
402     {}
403 
404     // add table to the list
add_table(Node * node)405     void add_table(Node *node) {
406         // add table
407         TableList<Table>::add_table(node);
408     }
409 
410     // debug dump
411     void dump(void);
412 
413     // check if any shared functions
414     bool is_empty();
415 
416     // process the table contents
417     void process();
418 };
419 
420 // List of MYO shared variable initialization routine tables
421 struct MYOInitTable {
422     typedef InitTableEntry Entry;
423     const Entry *entries;
424 };
425 
426 class MYOInitTableList : public TableList<MYOInitTable> {
427 public:
MYOInitTableList()428     MYOInitTableList() : TableList<Table>()
429     {}
430 
431     // add table to the list
add_table(Node * node)432     void add_table(Node *node) {
433         // add table
434         TableList<Table>::add_table(node);
435     }
436 
437     // debug dump
438     void dump(void);
439 
440     // check if any init routines
441     bool is_empty();
442 
443     // process the table contents
444     void process();
445 };
446 
447 extern MYOVarTableList  __offload_myo_var_tables;
448 extern MYOVarTableList  __offload_myo_vtable_tables;
449 extern MYOFuncTableList __offload_myo_func_tables;
450 extern MYOInitTableList __offload_myo_init_tables;
451 
452 extern "C" void __offload_myoRegisterTables1(
453     MYOInitTableList::Node *init_table,
454     MYOVarTableList::Node  *shared_table,
455     MYOVarTableList::Node  *shared_vtable,
456     MYOFuncTableList::Node *fptr_table
457 );
458 
459 extern "C" void __offload_myoRemoveTables(
460     MYOInitTableList::Node *init_table,
461     MYOVarTableList::Node  *shared_table,
462     MYOVarTableList::Node  *shared_vtable,
463     MYOFuncTableList::Node *fptr_table
464 );
465 
466 #endif // MYO_SUPPORT
467 
468 #endif  // OFFLOAD_TABLE_H_INCLUDED
469