//===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.txt for details. // //===----------------------------------------------------------------------===// /*! \file \brief Function and Variable tables used by the runtime library */ #ifndef OFFLOAD_TABLE_H_INCLUDED #define OFFLOAD_TABLE_H_INCLUDED #include #include "offload_util.h" // Template representing double linked list of tables template class TableList { public: // table type typedef T Table; // List node struct Node { Table table; Node* prev; Node* next; }; public: explicit TableList(Node *node = 0) : m_head(node) {} void add_table(Node *node) { m_lock.lock(); if (m_head != 0) { node->next = m_head; m_head->prev = node; } m_head = node; m_lock.unlock(); } void remove_table(Node *node) { m_lock.lock(); if (node->next != 0) { node->next->prev = node->prev; } if (node->prev != 0) { node->prev->next = node->next; } if (m_head == node) { m_head = node->next; } m_lock.unlock(); } protected: Node* m_head; mutex_t m_lock; }; // Function lookup table. struct FuncTable { //! Function table entry /*! This table contains functions created from offload regions. */ /*! Each entry consists of a pointer to the function's "key" and the function address. */ /*! Each shared library or executable may contain one such table. */ /*! The end of the table is marked with an entry whose name field has value -1. */ struct Entry { const char* name; //!< Name of the function void* func; //!< Address of the function }; // entries const Entry *entries; // max name length int64_t max_name_len; }; // Function table class FuncList : public TableList { public: explicit FuncList(Node *node = 0) : TableList(node), m_max_name_len(-1) {} // add table to the list void add_table(Node *node) { // recalculate max function name length m_max_name_len = -1; // add table TableList
::add_table(node); } // find function address for the given name const void* find_addr(const char *name); // find function name for the given address const char* find_name(const void *addr); // max name length from all tables in the list int64_t max_name_length(void); // debug dump void dump(void); private: // max name length within from all tables int64_t m_max_name_len; }; // Table entry for static variables struct VarTable { //! Variable table entry /*! This table contains statically allocated variables marked with __declspec(target(mic) or #pragma omp declare target. */ /*! Each entry consists of a pointer to the variable's "key", the variable address and its size in bytes. */ /*! Because memory allocation is done from the host, the MIC table does not need the size of the variable. */ /*! Padding to make the table entry size a power of 2 is necessary to avoid "holes" between table contributions from different object files on Windows when debug information is specified with /Zi. */ struct Entry { const char* name; //!< Name of the variable void* addr; //!< Address of the variable #if HOST_LIBRARY uint64_t size; #ifdef TARGET_WINNT // padding to make entry size a power of 2 uint64_t padding; #endif // TARGET_WINNT #endif }; // Table terminated by an entry with name == -1 const Entry *entries; }; // List of var tables class VarList : public TableList { public: VarList() : TableList
() {} // debug dump void dump(); public: // var table list iterator class Iterator : public std::iterator { public: Iterator() : m_node(0), m_entry(0) {} explicit Iterator(Node *node) { new_node(node); } Iterator& operator++() { if (m_entry != 0) { m_entry++; while (m_entry->name == 0) { m_entry++; } if (m_entry->name == reinterpret_cast(-1)) { new_node(m_node->next); } } return *this; } bool operator==(const Iterator &other) const { return m_entry == other.m_entry; } bool operator!=(const Iterator &other) const { return m_entry != other.m_entry; } const Table::Entry* operator*() const { return m_entry; } private: void new_node(Node *node) { m_node = node; m_entry = 0; while (m_node != 0) { m_entry = m_node->table.entries; while (m_entry->name == 0) { m_entry++; } if (m_entry->name != reinterpret_cast(-1)) { break; } m_node = m_node->next; m_entry = 0; } } private: Node *m_node; const Table::Entry *m_entry; }; Iterator begin() const { return Iterator(m_head); } Iterator end() const { return Iterator(); } public: // Entry representation in a copy buffer struct BufEntry { intptr_t name; intptr_t addr; }; // Calculate the number of elements in the table and // returns the size of buffer for the table int64_t table_size(int64_t &nelems); // Copy table contents to given buffer. It is supposed to be large // enough to hold all elements as string table. void table_copy(void *buf, int64_t nelems); // Patch name offsets in a table after it's been copied to other side static void table_patch_names(void *buf, int64_t nelems); }; extern FuncList __offload_entries; extern FuncList __offload_funcs; extern VarList __offload_vars; // Section names where the lookup tables are stored #ifdef TARGET_WINNT #define OFFLOAD_ENTRY_TABLE_SECTION_START ".OffloadEntryTable$a" #define OFFLOAD_ENTRY_TABLE_SECTION_END ".OffloadEntryTable$z" #define OFFLOAD_FUNC_TABLE_SECTION_START ".OffloadFuncTable$a" #define OFFLOAD_FUNC_TABLE_SECTION_END ".OffloadFuncTable$z" #define OFFLOAD_VAR_TABLE_SECTION_START ".OffloadVarTable$a" #define OFFLOAD_VAR_TABLE_SECTION_END ".OffloadVarTable$z" #define OFFLOAD_CRTINIT_SECTION_START ".CRT$XCT" #pragma section(OFFLOAD_CRTINIT_SECTION_START, read) #else // TARGET_WINNT #define OFFLOAD_ENTRY_TABLE_SECTION_START ".OffloadEntryTable." #define OFFLOAD_ENTRY_TABLE_SECTION_END ".OffloadEntryTable." #define OFFLOAD_FUNC_TABLE_SECTION_START ".OffloadFuncTable." #define OFFLOAD_FUNC_TABLE_SECTION_END ".OffloadFuncTable." #define OFFLOAD_VAR_TABLE_SECTION_START ".OffloadVarTable." #define OFFLOAD_VAR_TABLE_SECTION_END ".OffloadVarTable." #endif // TARGET_WINNT #pragma section(OFFLOAD_ENTRY_TABLE_SECTION_START, read, write) #pragma section(OFFLOAD_ENTRY_TABLE_SECTION_END, read, write) #pragma section(OFFLOAD_FUNC_TABLE_SECTION_START, read, write) #pragma section(OFFLOAD_FUNC_TABLE_SECTION_END, read, write) #pragma section(OFFLOAD_VAR_TABLE_SECTION_START, read, write) #pragma section(OFFLOAD_VAR_TABLE_SECTION_END, read, write) // register/unregister given tables extern "C" void __offload_register_tables( FuncList::Node *entry_table, FuncList::Node *func_table, VarList::Node *var_table ); extern "C" void __offload_unregister_tables( FuncList::Node *entry_table, FuncList::Node *func_table, VarList::Node *var_table ); #endif // OFFLOAD_TABLE_H_INCLUDED