2,328 changes: 2,328 additions & 0 deletions openmp/offload/doc/doxygen/config

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions openmp/offload/doc/doxygen/header.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
% Latex header for doxygen 1.8.3.1
\documentclass{book}
\usepackage[a4paper,top=2.5cm,bottom=2.5cm,left=2.5cm,right=2.5cm]{geometry}
\usepackage{makeidx}
\usepackage{natbib}
\usepackage{graphicx}
\usepackage{multicol}
\usepackage{float}
\usepackage{listings}
\usepackage{color}
\usepackage{ifthen}
\usepackage[table]{xcolor}
\usepackage{textcomp}
\usepackage{alltt}
\usepackage{ifpdf}
\ifpdf
\usepackage[pdftex,
pagebackref=true,
colorlinks=true,
linkcolor=blue,
unicode
]{hyperref}
\else
\usepackage[ps2pdf,
pagebackref=true,
colorlinks=true,
linkcolor=blue,
unicode
]{hyperref}
\usepackage{pspicture}
\fi
\usepackage[utf8]{inputenc}
\usepackage{mathptmx}
\usepackage[scaled=.90]{helvet}
\usepackage{courier}
\usepackage{sectsty}
\usepackage{amssymb}
\usepackage[titles]{tocloft}
\usepackage{doxygen}
\usepackage{fancyhdr}
\pagestyle{fancy}
\lstset{language=C++,inputencoding=utf8,basicstyle=\footnotesize,breaklines=true,breakatwhitespace=true,tabsize=4,numbers=left }
\makeindex
\setcounter{tocdepth}{3}
\renewcommand{\footrulewidth}{0.4pt}
\renewcommand{\familydefault}{\sfdefault}
\hfuzz=15pt
\setlength{\emergencystretch}{15pt}
\hbadness=750
\tolerance=750
\begin{document}
\hypersetup{pageanchor=false,citecolor=blue}
\begin{titlepage}
\vspace*{7cm}
\begin{center}
{\Large Intel\textsuperscript{\textregistered} Offload Runtime Library }\\
\vspace*{1cm}
{\large Generated by Doxygen $doxygenversion }\\
\vspace*{0.5cm}
{\small $datetime }\\
\end{center}
\end{titlepage}
{\bf FTC Optimization Notice}
Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for
optimizations that are not unique to Intel microprocessors. These optimizations include SSE2,
SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the
availability, functionality, or effectiveness of any optimization on microprocessors not
manufactured by Intel.
Microprocessor-dependent optimizations in this product are intended for use with Intel
microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for
Intel microprocessors. Please refer to the applicable product User and Reference Guides for
more information regarding the specific instruction sets covered by this notice.
Notice revision \#20110804
\vspace*{0.5cm}
{\bf Trademarks}
Intel, Xeon, and Intel Xeon Phi are trademarks of Intel Corporation in the U.S. and/or other countries.
This document is Copyright \textcopyright 2014, Intel Corporation. All rights reserved.
\pagenumbering{roman}
\tableofcontents
\pagenumbering{arabic}
\hypersetup{pageanchor=true,citecolor=blue}
344 changes: 344 additions & 0 deletions openmp/offload/src/cean_util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,344 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#include "cean_util.h"
#include "offload_common.h"

// 1. allocate element of CeanReadRanges type
// 2. initialized it for reading consequently contiguous ranges
// described by "ap" argument
CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap)
{
CeanReadRanges * res;

// find the max contiguous range
int64_t rank = ap->rank - 1;
int64_t length = ap->dim[rank].size;
for (; rank >= 0; rank--) {
if (ap->dim[rank].stride == 1) {
length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
if (rank > 0 && length != ap->dim[rank - 1].size) {
break;
}
}
else {
break;
}
}

res =(CeanReadRanges *)malloc(sizeof(CeanReadRanges) +
(ap->rank - rank) * sizeof(CeanReadDim));
res->current_number = 0;
res->range_size = length;
res->last_noncont_ind = rank;

// calculate number of contiguous ranges inside noncontiguous dimensions
int count = 1;
bool prev_is_cont = true;
int64_t offset = 0;

for (; rank >= 0; rank--) {
res->Dim[rank].count = count;
res->Dim[rank].size = ap->dim[rank].stride * ap->dim[rank].size;
count *= (prev_is_cont && ap->dim[rank].stride == 1? 1 :
(ap->dim[rank].upper - ap->dim[rank].lower +
ap->dim[rank].stride) / ap->dim[rank].stride);
prev_is_cont = false;
offset +=(ap->dim[rank].lower - ap->dim[rank].lindex) *
ap->dim[rank].size;
}
res->range_max_number = count;
res -> ptr = (void*)ap->base;
res -> init_offset = offset;
return res;
}

// check if ranges described by 1 argument could be transfered into ranges
// described by 2-nd one
bool cean_ranges_match(
CeanReadRanges * read_rng1,
CeanReadRanges * read_rng2
)
{
return ( read_rng1 == NULL || read_rng2 == NULL ||
(read_rng1->range_size % read_rng2->range_size == 0 ||
read_rng2->range_size % read_rng1->range_size == 0));
}

// Set next offset and length and returns true for next range.
// Returns false if the ranges are over.
bool get_next_range(
CeanReadRanges * read_rng,
int64_t *offset
)
{
if (++read_rng->current_number > read_rng->range_max_number) {
read_rng->current_number = 0;
return false;
}
int rank = 0;
int num = read_rng->current_number - 1;
int64_t cur_offset = 0;
int num_loc;
for (; rank <= read_rng->last_noncont_ind; rank++) {
num_loc = num / read_rng->Dim[rank].count;
cur_offset += num_loc * read_rng->Dim[rank].size;
num = num % read_rng->Dim[rank].count;
}
*offset = cur_offset + read_rng->init_offset;
return true;
}

bool is_arr_desc_contiguous(const arr_desc *ap)
{
int64_t rank = ap->rank - 1;
int64_t length = ap->dim[rank].size;
for (; rank >= 0; rank--) {
if (ap->dim[rank].stride > 1 &&
ap->dim[rank].upper - ap->dim[rank].lower != 0) {
return false;
}
else if (length != ap->dim[rank].size) {
for (; rank >= 0; rank--) {
if (ap->dim[rank].upper - ap->dim[rank].lower != 0) {
return false;
}
}
return true;
}
length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
}
return true;
}

int64_t cean_get_transf_size(CeanReadRanges * read_rng)
{
return(read_rng->range_max_number * read_rng->range_size);
}

static uint64_t last_left, last_right;
typedef void (*fpp)(const char *spaces, uint64_t low, uint64_t high, int esize);

static void generate_one_range(
const char *spaces,
uint64_t lrange,
uint64_t rrange,
fpp fp,
int esize
)
{
OFFLOAD_TRACE(3,
"%s generate_one_range(lrange=%p, rrange=%p, esize=%d)\n",
spaces, (void*)lrange, (void*)rrange, esize);
if (last_left == -1) {
// First range
last_left = lrange;
}
else {
if (lrange == last_right+1) {
// Extend previous range, don't print
}
else {
(*fp)(spaces, last_left, last_right, esize);
last_left = lrange;
}
}
last_right = rrange;
}

static void generate_mem_ranges_one_rank(
const char *spaces,
uint64_t base,
uint64_t rank,
const struct dim_desc *ddp,
fpp fp,
int esize
)
{
uint64_t lindex = ddp->lindex;
uint64_t lower = ddp->lower;
uint64_t upper = ddp->upper;
uint64_t stride = ddp->stride;
uint64_t size = ddp->size;
OFFLOAD_TRACE(3,
"%s "
"generate_mem_ranges_one_rank(base=%p, rank=%lld, lindex=%lld, "
"lower=%lld, upper=%lld, stride=%lld, size=%lld, esize=%d)\n",
spaces, (void*)base, rank, lindex, lower, upper, stride, size, esize);
if (rank == 1) {
uint64_t lrange, rrange;
if (stride == 1) {
lrange = base + (lower-lindex)*size;
rrange = lrange + (upper-lower+1)*size - 1;
generate_one_range(spaces, lrange, rrange, fp, esize);
}
else {
for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
lrange = base + i*size;
rrange = lrange + size - 1;
generate_one_range(spaces, lrange, rrange, fp, esize);
}
}
}
else {
for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
generate_mem_ranges_one_rank(
spaces, base+i*size, rank-1, ddp+1, fp, esize);

}
}
}

static void generate_mem_ranges(
const char *spaces,
const arr_desc *adp,
bool deref,
fpp fp
)
{
uint64_t esize;

OFFLOAD_TRACE(3,
"%s "
"generate_mem_ranges(adp=%p, deref=%d, fp)\n",
spaces, adp, deref);
last_left = -1;
last_right = -2;

// Element size is derived from last dimension
esize = adp->dim[adp->rank-1].size;

generate_mem_ranges_one_rank(
// For c_cean_var the base addr is the address of the data
// For c_cean_var_ptr the base addr is dereferenced to get to the data
spaces, deref ? *((uint64_t*)(adp->base)) : adp->base,
adp->rank, &adp->dim[0], fp, esize);
(*fp)(spaces, last_left, last_right, esize);
}

// returns offset and length of the data to be transferred
void __arr_data_offset_and_length(
const arr_desc *adp,
int64_t &offset,
int64_t &length
)
{
int64_t rank = adp->rank - 1;
int64_t size = adp->dim[rank].size;
int64_t r_off = 0; // offset from right boundary

// find the rightmost dimension which takes just part of its
// range. We define it if the size of left rank is not equal
// the range's length between upper and lower boungaries
while (rank > 0) {
size *= (adp->dim[rank].upper - adp->dim[rank].lower + 1);
if (size != adp->dim[rank - 1].size) {
break;
}
rank--;
}

offset = (adp->dim[rank].lower - adp->dim[rank].lindex) *
adp->dim[rank].size;

// find gaps both from the left - offset and from the right - r_off
for (rank--; rank >= 0; rank--) {
offset += (adp->dim[rank].lower - adp->dim[rank].lindex) *
adp->dim[rank].size;
r_off += adp->dim[rank].size -
(adp->dim[rank + 1].upper - adp->dim[rank + 1].lindex + 1) *
adp->dim[rank + 1].size;
}
length = (adp->dim[0].upper - adp->dim[0].lindex + 1) *
adp->dim[0].size - offset - r_off;
}

#if OFFLOAD_DEBUG > 0

void print_range(
const char *spaces,
uint64_t low,
uint64_t high,
int esize
)
{
char buffer[1024];
char number[32];

OFFLOAD_TRACE(3, "%s print_range(low=%p, high=%p, esize=%d)\n",
spaces, (void*)low, (void*)high, esize);

if (console_enabled < 4) {
return;
}
OFFLOAD_TRACE(4, "%s values:\n", spaces);
int count = 0;
buffer[0] = '\0';
while (low <= high)
{
switch (esize)
{
case 1:
sprintf(number, "%d ", *((char *)low));
low += 1;
break;
case 2:
sprintf(number, "%d ", *((short *)low));
low += 2;
break;
case 4:
sprintf(number, "%d ", *((int *)low));
low += 4;
break;
default:
sprintf(number, "0x%016x ", *((uint64_t *)low));
low += 8;
break;
}
strcat(buffer, number);
count++;
if (count == 10) {
OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
count = 0;
buffer[0] = '\0';
}
}
if (count != 0) {
OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
}
}

void __arr_desc_dump(
const char *spaces,
const char *name,
const arr_desc *adp,
bool deref
)
{
OFFLOAD_TRACE(2, "%s%s CEAN expression %p\n", spaces, name, adp);

if (adp != 0) {
OFFLOAD_TRACE(2, "%s base=%llx, rank=%lld\n",
spaces, adp->base, adp->rank);

for (int i = 0; i < adp->rank; i++) {
OFFLOAD_TRACE(2,
"%s dimension %d: size=%lld, lindex=%lld, "
"lower=%lld, upper=%lld, stride=%lld\n",
spaces, i, adp->dim[i].size, adp->dim[i].lindex,
adp->dim[i].lower, adp->dim[i].upper,
adp->dim[i].stride);
}
// For c_cean_var the base addr is the address of the data
// For c_cean_var_ptr the base addr is dereferenced to get to the data
generate_mem_ranges(spaces, adp, deref, &print_range);
}
}
#endif // OFFLOAD_DEBUG
96 changes: 96 additions & 0 deletions openmp/offload/src/cean_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#ifndef CEAN_UTIL_H_INCLUDED
#define CEAN_UTIL_H_INCLUDED

#include <stdint.h>

// CEAN expression representation
struct dim_desc {
int64_t size; // Length of data type
int64_t lindex; // Lower index
int64_t lower; // Lower section bound
int64_t upper; // Upper section bound
int64_t stride; // Stride
};

struct arr_desc {
int64_t base; // Base address
int64_t rank; // Rank of array
dim_desc dim[1];
};

struct CeanReadDim {
int64_t count; // The number of elements in this dimension
int64_t size; // The number of bytes between successive
// elements in this dimension.
};

struct CeanReadRanges {
void * ptr;
int64_t current_number; // the number of ranges read
int64_t range_max_number; // number of contiguous ranges
int64_t range_size; // size of max contiguous range
int last_noncont_ind; // size of Dim array
int64_t init_offset; // offset of 1-st element from array left bound
CeanReadDim Dim[1];
};

// array descriptor length
#define __arr_desc_length(rank) \
(sizeof(int64_t) + sizeof(dim_desc) * (rank))

// returns offset and length of the data to be transferred
void __arr_data_offset_and_length(const arr_desc *adp,
int64_t &offset,
int64_t &length);

// define if data array described by argument is contiguous one
bool is_arr_desc_contiguous(const arr_desc *ap);

// allocate element of CeanReadRanges type initialized
// to read consequently contiguous ranges described by "ap" argument
CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap);

// check if ranges described by 1 argument could be transfered into ranges
// described by 2-nd one
bool cean_ranges_match(
CeanReadRanges * read_rng1,
CeanReadRanges * read_rng2
);

// first argument - returned value by call to init_read_ranges_arr_desc.
// returns true if offset and length of next range is set successfuly.
// returns false if the ranges is over.
bool get_next_range(
CeanReadRanges * read_rng,
int64_t *offset
);

// returns number of transfered bytes
int64_t cean_get_transf_size(CeanReadRanges * read_rng);

#if OFFLOAD_DEBUG > 0
// prints array descriptor contents to stderr
void __arr_desc_dump(
const char *spaces,
const char *name,
const arr_desc *adp,
bool dereference);
#else
#define __arr_desc_dump(
spaces,
name,
adp,
dereference)
#endif // OFFLOAD_DEBUG

#endif // CEAN_UTIL_H_INCLUDED
350 changes: 350 additions & 0 deletions openmp/offload/src/coi/coi_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,350 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


// The COI host interface

#include "coi_client.h"
#include "../offload_common.h"

namespace COI {

#define COI_VERSION1 "COI_1.0"
#define COI_VERSION2 "COI_2.0"

bool is_available;
static void* lib_handle;

// pointers to functions from COI library
COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*);
COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*);

COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*, const void*,
uint64_t, int, const char**, uint8_t,
const char**, uint8_t, const char*,
uint64_t, const char*, const char*,
uint64_t, COIPROCESS*);
COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t, int8_t*, uint32_t*);
COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t, const char**,
COIFUNCTION*);
COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS, const void*, uint64_t,
const char*, const char*,
const char*, uint64_t, uint32_t,
COILIBRARY*);
COIRESULT (*ProcessRegisterLibraries)(uint32_t, const void**, const uint64_t*,
const char**, const uint64_t*);

COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*);
COIRESULT (*PipelineDestroy)(COIPIPELINE);
COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION, uint32_t,
const COIBUFFER*, const COI_ACCESS_FLAGS*,
uint32_t, const COIEVENT*, const void*,
uint16_t, void*, uint16_t, COIEVENT*);

COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*,
uint32_t, const COIPROCESS*, COIBUFFER*);
COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE, uint32_t,
void*, uint32_t, const COIPROCESS*,
COIBUFFER*);
COIRESULT (*BufferDestroy)(COIBUFFER);
COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t,
const COIEVENT*, COIEVENT*, COIMAPINSTANCE*, void**);
COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t, COI_COPY_TYPE,
uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*);
COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t,
const COIEVENT*, COIEVENT*);

COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t, uint8_t, uint32_t*,
uint32_t*);

uint64_t (*PerfGetCycleFrequency)(void);

bool init(void)
{
#ifndef TARGET_WINNT
const char *lib_name = "libcoi_host.so.0";
#else // TARGET_WINNT
const char *lib_name = "coi_host.dll";
#endif // TARGET_WINNT

OFFLOAD_DEBUG_TRACE(2, "Loading COI library %s ...\n", lib_name);
lib_handle = DL_open(lib_name);
if (lib_handle == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to load the library\n");
return false;
}

EngineGetCount =
(COIRESULT (*)(COI_ISA_TYPE, uint32_t*))
DL_sym(lib_handle, "COIEngineGetCount", COI_VERSION1);
if (EngineGetCount == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEngineGetCount");
fini();
return false;
}

EngineGetHandle =
(COIRESULT (*)(COI_ISA_TYPE, uint32_t, COIENGINE*))
DL_sym(lib_handle, "COIEngineGetHandle", COI_VERSION1);
if (EngineGetHandle == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEngineGetHandle");
fini();
return false;
}

ProcessCreateFromMemory =
(COIRESULT (*)(COIENGINE, const char*, const void*, uint64_t, int,
const char**, uint8_t, const char**, uint8_t,
const char*, uint64_t, const char*, const char*,
uint64_t, COIPROCESS*))
DL_sym(lib_handle, "COIProcessCreateFromMemory", COI_VERSION1);
if (ProcessCreateFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessCreateFromMemory");
fini();
return false;
}

ProcessDestroy =
(COIRESULT (*)(COIPROCESS, int32_t, uint8_t, int8_t*,
uint32_t*))
DL_sym(lib_handle, "COIProcessDestroy", COI_VERSION1);
if (ProcessDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessDestroy");
fini();
return false;
}

ProcessGetFunctionHandles =
(COIRESULT (*)(COIPROCESS, uint32_t, const char**, COIFUNCTION*))
DL_sym(lib_handle, "COIProcessGetFunctionHandles", COI_VERSION1);
if (ProcessGetFunctionHandles == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessGetFunctionHandles");
fini();
return false;
}

ProcessLoadLibraryFromMemory =
(COIRESULT (*)(COIPROCESS, const void*, uint64_t, const char*,
const char*, const char*, uint64_t, uint32_t,
COILIBRARY*))
DL_sym(lib_handle, "COIProcessLoadLibraryFromMemory", COI_VERSION2);
if (ProcessLoadLibraryFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessLoadLibraryFromMemory");
fini();
return false;
}

ProcessRegisterLibraries =
(COIRESULT (*)(uint32_t, const void**, const uint64_t*, const char**,
const uint64_t*))
DL_sym(lib_handle, "COIProcessRegisterLibraries", COI_VERSION1);
if (ProcessRegisterLibraries == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessRegisterLibraries");
fini();
return false;
}

PipelineCreate =
(COIRESULT (*)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*))
DL_sym(lib_handle, "COIPipelineCreate", COI_VERSION1);
if (PipelineCreate == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineCreate");
fini();
return false;
}

PipelineDestroy =
(COIRESULT (*)(COIPIPELINE))
DL_sym(lib_handle, "COIPipelineDestroy", COI_VERSION1);
if (PipelineDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineDestroy");
fini();
return false;
}

PipelineRunFunction =
(COIRESULT (*)(COIPIPELINE, COIFUNCTION, uint32_t, const COIBUFFER*,
const COI_ACCESS_FLAGS*, uint32_t, const COIEVENT*,
const void*, uint16_t, void*, uint16_t, COIEVENT*))
DL_sym(lib_handle, "COIPipelineRunFunction", COI_VERSION1);
if (PipelineRunFunction == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineRunFunction");
fini();
return false;
}

BufferCreate =
(COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*,
uint32_t, const COIPROCESS*, COIBUFFER*))
DL_sym(lib_handle, "COIBufferCreate", COI_VERSION1);
if (BufferCreate == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCreate");
fini();
return false;
}

BufferCreateFromMemory =
(COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, void*,
uint32_t, const COIPROCESS*, COIBUFFER*))
DL_sym(lib_handle, "COIBufferCreateFromMemory", COI_VERSION1);
if (BufferCreateFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCreateFromMemory");
fini();
return false;
}

BufferDestroy =
(COIRESULT (*)(COIBUFFER))
DL_sym(lib_handle, "COIBufferDestroy", COI_VERSION1);
if (BufferDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferDestroy");
fini();
return false;
}

BufferMap =
(COIRESULT (*)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t,
const COIEVENT*, COIEVENT*, COIMAPINSTANCE*,
void**))
DL_sym(lib_handle, "COIBufferMap", COI_VERSION1);
if (BufferMap == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferMap");
fini();
return false;
}

BufferUnmap =
(COIRESULT (*)(COIMAPINSTANCE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferUnmap", COI_VERSION1);
if (BufferUnmap == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferUnmap");
fini();
return false;
}

BufferWrite =
(COIRESULT (*)(COIBUFFER, uint64_t, const void*, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferWrite", COI_VERSION1);
if (BufferWrite == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferWrite");
fini();
return false;
}

BufferRead =
(COIRESULT (*)(COIBUFFER, uint64_t, void*, uint64_t,
COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*))
DL_sym(lib_handle, "COIBufferRead", COI_VERSION1);
if (BufferRead == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferRead");
fini();
return false;
}

BufferCopy =
(COIRESULT (*)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferCopy", COI_VERSION1);
if (BufferCopy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCopy");
fini();
return false;
}

BufferGetSinkAddress =
(COIRESULT (*)(COIBUFFER, uint64_t*))
DL_sym(lib_handle, "COIBufferGetSinkAddress", COI_VERSION1);
if (BufferGetSinkAddress == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferGetSinkAddress");
fini();
return false;
}

BufferSetState =
(COIRESULT(*)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferSetState", COI_VERSION1);
if (BufferSetState == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferSetState");
fini();
return false;
}

EventWait =
(COIRESULT (*)(uint16_t, const COIEVENT*, int32_t, uint8_t,
uint32_t*, uint32_t*))
DL_sym(lib_handle, "COIEventWait", COI_VERSION1);
if (EventWait == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEventWait");
fini();
return false;
}

PerfGetCycleFrequency =
(uint64_t (*)(void))
DL_sym(lib_handle, "COIPerfGetCycleFrequency", COI_VERSION1);
if (PerfGetCycleFrequency == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPerfGetCycleFrequency");
fini();
return false;
}

is_available = true;

return true;
}

void fini(void)
{
is_available = false;

if (lib_handle != 0) {
#ifndef TARGET_WINNT
DL_close(lib_handle);
#endif // TARGET_WINNT
lib_handle = 0;
}
}

} // namespace COI
118 changes: 118 additions & 0 deletions openmp/offload/src/coi/coi_client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


// The interface betwen offload library and the COI API on the host

#ifndef COI_CLIENT_H_INCLUDED
#define COI_CLIENT_H_INCLUDED

#include <common/COIPerf_common.h>
#include <source/COIEngine_source.h>
#include <source/COIProcess_source.h>
#include <source/COIPipeline_source.h>
#include <source/COIBuffer_source.h>
#include <source/COIEvent_source.h>

#include <string.h>

#include "../liboffload_error_codes.h"
#include "../offload_util.h"

#define MIC_ENGINES_MAX 128

#if MIC_ENGINES_MAX < COI_MAX_ISA_MIC_DEVICES
#error MIC_ENGINES_MAX need to be increased
#endif

// COI library interface
namespace COI {

extern bool init(void);
extern void fini(void);

extern bool is_available;

// pointers to functions from COI library
extern COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*);
extern COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*);

extern COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*,
const void*, uint64_t, int,
const char**, uint8_t,
const char**, uint8_t,
const char*, uint64_t,
const char*,
const char*, uint64_t,
COIPROCESS*);
extern COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t,
int8_t*, uint32_t*);
extern COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t,
const char**,
COIFUNCTION*);
extern COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS,
const void*,
uint64_t,
const char*,
const char*,
const char*,
uint64_t,
uint32_t,
COILIBRARY*);
extern COIRESULT (*ProcessRegisterLibraries)(uint32_t,
const void**,
const uint64_t*,
const char**,
const uint64_t*);

extern COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t,
COIPIPELINE*);
extern COIRESULT (*PipelineDestroy)(COIPIPELINE);
extern COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION,
uint32_t, const COIBUFFER*,
const COI_ACCESS_FLAGS*,
uint32_t, const COIEVENT*,
const void*, uint16_t, void*,
uint16_t, COIEVENT*);

extern COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t,
const void*, uint32_t,
const COIPROCESS*, COIBUFFER*);
extern COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE,
uint32_t, void*,
uint32_t, const COIPROCESS*,
COIBUFFER*);
extern COIRESULT (*BufferDestroy)(COIBUFFER);
extern COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t,
COI_MAP_TYPE, uint32_t, const COIEVENT*,
COIEVENT*, COIMAPINSTANCE*, void**);
extern COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*,
uint64_t, COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t,
COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t,
uint64_t, COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*);
extern COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t,
const COIEVENT*, COIEVENT*);

extern COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t,
uint8_t, uint32_t*, uint32_t*);

extern uint64_t (*PerfGetCycleFrequency)(void);

} // namespace COI

#endif // COI_CLIENT_H_INCLUDED
130 changes: 130 additions & 0 deletions openmp/offload/src/coi/coi_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


// The COI interface on the target

#include "coi_server.h"

#include "../offload_target.h"
#include "../offload_timer.h"
#ifdef MYO_SUPPORT
#include "../offload_myo_target.h" // for __offload_myoLibInit/Fini
#endif // MYO_SUPPORT

COINATIVELIBEXPORT
void server_compute(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
OffloadDescriptor::offload(buffer_count, buffers,
misc_data, misc_data_len,
return_data, return_data_len);
}

COINATIVELIBEXPORT
void server_init(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
struct init_data {
int device_index;
int devices_total;
int console_level;
int offload_report_level;
} *data = (struct init_data*) misc_data;

// set device index and number of total devices
mic_index = data->device_index;
mic_engines_total = data->devices_total;

// initialize trace level
console_enabled = data->console_level;
offload_report_level = data->offload_report_level;

// return back the process id
*((pid_t*) return_data) = getpid();
}

COINATIVELIBEXPORT
void server_var_table_size(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
struct Params {
int64_t nelems;
int64_t length;
} *params;

params = static_cast<Params*>(return_data);
params->length = __offload_vars.table_size(params->nelems);
}

COINATIVELIBEXPORT
void server_var_table_copy(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_vars.table_copy(buffers[0], *static_cast<int64_t*>(misc_data));
}

#ifdef MYO_SUPPORT
// temporary workaround for blocking behavior of myoiLibInit/Fini calls
COINATIVELIBEXPORT
void server_myoinit(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_myoLibInit();
}

COINATIVELIBEXPORT
void server_myofini(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_myoLibFini();
}
#endif // MYO_SUPPORT
74 changes: 74 additions & 0 deletions openmp/offload/src/coi/coi_server.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


//The interface betwen offload library and the COI API on the target.

#ifndef COI_SERVER_H_INCLUDED
#define COI_SERVER_H_INCLUDED

#include <common/COIEngine_common.h>
#include <common/COIPerf_common.h>
#include <sink/COIProcess_sink.h>
#include <sink/COIPipeline_sink.h>
#include <sink/COIBuffer_sink.h>
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../liboffload_error_codes.h"

// wrappers for COI API
#define PipelineStartExecutingRunFunctions() \
{ \
COIRESULT res = COIPipelineStartExecutingRunFunctions(); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_pipeline_start_run_funcs, mic_index, res); \
exit(1); \
} \
}

#define ProcessWaitForShutdown() \
{ \
COIRESULT res = COIProcessWaitForShutdown(); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_process_wait_shutdown, mic_index, res); \
exit(1); \
} \
}

#define BufferAddRef(buf) \
{ \
COIRESULT res = COIBufferAddRef(buf); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_buf_add_ref, mic_index, res); \
exit(1); \
} \
}

#define BufferReleaseRef(buf) \
{ \
COIRESULT res = COIBufferReleaseRef(buf); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_buf_release_ref, mic_index, res); \
exit(1); \
} \
}

#define EngineGetIndex(index) \
{ \
COI_ISA_TYPE isa_type; \
COIRESULT res = COIEngineGetIndex(&isa_type, index); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_get_engine_index, mic_index, res); \
exit(1); \
} \
}

#endif // COI_SERVER_H_INCLUDED
323 changes: 323 additions & 0 deletions openmp/offload/src/compiler_if_host.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#include "compiler_if_host.h"

#include <malloc.h>
#ifndef TARGET_WINNT
#include <alloca.h>
#endif // TARGET_WINNT

// Global counter on host.
// This variable is used if P2OPT_offload_do_data_persistence == 2.
// The variable used to identify offload constructs contained in one procedure.
// Increment of OFFLOAD_CALL_COUNT is inserted at entries of HOST routines with
// offload constructs.
static int offload_call_count = 0;

extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE(
TARGET_TYPE target_type,
int target_number,
int is_optional,
_Offload_status* status,
const char* file,
uint64_t line
)
{
bool retval;
OFFLOAD ofld;

// initialize status
if (status != 0) {
status->result = OFFLOAD_UNAVAILABLE;
status->device_number = -1;
status->data_sent = 0;
status->data_received = 0;
}

// make sure libray is initialized
retval = __offload_init_library();

// OFFLOAD_TIMER_INIT must follow call to __offload_init_library
OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);

OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);

OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);

// initalize all devices is init_type is on_offload_all
if (retval && __offload_init_type == c_init_on_offload_all) {
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init();
}
}
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);

OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);

if (target_type == TARGET_HOST) {
// Host always available
retval = true;
}
else if (target_type == TARGET_MIC) {
if (target_number >= -1) {
if (retval) {
if (target_number >= 0) {
// User provided the device number
target_number = target_number % mic_engines_total;
}
else {
// use device 0
target_number = 0;
}

// reserve device in ORSL
if (is_optional) {
if (!ORSL::try_reserve(target_number)) {
target_number = -1;
}
}
else {
if (!ORSL::reserve(target_number)) {
target_number = -1;
}
}

// initialize device
if (target_number >= 0 &&
__offload_init_type == c_init_on_offload) {
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
mic_engines[target_number].init();
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
}
}
else {
// fallback to CPU
target_number = -1;
}

if (target_number < 0 || !retval) {
if (!is_optional && status == 0) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}

retval = false;
}
}
else {
LIBOFFLOAD_ERROR(c_invalid_device_number);
exit(1);
}
}

if (retval) {
ofld = new OffloadDescriptor(target_number, status,
!is_optional, false, timer_data);
OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);
Offload_Report_Prolog(timer_data);
OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
"Starting offload: target_type = %d, "
"number = %d, is_optional = %d\n",
target_type, target_number, is_optional);

OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
}
else {
ofld = NULL;

OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_total_offload);
offload_report_free_data(timer_data);
}

return ofld;
}

extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1(
const int* device_num,
const char* file,
uint64_t line
)
{
int target_number;

// make sure libray is initialized and at least one device is available
if (!__offload_init_library()) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}

// OFFLOAD_TIMER_INIT must follow call to __offload_init_library

OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);

OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);

OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);

if (__offload_init_type == c_init_on_offload_all) {
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init();
}
}

OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);

OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);

// use default device number if it is not provided
if (device_num != 0) {
target_number = *device_num;
}
else {
target_number = __omp_device_num;
}

// device number should be a non-negative integer value
if (target_number < 0) {
LIBOFFLOAD_ERROR(c_omp_invalid_device_num);
exit(1);
}

// should we do this for OpenMP?
target_number %= mic_engines_total;

// reserve device in ORSL
if (!ORSL::reserve(target_number)) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}

// initialize device(s)
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);

if (__offload_init_type == c_init_on_offload) {
mic_engines[target_number].init();
}

OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);

OFFLOAD ofld =
new OffloadDescriptor(target_number, 0, true, true, timer_data);

OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);

Offload_Report_Prolog(timer_data);

OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
"Starting OpenMP offload, device = %d\n",
target_number);

OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);

return ofld;
}

int offload_offload_wrap(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void **signal,
int entry_id,
const void *stack_addr
)
{
bool ret = ofld->offload(name, is_empty, vars, vars2, num_vars,
waits, num_waits, signal, entry_id, stack_addr);
if (!ret || signal == 0) {
delete ofld;
}
return ret;
}

extern "C" int OFFLOAD_OFFLOAD1(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void **signal
)
{
return offload_offload_wrap(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits, waits,
signal, NULL, NULL);
}

extern "C" int OFFLOAD_OFFLOAD2(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal,
int entry_id,
const void *stack_addr
)
{
return offload_offload_wrap(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits, waits,
signal, entry_id, stack_addr);
}

extern "C" int OFFLOAD_OFFLOAD(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void *signal,
int entry_id,
const void *stack_addr
)
{
// signal is passed by reference now
const void **signal_new = (signal != 0) ? &signal : 0;
const void **waits_new = 0;
int num_waits_new = 0;

// remove NULL values from the list of signals to wait for
if (num_waits > 0) {
waits_new = (const void**) alloca(sizeof(void*) * num_waits);
for (int i = 0; i < num_waits; i++) {
if (waits[i] != 0) {
waits_new[num_waits_new++] = waits[i];
}
}
}

return OFFLOAD_OFFLOAD1(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits_new, waits_new,
signal_new);
}

extern "C" int OFFLOAD_CALL_COUNT()
{
offload_call_count++;
return offload_call_count;
}
133 changes: 133 additions & 0 deletions openmp/offload/src/compiler_if_host.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//===----------------------------------------------------------------------===//
//
// 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 The interface between compiler-generated host code and runtime library
*/

#ifndef COMPILER_IF_HOST_H_INCLUDED
#define COMPILER_IF_HOST_H_INCLUDED

#include "offload_host.h"

#define OFFLOAD_TARGET_ACQUIRE OFFLOAD_PREFIX(target_acquire)
#define OFFLOAD_TARGET_ACQUIRE1 OFFLOAD_PREFIX(target_acquire1)
#define OFFLOAD_OFFLOAD OFFLOAD_PREFIX(offload)
#define OFFLOAD_OFFLOAD1 OFFLOAD_PREFIX(offload1)
#define OFFLOAD_OFFLOAD2 OFFLOAD_PREFIX(offload2)
#define OFFLOAD_CALL_COUNT OFFLOAD_PREFIX(offload_call_count)


/*! \fn OFFLOAD_TARGET_ACQUIRE
\brief Attempt to acquire the target.
\param target_type The type of target.
\param target_number The device number.
\param is_optional Whether CPU fall-back is allowed.
\param status Address of variable to hold offload status.
\param file Filename in which this offload occurred.
\param line Line number in the file where this offload occurred.
*/
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE(
TARGET_TYPE target_type,
int target_number,
int is_optional,
_Offload_status* status,
const char* file,
uint64_t line
);

/*! \fn OFFLOAD_TARGET_ACQUIRE1
\brief Acquire the target for offload (OpenMP).
\param device_number Device number or null if not specified.
\param file Filename in which this offload occurred
\param line Line number in the file where this offload occurred.
*/
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1(
const int* device_number,
const char* file,
uint64_t line
);

/*! \fn OFFLOAD_OFFLOAD1
\brief Run function on target using interface for old data persistence.
\param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
\param name Name of offload entry point.
\param is_empty If no code to execute (e.g. offload_transfer)
\param num_vars Number of variable descriptors.
\param vars Pointer to VarDesc array.
\param vars2 Pointer to VarDesc2 array.
\param num_waits Number of "wait" values.
\param waits Pointer to array of wait values.
\param signal Pointer to signal value or NULL.
*/
extern "C" int OFFLOAD_OFFLOAD1(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal
);

/*! \fn OFFLOAD_OFFLOAD2
\brief Run function on target using interface for new data persistence.
\param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
\param name Name of offload entry point.
\param is_empty If no code to execute (e.g. offload_transfer)
\param num_vars Number of variable descriptors.
\param vars Pointer to VarDesc array.
\param vars2 Pointer to VarDesc2 array.
\param num_waits Number of "wait" values.
\param waits Pointer to array of wait values.
\param signal Pointer to signal value or NULL.
\param entry_id A signature for the function doing the offload.
\param stack_addr The stack frame address of the function doing offload.
*/
extern "C" int OFFLOAD_OFFLOAD2(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal,
int entry_id,
const void *stack_addr
);

// Run function on target (obsolete).
// @param o OFFLOAD object
// @param name function name
extern "C" int OFFLOAD_OFFLOAD(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void* signal,
int entry_id = 0,
const void *stack_addr = NULL
);

// Global counter on host.
// This variable is used if P2OPT_offload_do_data_persistence == 2.
// The variable used to identify offload constructs contained in one procedure.
// Call to OFFLOAD_CALL_COUNT() is inserted at HOST on entry of the routine.
extern "C" int OFFLOAD_CALL_COUNT();

#endif // COMPILER_IF_HOST_H_INCLUDED
44 changes: 44 additions & 0 deletions openmp/offload/src/compiler_if_target.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#include "compiler_if_target.h"

extern "C" void OFFLOAD_TARGET_ENTER(
OFFLOAD ofld,
int vars_total,
VarDesc *vars,
VarDesc2 *vars2
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p, %d, %p, %p)\n", __func__, ofld,
vars_total, vars, vars2);
ofld->merge_var_descs(vars, vars2, vars_total);
ofld->scatter_copyin_data();
}

extern "C" void OFFLOAD_TARGET_LEAVE(
OFFLOAD ofld
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ofld);
ofld->gather_copyout_data();
}

extern "C" void OFFLOAD_TARGET_MAIN(void)
{
// initialize target part
__offload_target_init();

// pass control to COI
PipelineStartExecutingRunFunctions();
ProcessWaitForShutdown();

OFFLOAD_DEBUG_TRACE(2, "Exiting main...\n");
}
50 changes: 50 additions & 0 deletions openmp/offload/src/compiler_if_target.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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 The interface between compiler-generated target code and runtime library
*/

#ifndef COMPILER_IF_TARGET_H_INCLUDED
#define COMPILER_IF_TARGET_H_INCLUDED

#include "offload_target.h"

#define OFFLOAD_TARGET_ENTER OFFLOAD_PREFIX(target_enter)
#define OFFLOAD_TARGET_LEAVE OFFLOAD_PREFIX(target_leave)
#define OFFLOAD_TARGET_MAIN OFFLOAD_PREFIX(target_main)

/*! \fn OFFLOAD_TARGET_ENTER
\brief Fill in variable addresses using VarDesc array.
\brief Then call back the runtime library to fetch data.
\param ofld Offload descriptor created by runtime.
\param var_desc_num Number of variable descriptors.
\param var_desc Pointer to VarDesc array.
\param var_desc2 Pointer to VarDesc2 array.
*/
extern "C" void OFFLOAD_TARGET_ENTER(
OFFLOAD ofld,
int var_desc_num,
VarDesc *var_desc,
VarDesc2 *var_desc2
);

/*! \fn OFFLOAD_TARGET_LEAVE
\brief Call back the runtime library to gather outputs using VarDesc array.
\param ofld Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
*/
extern "C" void OFFLOAD_TARGET_LEAVE(
OFFLOAD ofld
);

// Entry point for the target application.
extern "C" void OFFLOAD_TARGET_MAIN(void);

#endif // COMPILER_IF_TARGET_H_INCLUDED
131 changes: 131 additions & 0 deletions openmp/offload/src/dv_util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#include "offload_common.h"

bool __dv_is_contiguous(const ArrDesc *dvp)
{
if (dvp->Flags & ArrDescFlagsContiguous) {
return true;
}

if (dvp->Rank != 0) {
if (dvp->Dim[0].Mult != dvp->Len) {
return false;
}
for (int i = 1; i < dvp->Rank; i++) {
if (dvp->Dim[i].Mult !=
dvp->Dim[i-1].Extent * dvp->Dim[i-1].Mult) {
return false;
}
}
}
return true;
}

bool __dv_is_allocated(const ArrDesc *dvp)
{
return (dvp->Flags & ArrDescFlagsDefined);
}

uint64_t __dv_data_length(const ArrDesc *dvp)
{
uint64_t size;

if (dvp->Rank == 0) {
size = dvp->Len;
return size;
}

size = dvp->Len;
for (int i = 0; i < dvp->Rank; ++i) {
size += (dvp->Dim[i].Extent-1) * dvp->Dim[i].Mult;
}
return size;
}

uint64_t __dv_data_length(const ArrDesc *dvp, int64_t count)
{
if (dvp->Rank == 0) {
return count;
}

return count * dvp->Dim[0].Mult;
}

// Create CeanReadRanges data for reading contiguous ranges of
// noncontiguous array defined by the argument
CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp)
{
int64_t len;
int count;
int rank = dvp->Rank;
CeanReadRanges *res = NULL;

if (rank != 0) {
int i = 0;
len = dvp->Len;
if (dvp->Dim[0].Mult == len) {
for (i = 1; i < rank; i++) {
len *= dvp->Dim[i-1].Extent;
if (dvp->Dim[i].Mult != len) {
break;
}
}
}
res = (CeanReadRanges *)malloc(
sizeof(CeanReadRanges) + (rank - i) * sizeof(CeanReadDim));
res -> last_noncont_ind = rank - i - 1;
count = 1;
for (; i < rank; i++) {
res->Dim[rank - i - 1].count = count;
res->Dim[rank - i - 1].size = dvp->Dim[i].Mult;
count *= dvp->Dim[i].Extent;
}
res -> range_max_number = count;
res -> range_size = len;
res -> ptr = (void*)dvp->Base;
res -> current_number = 0;
res -> init_offset = 0;
}
return res;
}

#if OFFLOAD_DEBUG > 0
void __dv_desc_dump(const char *name, const ArrDesc *dvp)
{
OFFLOAD_TRACE(3, "%s DV %p\n", name, dvp);

if (dvp != 0) {
OFFLOAD_TRACE(3,
" dv->Base = 0x%lx\n"
" dv->Len = 0x%lx\n"
" dv->Offset = 0x%lx\n"
" dv->Flags = 0x%lx\n"
" dv->Rank = 0x%lx\n"
" dv->Resrvd = 0x%lx\n",
dvp->Base,
dvp->Len,
dvp->Offset,
dvp->Flags,
dvp->Rank,
dvp->Reserved);

for (int i = 0 ; i < dvp->Rank; i++) {
OFFLOAD_TRACE(3,
" (%d) Extent=%ld, Multiplier=%ld, LowerBound=%ld\n",
i,
dvp->Dim[i].Extent,
dvp->Dim[i].Mult,
dvp->Dim[i].LowerBound);
}
}
}
#endif // OFFLOAD_DEBUG > 0
63 changes: 63 additions & 0 deletions openmp/offload/src/dv_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#ifndef DV_UTIL_H_INCLUDED
#define DV_UTIL_H_INCLUDED

#include <stdint.h>

// Dope vector declarations
#define ArrDescMaxArrayRank 31

// Dope vector flags
#define ArrDescFlagsDefined 1
#define ArrDescFlagsNodealloc 2
#define ArrDescFlagsContiguous 4

typedef int64_t dv_size;

typedef struct DimDesc {
dv_size Extent; // Number of elements in this dimension
dv_size Mult; // Multiplier for this dimension.
// The number of bytes between successive
// elements in this dimension.
dv_size LowerBound; // LowerBound of this dimension
} DimDesc ;

typedef struct ArrDesc {
dv_size Base; // Base address
dv_size Len; // Length of data type, used only for
// character strings.
dv_size Offset;
dv_size Flags; // Flags
dv_size Rank; // Rank of pointer
dv_size Reserved; // reserved for openmp requests
DimDesc Dim[ArrDescMaxArrayRank];
} ArrDesc ;

typedef ArrDesc* pArrDesc;

bool __dv_is_contiguous(const ArrDesc *dvp);

bool __dv_is_allocated(const ArrDesc *dvp);

uint64_t __dv_data_length(const ArrDesc *dvp);

uint64_t __dv_data_length(const ArrDesc *dvp, int64_t nelems);

CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp);

#if OFFLOAD_DEBUG > 0
void __dv_desc_dump(const char *name, const ArrDesc *dvp);
#else // OFFLOAD_DEBUG
#define __dv_desc_dump(name, dvp)
#endif // OFFLOAD_DEBUG

#endif // DV_UTIL_H_INCLUDED
452 changes: 452 additions & 0 deletions openmp/offload/src/liboffload_error.c

Large diffs are not rendered by default.

276 changes: 276 additions & 0 deletions openmp/offload/src/liboffload_error_codes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#if !defined(LIBOFFLOAD_ERROR_CODES_H)
#define LIBOFFLOAD_ERROR_CODES_H
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

typedef enum
{
c_device_is_not_available = 0,
c_invalid_device_number,
c_offload1,
c_unknown_var_type,
c_send_func_ptr,
c_receive_func_ptr,
c_offload_malloc,
c_invalid_env_var_value,
c_invalid_env_var_int_value,
c_invalid_env_report_value,
c_offload_signaled1,
c_offload_signaled2,
c_myotarget_checkresult,
c_myowrapper_checkresult,
c_offload_descriptor_offload,
c_merge_var_descs1,
c_merge_var_descs2,
c_mic_parse_env_var_list1,
c_mic_parse_env_var_list2,
c_mic_process_exit_ret,
c_mic_process_exit_sig,
c_mic_process_exit,
c_mic_init3,
c_mic_init4,
c_mic_init5,
c_mic_init6,
c_no_static_var_data,
c_no_ptr_data,
c_get_engine_handle,
c_get_engine_index,
c_process_create,
c_process_get_func_handles,
c_process_wait_shutdown,
c_process_proxy_flush,
c_load_library,
c_pipeline_create,
c_pipeline_run_func,
c_pipeline_start_run_funcs,
c_buf_create,
c_buf_create_out_of_mem,
c_buf_create_from_mem,
c_buf_destroy,
c_buf_map,
c_buf_unmap,
c_buf_read,
c_buf_write,
c_buf_copy,
c_buf_get_address,
c_buf_add_ref,
c_buf_release_ref,
c_buf_set_state,
c_event_wait,
c_zero_or_neg_ptr_len,
c_zero_or_neg_transfer_size,
c_bad_ptr_mem_range,
c_different_src_and_dstn_sizes,
c_ranges_dont_match,
c_destination_is_over,
c_slice_of_noncont_array,
c_non_contiguous_dope_vector,
c_pointer_array_mismatch,
c_omp_invalid_device_num_env,
c_omp_invalid_device_num,
c_unknown_binary_type,
c_multiple_target_exes,
c_no_target_exe,
c_report_host,
c_report_target,
c_report_title,
c_report_from_file,
c_report_file,
c_report_line,
c_report_tag,
c_report_seconds,
c_report_bytes,
c_report_mic,
c_report_cpu_time,
c_report_cpu_to_mic_data,
c_report_mic_time,
c_report_mic_to_cpu_data,
c_report_unknown_timer_node,
c_report_unknown_trace_node,
c_report_offload,
c_report_w_tag,
c_report_state,
c_report_start,
c_report_init,
c_report_logical_card,
c_report_physical_card,
c_report_register,
c_report_init_func,
c_report_create_buf_host,
c_report_create_buf_mic,
c_report_send_pointer_data,
c_report_sent_pointer_data,
c_report_gather_copyin_data,
c_report_copyin_data,
c_report_state_signal,
c_report_signal,
c_report_wait,
c_report_compute,
c_report_receive_pointer_data,
c_report_received_pointer_data,
c_report_start_target_func,
c_report_var,
c_report_scatter_copyin_data,
c_report_gather_copyout_data,
c_report_scatter_copyout_data,
c_report_copyout_data,
c_report_unregister,
c_report_destroy,
c_report_myoinit,
c_report_myoregister,
c_report_myofini,
c_report_mic_myo_shared,
c_report_mic_myo_fptr,
c_report_myosharedmalloc,
c_report_myosharedfree,
c_report_myosharedalignedmalloc,
c_report_myosharedalignedfree,
c_report_myoacquire,
c_report_myorelease,
c_coipipe_max_number
} error_types;

enum OffloadHostPhase {
// Total time on host for entire offload
c_offload_host_total_offload = 0,

// Time to load target binary
c_offload_host_initialize,

// Time to acquire lrb availability dynamically
c_offload_host_target_acquire,

// Time to wait for dependencies
c_offload_host_wait_deps,

// Time to allocate pointer buffers, initiate writes for pointers
// and calculate size of copyin/copyout buffer
c_offload_host_setup_buffers,

// Time to allocate pointer buffers
c_offload_host_alloc_buffers,

// Time to initialize misc data
c_offload_host_setup_misc_data,

// Time to allocate copyin/copyout buffer
c_offload_host_alloc_data_buffer,

// Time to initiate writes from host pointers to buffers
c_offload_host_send_pointers,

// Time to Gather IN data of offload into buffer
c_offload_host_gather_inputs,

// Time to map buffer
c_offload_host_map_in_data_buffer,

// Time to unmap buffer
c_offload_host_unmap_in_data_buffer,

// Time to start remote function call that does computation on lrb
c_offload_host_start_compute,

// Time to wait for compute to finish
c_offload_host_wait_compute,

// Time to initiate reads from pointer buffers
c_offload_host_start_buffers_reads,

// Time to update host variabels with OUT data from buffer
c_offload_host_scatter_outputs,

// Time to map buffer
c_offload_host_map_out_data_buffer,

// Time to unmap buffer
c_offload_host_unmap_out_data_buffer,

// Time to wait reads from buffers to finish
c_offload_host_wait_buffers_reads,

// Time to destroy buffers that are no longer needed
c_offload_host_destroy_buffers,

// LAST TIME MONITOR
c_offload_host_max_phase
};

enum OffloadTargetPhase {
// Total time spent on the target
c_offload_target_total_time = 0,

// Time to initialize offload descriptor
c_offload_target_descriptor_setup,

// Time to find target entry point in lookup table
c_offload_target_func_lookup,

// Total time spend executing offload entry
c_offload_target_func_time,

// Time to initialize target variables with IN values from buffer
c_offload_target_scatter_inputs,

// Time to add buffer reference for pointer buffers
c_offload_target_add_buffer_refs,

// Total time on lrb for computation
c_offload_target_compute,

// On lrb, time to copy OUT into buffer
c_offload_target_gather_outputs,

// Time to release buffer references
c_offload_target_release_buffer_refs,

// LAST TIME MONITOR
c_offload_target_max_phase
};

#ifdef __cplusplus
extern "C" {
#endif
void __liboffload_error_support(error_types input_tag, ...);
void __liboffload_report_support(error_types input_tag, ...);
char const *offload_get_message_str(int msgCode);
char const * report_get_message_str(error_types input_tag);
char const * report_get_host_stage_str(int i);
char const * report_get_target_stage_str(int i);
#ifdef __cplusplus
}
#endif

#define test_msg_cat(nm, msg) \
fprintf(stderr, "\t TEST for %s \n \t", nm); \
__liboffload_error_support(msg);

#define test_msg_cat1(nm, msg, ...) \
fprintf(stderr, "\t TEST for %s \n \t", nm); \
__liboffload_error_support(msg, __VA_ARGS__);

void write_message(FILE * file, int msgCode, va_list args_p);

#define LIBOFFLOAD_ERROR __liboffload_error_support

#ifdef TARGET_WINNT
#define LIBOFFLOAD_ABORT \
_set_abort_behavior(0, _WRITE_ABORT_MSG); \
abort()
#else
#define LIBOFFLOAD_ABORT \
abort()
#endif

#endif // !defined(LIBOFFLOAD_ERROR_CODES_H)
35 changes: 35 additions & 0 deletions openmp/offload/src/liboffload_msg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//



#include <stdio.h>

// ===========================================================================
// Bring in the static string table and the enumerations for indexing into
// it.
// ===========================================================================

#include "liboffload_msg.h"

# define DYNART_STDERR_PUTS(__message_text__) fputs((__message_text__),stderr)

// ===========================================================================
// Now the code for accessing the message catalogs
// ===========================================================================


void write_message(FILE * file, int msgCode) {
fputs(MESSAGE_TABLE_NAME[ msgCode ], file);
fflush(file);
}

char const *offload_get_message_str(int msgCode) {
return MESSAGE_TABLE_NAME[ msgCode ];
}
326 changes: 326 additions & 0 deletions openmp/offload/src/liboffload_msg.h

Large diffs are not rendered by default.

441 changes: 441 additions & 0 deletions openmp/offload/src/mic_lib.f90

Large diffs are not rendered by default.

474 changes: 474 additions & 0 deletions openmp/offload/src/offload.h

Large diffs are not rendered by default.

170 changes: 170 additions & 0 deletions openmp/offload/src/offload_common.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#if defined(LINUX) || defined(FREEBSD)
#include <mm_malloc.h>
#endif

#include "offload_common.h"

// The debug routines

#if OFFLOAD_DEBUG > 0

void __dump_bytes(
int trace_level,
const void *data,
int len
)
{
if (console_enabled > trace_level) {
const uint8_t *arr = (const uint8_t*) data;
char buffer[4096];
char *bufferp;
int count = 0;

bufferp = buffer;
while (len--) {
sprintf(bufferp, "%02x", *arr++);
bufferp += 2;
count++;
if ((count&3) == 0) {
sprintf(bufferp, " ");
bufferp++;
}
if ((count&63) == 0) {
OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer);
bufferp = buffer;
count = 0;
}
}
if (count) {
OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer);
}
}
}
#endif // OFFLOAD_DEBUG

// The Marshaller and associated routines

void Marshaller::send_data(
const void *data,
int64_t length
)
{
OFFLOAD_DEBUG_TRACE(2, "send_data(%p, %lld)\n",
data, length);
memcpy(buffer_ptr, data, (size_t)length);
buffer_ptr += length;
tfr_size += length;
}

void Marshaller::receive_data(
void *data,
int64_t length
)
{
OFFLOAD_DEBUG_TRACE(2, "receive_data(%p, %lld)\n",
data, length);
memcpy(data, buffer_ptr, (size_t)length);
buffer_ptr += length;
tfr_size += length;
}

// Send function pointer
void Marshaller::send_func_ptr(
const void* data
)
{
const char* name;
size_t length;

if (data != 0) {
name = __offload_funcs.find_name(data);
if (name == 0) {
#if OFFLOAD_DEBUG > 0
if (console_enabled > 2) {
__offload_funcs.dump();
}
#endif // OFFLOAD_DEBUG > 0

LIBOFFLOAD_ERROR(c_send_func_ptr, data);
exit(1);
}
length = strlen(name) + 1;
}
else {
name = "";
length = 1;
}

memcpy(buffer_ptr, name, length);
buffer_ptr += length;
tfr_size += length;
}

// Receive function pointer
void Marshaller::receive_func_ptr(
const void** data
)
{
const char* name;
size_t length;

name = (const char*) buffer_ptr;
if (name[0] != '\0') {
*data = __offload_funcs.find_addr(name);
if (*data == 0) {
#if OFFLOAD_DEBUG > 0
if (console_enabled > 2) {
__offload_funcs.dump();
}
#endif // OFFLOAD_DEBUG > 0

LIBOFFLOAD_ERROR(c_receive_func_ptr, name);
exit(1);
}
length = strlen(name) + 1;
}
else {
*data = 0;
length = 1;
}

buffer_ptr += length;
tfr_size += length;
}

// End of the Marshaller and associated routines

extern void *OFFLOAD_MALLOC(
size_t size,
size_t align
)
{
void *ptr;
int err;

OFFLOAD_DEBUG_TRACE(2, "%s(%lld, %lld)\n", __func__, size, align);

if (align < sizeof(void*)) {
align = sizeof(void*);
}

ptr = _mm_malloc(size, align);
if (ptr == NULL) {
LIBOFFLOAD_ERROR(c_offload_malloc, size, align);
exit(1);
}

OFFLOAD_DEBUG_TRACE(2, "%s returned %p\n", __func__, ptr);

return ptr;
}
444 changes: 444 additions & 0 deletions openmp/offload/src/offload_common.h

Large diffs are not rendered by default.

531 changes: 531 additions & 0 deletions openmp/offload/src/offload_engine.cpp

Large diffs are not rendered by default.

482 changes: 482 additions & 0 deletions openmp/offload/src/offload_engine.h

Large diffs are not rendered by default.

354 changes: 354 additions & 0 deletions openmp/offload/src/offload_env.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#include "offload_env.h"
#include <string.h>
#include <ctype.h>
#include "offload_util.h"
#include "liboffload_error_codes.h"

// for environment variables valid on all cards
const int MicEnvVar::any_card = -1;

MicEnvVar::~MicEnvVar()
{
for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
it = card_spec_list.begin();
it != card_spec_list.end(); it++) {
CardEnvVars *card_data = *it;
delete card_data;
}
}

MicEnvVar::VarValue::~VarValue()
{
free(env_var_value);
}

MicEnvVar::CardEnvVars::~CardEnvVars()
{
for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
it != env_vars.end(); it++) {
VarValue *var_value = *it;
delete var_value;
}
}

// Searching for card in "card_spec_list" list with the same "number"

MicEnvVar::CardEnvVars* MicEnvVar::get_card(int number)
{
if (number == any_card) {
return &common_vars;
}
for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
it = card_spec_list.begin();
it != card_spec_list.end(); it++) {
CardEnvVars *card_data = *it;
if (card_data->card_number == number) {
return card_data;
}
}
return NULL;
}

// Searching for environment variable in "env_var" list with the same name

MicEnvVar::VarValue* MicEnvVar::CardEnvVars::find_var(
char* env_var_name,
int env_var_name_length
)
{
for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
it != env_vars.end(); it++) {
VarValue *var_value = *it;
if (var_value->length == env_var_name_length &&
!strncmp(var_value->env_var, env_var_name,
env_var_name_length)) {
return var_value;
}
}
return NULL;
}

void MicEnvVar::analyze_env_var(char *env_var_string)
{
char *env_var_name;
char *env_var_def;
int card_number;
int env_var_name_length;
MicEnvVarKind env_var_kind;

env_var_kind = get_env_var_kind(env_var_string,
&card_number,
&env_var_name,
&env_var_name_length,
&env_var_def);
switch (env_var_kind) {
case c_mic_var:
case c_mic_card_var:
add_env_var(card_number,
env_var_name,
env_var_name_length,
env_var_def);
break;
case c_mic_card_env:
mic_parse_env_var_list(card_number, env_var_def);
break;
case c_no_mic:
default:
break;
}
}

void MicEnvVar::add_env_var(
int card_number,
char *env_var_name,
int env_var_name_length,
char *env_var_def
)
{
VarValue *var;
CardEnvVars *card;

// The case corresponds to common env var definition of kind
// <mic-prefix>_<var>
if (card_number == any_card) {
card = &common_vars;
}
else {
card = get_card(card_number);
if (!card) {
// definition for new card occured
card = new CardEnvVars(card_number);
card_spec_list.push_back(card);
}

}
var = card->find_var(env_var_name, env_var_name_length);
if (!var) {
// put new env var definition in "env_var" list
var = new VarValue(env_var_name, env_var_name_length, env_var_def);
card->env_vars.push_back(var);
}
}

// The routine analyses string pointed by "env_var_string" argument
// according to the following syntax:
//
// Specification of prefix for MIC environment variables
// MIC_ENV_PREFIX=<mic-prefix>
//
// Setting single MIC environment variable
// <mic-prefix>_<var>=<value>
// <mic-prefix>_<card-number>_<var>=<value>

// Setting multiple MIC environment variables
// <mic-prefix>_<card-number>_ENV=<env-vars>

MicEnvVarKind MicEnvVar::get_env_var_kind(
char *env_var_string,
int *card_number,
char **env_var_name,
int *env_var_name_length,
char **env_var_def
)
{
int len = strlen(prefix);
char *c = env_var_string;
int num = 0;
bool card_is_set = false;

if (strncmp(c, prefix, len) != 0 || c[len] != '_') {
return c_no_mic;
}
c += len + 1;

*card_number = any_card;
if (isdigit(*c)) {
while (isdigit (*c)) {
num = (*c++ - '0') + (num * 10);
}
if (*c != '_') {
return c_no_mic;
}
c++;
*card_number = num;
card_is_set = true;
}
if (!isalpha(*c)) {
return c_no_mic;
}
*env_var_name = *env_var_def = c;
if (strncmp(c, "ENV=", 4) == 0) {
if (!card_is_set) {
*env_var_name_length = 3;
*env_var_name = *env_var_def = c;
*env_var_def = strdup(*env_var_def);
return c_mic_var;
}
*env_var_def = c + strlen("ENV=");
*env_var_def = strdup(*env_var_def);
return c_mic_card_env;
}
if (isalpha(*c)) {
*env_var_name_length = 0;
while (isalnum(*c) || *c == '_') {
c++;
(*env_var_name_length)++;
}
}
if (*c != '=') {
return c_no_mic;
}
*env_var_def = strdup(*env_var_def);
return card_is_set? c_mic_card_var : c_mic_var;
}

// analysing <env-vars> in form:
// <mic-prefix>_<card-number>_ENV=<env-vars>
// where:
//
// <env-vars>:
// <env-var>
// <env-vars> | <env-var>
//
// <env-var>:
// variable=value
// variable="value"
// variable=

void MicEnvVar::mic_parse_env_var_list(
int card_number, char *env_vars_def_list)
{
char *c = env_vars_def_list;
char *env_var_name;
int env_var_name_length;
char *env_var_def;
bool var_is_quoted;

if (*c == '"') {
c++;
}
while (*c != 0) {
var_is_quoted = false;
env_var_name = c;
env_var_name_length = 0;
if (isalpha(*c)) {
while (isalnum(*c) || *c == '_') {
c++;
env_var_name_length++;
}
}
else {
LIBOFFLOAD_ERROR(c_mic_parse_env_var_list1);
return;
}
if (*c != '=') {
LIBOFFLOAD_ERROR(c_mic_parse_env_var_list2);
return;
}
c++;

if (*c == '"') {
var_is_quoted = true;
c++;
}
// Environment variable values that contain | will need to be escaped.
while (*c != 0 && *c != '|' &&
(!var_is_quoted || *c != '"'))
{
// skip escaped symbol
if (*c == '\\') {
c++;
}
c++;
}
if (var_is_quoted) {
c++; // for "
while (*c != 0 && *c != '|') {
c++;
}
}

int sz = c - env_var_name;
env_var_def = (char*)malloc(sz);
memcpy(env_var_def, env_var_name, sz);
env_var_def[sz] = 0;

if (*c == '|') {
c++;
while (*c != 0 && *c == ' ') {
c++;
}
}
add_env_var(card_number,
env_var_name,
env_var_name_length,
env_var_def);
}
}

// Collect all definitions for the card with number "card_num".
// The returned result is vector of string pointers defining one
// environment variable. The vector is terminated by NULL pointer.
// In the begining of the vector there are env vars defined as
// <mic-prefix>_<card-number>_<var>=<value>
// or
// <mic-prefix>_<card-number>_ENV=<env-vars>
// where <card-number> is equal to "card_num"
// They are followed by definitions valid for any card
// and absent in previous definitions.

char** MicEnvVar::create_environ_for_card(int card_num)
{
VarValue *var_value;
VarValue *var_value_find;
CardEnvVars *card_data = get_card(card_num);
CardEnvVars *card_data_common;
std::list<char*> new_env;
char **rez;

if (!prefix) {
return NULL;
}
// There is no personel env var definitions for the card with
// number "card_num"
if (!card_data) {
return create_environ_for_card(any_card);
}

for (std::list<MicEnvVar::VarValue*>::const_iterator
it = card_data->env_vars.begin();
it != card_data->env_vars.end(); it++) {
var_value = *it;
new_env.push_back(var_value->env_var_value);
}

if (card_num != any_card) {
card_data_common = get_card(any_card);
for (std::list<MicEnvVar::VarValue*>::const_iterator
it = card_data_common->env_vars.begin();
it != card_data_common->env_vars.end(); it++) {
var_value = *it;
var_value_find = card_data->find_var(var_value->env_var,
var_value->length);
if (!var_value_find) {
new_env.push_back(var_value->env_var_value);
}
}
}

int new_env_size = new_env.size();
rez = (char**) malloc((new_env_size + 1) * sizeof(char*));
std::copy(new_env.begin(), new_env.end(), rez);
rez[new_env_size] = 0;
return rez;
}
91 changes: 91 additions & 0 deletions openmp/offload/src/offload_env.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//


#ifndef OFFLOAD_ENV_H_INCLUDED
#define OFFLOAD_ENV_H_INCLUDED

#include <list>

// data structure and routines to parse MIC user environment and pass to MIC

enum MicEnvVarKind
{
c_no_mic, // not MIC env var
c_mic_var, // for <mic-prefix>_<var>
c_mic_card_var, // for <mic-prefix>_<card-number>_<var>
c_mic_card_env // for <mic-prefix>_<card-number>_ENV
};

struct MicEnvVar {
public:
MicEnvVar() : prefix(0) {}
~MicEnvVar();

void analyze_env_var(char *env_var_string);
char** create_environ_for_card(int card_num);
MicEnvVarKind get_env_var_kind(
char *env_var_string,
int *card_number,
char **env_var_name,
int *env_var_name_length,
char **env_var_def
);
void add_env_var(
int card_number,
char *env_var_name,
int env_var_name_length,
char *env_var_def
);

void set_prefix(const char *pref) {
prefix = (pref && *pref != '\0') ? pref : 0;
}

struct VarValue {
public:
char* env_var;
int length;
char* env_var_value;

VarValue(char* var, int ln, char* value)
{
env_var = var;
length = ln;
env_var_value = value;
}
~VarValue();
};

struct CardEnvVars {
public:

int card_number;
std::list<struct VarValue*> env_vars;

CardEnvVars() { card_number = any_card; }
CardEnvVars(int num) { card_number = num; }
~CardEnvVars();

void add_new_env_var(int number, char *env_var, int length,
char *env_var_value);
VarValue* find_var(char* env_var_name, int env_var_name_length);
};
static const int any_card;

private:
void mic_parse_env_var_list(int card_number, char *env_var_def);
CardEnvVars* get_card(int number);

const char *prefix;
std::list<struct CardEnvVars *> card_spec_list;
CardEnvVars common_vars;
};

#endif // OFFLOAD_ENV_H_INCLUDED
Loading