mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-30 19:53:46 +00:00
322 lines
9.5 KiB
C++
322 lines
9.5 KiB
C++
/*
|
|
Copyright (c) 2014 Intel Corporation. All Rights Reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Intel Corporation nor the names of its
|
|
contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
|
|
/*! \file
|
|
\brief Function and Variable tables used by the runtime library
|
|
*/
|
|
|
|
#ifndef OFFLOAD_TABLE_H_INCLUDED
|
|
#define OFFLOAD_TABLE_H_INCLUDED
|
|
|
|
#include <iterator>
|
|
#include "offload_util.h"
|
|
|
|
// Template representing double linked list of tables
|
|
template <typename T> 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<FuncTable> {
|
|
public:
|
|
explicit FuncList(Node *node = 0) : TableList<Table>(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<Table>::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<VarTable> {
|
|
public:
|
|
VarList() : TableList<Table>()
|
|
{}
|
|
|
|
// debug dump
|
|
void dump();
|
|
|
|
public:
|
|
// var table list iterator
|
|
class Iterator : public std::iterator<std::input_iterator_tag,
|
|
Table::Entry> {
|
|
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<const char*>(-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<const char*>(-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
|