Add support for host/device stub functions for offload.
This commit is contained in:
2
lex.ll
2
lex.ll
@@ -49,6 +49,7 @@ static void lCppComment(SourcePos *);
|
|||||||
static void lHandleCppHash(SourcePos *);
|
static void lHandleCppHash(SourcePos *);
|
||||||
static void lStringConst(YYSTYPE *, SourcePos *);
|
static void lStringConst(YYSTYPE *, SourcePos *);
|
||||||
static double lParseHexFloat(const char *ptr);
|
static double lParseHexFloat(const char *ptr);
|
||||||
|
extern void RegisterDependency(const std::string &fileName);
|
||||||
|
|
||||||
#define YY_USER_ACTION \
|
#define YY_USER_ACTION \
|
||||||
yylloc.first_line = yylloc.last_line; \
|
yylloc.first_line = yylloc.last_line; \
|
||||||
@@ -662,6 +663,7 @@ static void lHandleCppHash(SourcePos *pos) {
|
|||||||
++src;
|
++src;
|
||||||
}
|
}
|
||||||
pos->name = strdup(filename.c_str());
|
pos->name = strdup(filename.c_str());
|
||||||
|
RegisterDependency(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
49
main.cpp
49
main.cpp
@@ -89,6 +89,7 @@ usage(int ret) {
|
|||||||
printf(" [--cpu=<cpu>]\t\t\tSelect target CPU type\n");
|
printf(" [--cpu=<cpu>]\t\t\tSelect target CPU type\n");
|
||||||
printf(" <cpu>={%s}\n", Target::SupportedTargetCPUs().c_str());
|
printf(" <cpu>={%s}\n", Target::SupportedTargetCPUs().c_str());
|
||||||
printf(" [-D<foo>]\t\t\t\t#define given value when running preprocessor\n");
|
printf(" [-D<foo>]\t\t\t\t#define given value when running preprocessor\n");
|
||||||
|
printf(" [--dev-stub <filename>]\t\tEmit device-side offload stub functions to file\n");
|
||||||
printf(" [--emit-asm]\t\t\tGenerate assembly language file as output\n");
|
printf(" [--emit-asm]\t\t\tGenerate assembly language file as output\n");
|
||||||
printf(" [--emit-c++]\t\t\tEmit a C++ source file as output\n");
|
printf(" [--emit-c++]\t\t\tEmit a C++ source file as output\n");
|
||||||
printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n");
|
printf(" [--emit-llvm]\t\t\tEmit LLVM bitode file as output\n");
|
||||||
@@ -96,6 +97,7 @@ usage(int ret) {
|
|||||||
printf(" [-g]\t\t\t\tGenerate debugging information\n");
|
printf(" [-g]\t\t\t\tGenerate debugging information\n");
|
||||||
printf(" [--help]\t\t\t\tPrint help\n");
|
printf(" [--help]\t\t\t\tPrint help\n");
|
||||||
printf(" [--help-dev]\t\t\tPrint help for developer options\n");
|
printf(" [--help-dev]\t\t\tPrint help for developer options\n");
|
||||||
|
printf(" [--host-stub <filename>]\t\tEmit host-side offload stub functions to file\n");
|
||||||
printf(" [-h <name>/--header-outfile=<name>]\tOutput filename for header\n");
|
printf(" [-h <name>/--header-outfile=<name>]\tOutput filename for header\n");
|
||||||
printf(" [-I <path>]\t\t\t\tAdd <path> to #include file search path\n");
|
printf(" [-I <path>]\t\t\t\tAdd <path> to #include file search path\n");
|
||||||
printf(" [--instrument]\t\t\tEmit instrumentation to gather performance data\n");
|
printf(" [--instrument]\t\t\tEmit instrumentation to gather performance data\n");
|
||||||
@@ -104,6 +106,7 @@ usage(int ret) {
|
|||||||
printf(" fast\t\t\t\tUse high-performance but lower-accuracy math functions\n");
|
printf(" fast\t\t\t\tUse high-performance but lower-accuracy math functions\n");
|
||||||
printf(" svml\t\t\t\tUse the Intel(r) SVML math libraries\n");
|
printf(" svml\t\t\t\tUse the Intel(r) SVML math libraries\n");
|
||||||
printf(" system\t\t\t\tUse the system's math library (*may be quite slow*)\n");
|
printf(" system\t\t\t\tUse the system's math library (*may be quite slow*)\n");
|
||||||
|
printf(" [-MMM <filename>\t\t\t\tWrite #include dependencies to given file.\n");
|
||||||
printf(" [--nostdlib]\t\t\tDon't make the ispc standard library available\n");
|
printf(" [--nostdlib]\t\t\tDon't make the ispc standard library available\n");
|
||||||
printf(" [--nocpp]\t\t\t\tDon't run the C preprocessor\n");
|
printf(" [--nocpp]\t\t\t\tDon't run the C preprocessor\n");
|
||||||
printf(" [-o <name>/--outfile=<name>]\tOutput filename (may be \"-\" for standard output)\n");
|
printf(" [-o <name>/--outfile=<name>]\tOutput filename (may be \"-\" for standard output)\n");
|
||||||
@@ -221,7 +224,9 @@ int main(int Argc, char *Argv[]) {
|
|||||||
const char *headerFileName = NULL;
|
const char *headerFileName = NULL;
|
||||||
const char *outFileName = NULL;
|
const char *outFileName = NULL;
|
||||||
const char *includeFileName = NULL;
|
const char *includeFileName = NULL;
|
||||||
|
const char *depsFileName = NULL;
|
||||||
|
const char *hostStubFileName = NULL;
|
||||||
|
const char *devStubFileName = NULL;
|
||||||
// Initiailize globals early so that we can set various option values
|
// Initiailize globals early so that we can set various option values
|
||||||
// as we're parsing below
|
// as we're parsing below
|
||||||
g = new Globals;
|
g = new Globals;
|
||||||
@@ -413,6 +418,27 @@ int main(int Argc, char *Argv[]) {
|
|||||||
extern int yydebug;
|
extern int yydebug;
|
||||||
yydebug = 1;
|
yydebug = 1;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(argv[i], "-MMM")) {
|
||||||
|
if (++i == argc) {
|
||||||
|
fprintf(stderr, "No output file name specified after -MMM option.\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
depsFileName = argv[i];
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[i], "--dev-stub")) {
|
||||||
|
if (++i == argc) {
|
||||||
|
fprintf(stderr, "No output file name specified after --dev-stub option.\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
devStubFileName = argv[i];
|
||||||
|
}
|
||||||
|
else if (!strcmp(argv[i], "--host-stub")) {
|
||||||
|
if (++i == argc) {
|
||||||
|
fprintf(stderr, "No output file name specified after --host-stub option.\n");
|
||||||
|
usage(1);
|
||||||
|
}
|
||||||
|
hostStubFileName = argv[i];
|
||||||
|
}
|
||||||
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
|
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
|
||||||
lPrintVersion();
|
lPrintVersion();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -456,12 +482,21 @@ int main(int Argc, char *Argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outFileName == NULL && headerFileName == NULL)
|
if (outFileName == NULL &&
|
||||||
Warning(SourcePos(), "No output file or header file name specified. "
|
headerFileName == NULL &&
|
||||||
"Program will be compiled and warnings/errors will "
|
depsFileName == NULL &&
|
||||||
"be issued, but no output will be generated.");
|
hostStubFileName == NULL &&
|
||||||
|
devStubFileName == NULL)
|
||||||
|
Warning(SourcePos(), "No output file or header file name specified. "
|
||||||
|
"Program will be compiled and warnings/errors will "
|
||||||
|
"be issued, but no output will be generated.");
|
||||||
|
|
||||||
return Module::CompileAndOutput(file, arch, cpu, target, generatePIC,
|
return Module::CompileAndOutput(file, arch, cpu, target, generatePIC,
|
||||||
ot, outFileName, headerFileName,
|
ot,
|
||||||
includeFileName);
|
outFileName,
|
||||||
|
headerFileName,
|
||||||
|
includeFileName,
|
||||||
|
depsFileName,
|
||||||
|
hostStubFileName,
|
||||||
|
devStubFileName);
|
||||||
}
|
}
|
||||||
|
|||||||
409
module.cpp
409
module.cpp
@@ -56,6 +56,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
#ifdef ISPC_IS_WINDOWS
|
#ifdef ISPC_IS_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
@@ -88,6 +90,18 @@
|
|||||||
#include <llvm/Support/raw_ostream.h>
|
#include <llvm/Support/raw_ostream.h>
|
||||||
#include <llvm/Bitcode/ReaderWriter.h>
|
#include <llvm/Bitcode/ReaderWriter.h>
|
||||||
|
|
||||||
|
/*! list of files encountered by the parser. this allows emitting of
|
||||||
|
the module file's dependencies via the -MMM option */
|
||||||
|
std::set<std::string> registeredDependencies;
|
||||||
|
|
||||||
|
/*! this is where the parser tells us that it has seen the given file
|
||||||
|
name in the CPP hash */
|
||||||
|
void RegisterDependency(const std::string &fileName)
|
||||||
|
{
|
||||||
|
if (fileName[0] != '<' && fileName != "stdlib.ispc")
|
||||||
|
registeredDependencies.insert(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable) {
|
lDeclareSizeAndPtrIntTypes(SymbolTable *symbolTable) {
|
||||||
const Type *ptrIntType = (g->target.is32Bit) ? AtomicType::VaryingInt32 :
|
const Type *ptrIntType = (g->target.is32Bit) ? AtomicType::VaryingInt32 :
|
||||||
@@ -880,6 +894,23 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
|
|||||||
strcasecmp(suffix, "hpp"))
|
strcasecmp(suffix, "hpp"))
|
||||||
fileType = "header";
|
fileType = "header";
|
||||||
break;
|
break;
|
||||||
|
case Deps:
|
||||||
|
break;
|
||||||
|
case DevStub:
|
||||||
|
if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") &&
|
||||||
|
strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") &&
|
||||||
|
strcasecmp(suffix, "cpp"))
|
||||||
|
fileType = "dev-side offload stub";
|
||||||
|
break;
|
||||||
|
case HostStub:
|
||||||
|
if (strcasecmp(suffix, "c") && strcasecmp(suffix, "cc") &&
|
||||||
|
strcasecmp(suffix, "c++") && strcasecmp(suffix, "cxx") &&
|
||||||
|
strcasecmp(suffix, "cpp"))
|
||||||
|
fileType = "host-side offload stub";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assert(0 /* swtich case not handled */);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
if (fileType != NULL)
|
if (fileType != NULL)
|
||||||
fprintf(stderr, "Warning: emitting %s file, but filename \"%s\" "
|
fprintf(stderr, "Warning: emitting %s file, but filename \"%s\" "
|
||||||
@@ -887,7 +918,13 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (outputType == Header)
|
if (outputType == Header)
|
||||||
return writeHeader(outFileName);
|
return writeHeader(outFileName);
|
||||||
|
else if (outputType == Deps)
|
||||||
|
return writeDeps(outFileName);
|
||||||
|
else if (outputType == HostStub)
|
||||||
|
return writeHostStub(outFileName);
|
||||||
|
else if (outputType == DevStub)
|
||||||
|
return writeDevStub(outFileName);
|
||||||
else if (outputType == Bitcode)
|
else if (outputType == Bitcode)
|
||||||
return writeBitcode(module, outFileName);
|
return writeBitcode(module, outFileName);
|
||||||
else if (outputType == CXX) {
|
else if (outputType == CXX) {
|
||||||
@@ -1187,18 +1224,28 @@ lGetExportedParamTypes(const std::vector<Symbol *> &funcs,
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs) {
|
lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs,
|
||||||
fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
|
bool useExternC=1) {
|
||||||
for (unsigned int i = 0; i < funcs.size(); ++i) {
|
if (useExternC)
|
||||||
const FunctionType *ftype = CastType<FunctionType>(funcs[i]->type);
|
fprintf(file, "#if defined(__cplusplus) && !defined(__ISPC_NO_EXTERN_C)\nextern \"C\" {\n#endif // __cplusplus\n");
|
||||||
Assert(ftype);
|
// fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
|
||||||
std::string decl = ftype->GetCDeclaration(funcs[i]->name);
|
for (unsigned int i = 0; i < funcs.size(); ++i) {
|
||||||
fprintf(file, " extern %s;\n", decl.c_str());
|
const FunctionType *ftype = CastType<FunctionType>(funcs[i]->type);
|
||||||
}
|
Assert(ftype);
|
||||||
fprintf(file, "#ifdef __cplusplus\n}\n#endif // __cplusplus\n");
|
std::string decl = ftype->GetCDeclaration(funcs[i]->name);
|
||||||
|
fprintf(file, " extern %s;\n", decl.c_str());
|
||||||
|
}
|
||||||
|
if (useExternC)
|
||||||
|
|
||||||
|
fprintf(file, "#if defined(__cplusplus) && !defined(__ISPC_NO_EXTERN_C)\n} /* end extern C */\n#endif // __cplusplus\n");
|
||||||
|
// fprintf(file, "#ifdef __cplusplus\n} /* end extern C */\n#endif // __cplusplus\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lIsExported(const Symbol *sym) {
|
lIsExported(const Symbol *sym) {
|
||||||
const FunctionType *ft = CastType<FunctionType>(sym->type);
|
const FunctionType *ft = CastType<FunctionType>(sym->type);
|
||||||
@@ -1215,6 +1262,312 @@ lIsExternC(const Symbol *sym) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Module::writeDeps(const char *fn) {
|
||||||
|
std::cout << "writing dependencies to file " << fn << std::endl;
|
||||||
|
FILE *file = fopen(fn,"w");
|
||||||
|
if (!file) {
|
||||||
|
perror("fopen");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::set<std::string>::const_iterator it=registeredDependencies.begin();
|
||||||
|
it != registeredDependencies.end();
|
||||||
|
++it)
|
||||||
|
fprintf(file,"%s\n",it->c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string emitOffloadParamStruct(const std::string ¶mStructName,
|
||||||
|
const Symbol *sym,
|
||||||
|
const FunctionType *fct)
|
||||||
|
{
|
||||||
|
std::stringstream out;
|
||||||
|
out << "struct " << paramStructName << " {" << std::endl;
|
||||||
|
|
||||||
|
for (int i=0;i<fct->GetNumParameters();i++) {
|
||||||
|
const Type *orgParamType = fct->GetParameterType(i);
|
||||||
|
if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) {
|
||||||
|
/* we're passing pointers separately -- no pointers in that struct... */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// const reference parameters can be passed as copies.
|
||||||
|
const Type *paramType;
|
||||||
|
if (orgParamType->IsReferenceType()) {
|
||||||
|
if (!orgParamType->IsConstType()) {
|
||||||
|
Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-const reference-type parameters.\n");
|
||||||
|
}
|
||||||
|
const ReferenceType *refType
|
||||||
|
= dynamic_cast<const ReferenceType*>(orgParamType);
|
||||||
|
paramType = refType->GetReferenceTarget()->GetAsNonConstType();
|
||||||
|
} else {
|
||||||
|
paramType = orgParamType->GetAsNonConstType();
|
||||||
|
}
|
||||||
|
std::string paramName = fct->GetParameterName(i);
|
||||||
|
std::string paramTypeName = paramType->GetString();
|
||||||
|
|
||||||
|
std::string tmpArgDecl = paramType->GetCDeclaration(paramName);
|
||||||
|
out << " " << tmpArgDecl << ";" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "};" << std::endl;
|
||||||
|
return out.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Module::writeDevStub(const char *fn)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fn, "w");
|
||||||
|
if (!file) {
|
||||||
|
perror("fopen");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn);
|
||||||
|
fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n");
|
||||||
|
fprintf(file,"#include \"ispc/dev/offload.h\"\n\n");
|
||||||
|
|
||||||
|
fprintf(file, "#include <stdint.h>\n\n");
|
||||||
|
|
||||||
|
// Collect single linear arrays of the *exported* functions (we'll
|
||||||
|
// treat those as "__kernel"s in IVL -- "extern" functions will only
|
||||||
|
// be used for dev-dev function calls; only "export" functions will
|
||||||
|
// get exported to the host
|
||||||
|
std::vector<Symbol *> exportedFuncs;
|
||||||
|
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
|
||||||
|
|
||||||
|
// Get all of the struct, vector, and enumerant types used as function
|
||||||
|
// parameters. These vectors may have repeats.
|
||||||
|
std::vector<const StructType *> exportedStructTypes;
|
||||||
|
std::vector<const EnumType *> exportedEnumTypes;
|
||||||
|
std::vector<const VectorType *> exportedVectorTypes;
|
||||||
|
lGetExportedParamTypes(exportedFuncs, &exportedStructTypes,
|
||||||
|
&exportedEnumTypes, &exportedVectorTypes);
|
||||||
|
|
||||||
|
// And print them
|
||||||
|
lEmitVectorTypedefs(exportedVectorTypes, file);
|
||||||
|
lEmitEnumDecls(exportedEnumTypes, file);
|
||||||
|
lEmitStructDecls(exportedStructTypes, file);
|
||||||
|
|
||||||
|
fprintf(file, "#ifdef __cplusplus\n");
|
||||||
|
fprintf(file, "namespace ispc {\n");
|
||||||
|
fprintf(file, "#endif // __cplusplus\n");
|
||||||
|
|
||||||
|
fprintf(file, "\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
fprintf(file, "// Functions exported from ispc code\n");
|
||||||
|
fprintf(file, "// (so the dev stub knows what to call)\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
lPrintFunctionDeclarations(file, exportedFuncs, true);
|
||||||
|
|
||||||
|
fprintf(file, "#ifdef __cplusplus\n");
|
||||||
|
fprintf(file, "}/* end namespace */\n");
|
||||||
|
fprintf(file, "#endif // __cplusplus\n");
|
||||||
|
|
||||||
|
fprintf(file, "\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
fprintf(file, "// actual dev stubs\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
|
||||||
|
fprintf(file, "// note(iw): due to some linking issues offload stubs *only* work under C++\n");
|
||||||
|
fprintf(file, "extern \"C\" {\n\n");
|
||||||
|
for (unsigned int i = 0; i < exportedFuncs.size(); ++i) {
|
||||||
|
const Symbol *sym = exportedFuncs[i];
|
||||||
|
Assert(sym);
|
||||||
|
const FunctionType *fct = CastType<FunctionType>(sym->type);
|
||||||
|
Assert(fct);
|
||||||
|
|
||||||
|
if (!fct->GetReturnType()->IsVoidType()) {
|
||||||
|
Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-void return types.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// first, emit a struct that holds the parameters
|
||||||
|
// -------------------------------------------------------
|
||||||
|
std::string paramStructName = std::string("__ispc_dev_stub_")+sym->name;
|
||||||
|
std::string paramStruct = emitOffloadParamStruct(paramStructName,sym,fct);
|
||||||
|
fprintf(file,"%s\n",paramStruct.c_str());
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// then, emit a fct stub that unpacks the parameters and pointers
|
||||||
|
// -------------------------------------------------------
|
||||||
|
fprintf(file,"void __ispc_dev_stub_%s(\n"
|
||||||
|
" uint32_t in_BufferCount,\n"
|
||||||
|
" void** in_ppBufferPointers,\n"
|
||||||
|
" uint64_t* in_pBufferLengths,\n"
|
||||||
|
" void* in_pMiscData,\n"
|
||||||
|
" uint16_t in_MiscDataLength,\n"
|
||||||
|
" void* in_pReturnValue,\n"
|
||||||
|
" uint16_t in_ReturnValueLength)\n",
|
||||||
|
sym->name.c_str()
|
||||||
|
);
|
||||||
|
fprintf(file,"{\n");
|
||||||
|
fprintf(file," struct %s args;\n memcpy(&args,in_pMiscData,sizeof(args));\n",
|
||||||
|
paramStructName.c_str());
|
||||||
|
std::stringstream funcall;
|
||||||
|
|
||||||
|
funcall << "ispc::" << sym->name << "(";
|
||||||
|
for (int i=0;i<fct->GetNumParameters();i++) {
|
||||||
|
// get param type and make it non-const, so we can write while unpacking
|
||||||
|
// const Type *paramType = fct->GetParameterType(i)->GetAsNonConstType();
|
||||||
|
const Type *paramType;// = fct->GetParameterType(i)->GetAsNonConstType();
|
||||||
|
const Type *orgParamType = fct->GetParameterType(i);
|
||||||
|
if (orgParamType->IsReferenceType()) {
|
||||||
|
if (!orgParamType->IsConstType()) {
|
||||||
|
Error(sym->pos,"When emitting offload-stubs, \"export\"ed functions cannot have non-const reference-type parameters.\n");
|
||||||
|
}
|
||||||
|
const ReferenceType *refType
|
||||||
|
= dynamic_cast<const ReferenceType*>(orgParamType);
|
||||||
|
paramType = refType->GetReferenceTarget()->GetAsNonConstType();
|
||||||
|
} else {
|
||||||
|
paramType = orgParamType->GetAsNonConstType();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string paramName = fct->GetParameterName(i);
|
||||||
|
std::string paramTypeName = paramType->GetString();
|
||||||
|
|
||||||
|
if (i) funcall << ", ";
|
||||||
|
std::string tmpArgName = std::string("_")+paramName;
|
||||||
|
if (paramType->IsPointerType() || paramType->IsArrayType()) {
|
||||||
|
std::string tmpArgDecl = paramType->GetCDeclaration(tmpArgName);
|
||||||
|
fprintf(file," %s;\n",
|
||||||
|
tmpArgDecl.c_str());
|
||||||
|
fprintf(file," (void *&)%s = ispc_dev_translate_pointer(*in_ppBufferPointers++);\n",
|
||||||
|
tmpArgName.c_str());
|
||||||
|
funcall << tmpArgName;
|
||||||
|
} else {
|
||||||
|
funcall << "args." << paramName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
funcall << ");";
|
||||||
|
fprintf(file," %s\n",funcall.str().c_str());
|
||||||
|
fprintf(file,"}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// end extern "C"
|
||||||
|
fprintf(file, "}/* end extern C */\n");
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Module::writeHostStub(const char *fn)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fn, "w");
|
||||||
|
if (!file) {
|
||||||
|
perror("fopen");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fprintf(file, "//\n// %s\n// (device stubs automatically generated by the ispc compiler.)\n", fn);
|
||||||
|
fprintf(file, "// DO NOT EDIT THIS FILE.\n//\n\n");
|
||||||
|
fprintf(file,"#include \"ispc/host/offload.h\"\n\n");
|
||||||
|
fprintf(file,"// note(iw): Host stubs do not get extern C linkage -- dev-side already uses that for the same symbols.\n\n");
|
||||||
|
//fprintf(file,"#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
|
||||||
|
|
||||||
|
fprintf(file, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n");
|
||||||
|
|
||||||
|
// Collect single linear arrays of the *exported* functions (we'll
|
||||||
|
// treat those as "__kernel"s in IVL -- "extern" functions will only
|
||||||
|
// be used for dev-dev function calls; only "export" functions will
|
||||||
|
// get exported to the host
|
||||||
|
std::vector<Symbol *> exportedFuncs;
|
||||||
|
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
|
||||||
|
|
||||||
|
// Get all of the struct, vector, and enumerant types used as function
|
||||||
|
// parameters. These vectors may have repeats.
|
||||||
|
std::vector<const StructType *> exportedStructTypes;
|
||||||
|
std::vector<const EnumType *> exportedEnumTypes;
|
||||||
|
std::vector<const VectorType *> exportedVectorTypes;
|
||||||
|
lGetExportedParamTypes(exportedFuncs, &exportedStructTypes,
|
||||||
|
&exportedEnumTypes, &exportedVectorTypes);
|
||||||
|
|
||||||
|
// And print them
|
||||||
|
lEmitVectorTypedefs(exportedVectorTypes, file);
|
||||||
|
lEmitEnumDecls(exportedEnumTypes, file);
|
||||||
|
lEmitStructDecls(exportedStructTypes, file);
|
||||||
|
|
||||||
|
fprintf(file, "\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
fprintf(file, "// host-side stubs for dev-side ISPC fucntion(s)\n");
|
||||||
|
fprintf(file, "///////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
for (unsigned int i = 0; i < exportedFuncs.size(); ++i) {
|
||||||
|
const Symbol *sym = exportedFuncs[i];
|
||||||
|
Assert(sym);
|
||||||
|
const FunctionType *fct = CastType<FunctionType>(sym->type);
|
||||||
|
Assert(fct);
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// first, emit a struct that holds the parameters
|
||||||
|
// -------------------------------------------------------
|
||||||
|
std::string paramStructName = std::string("__ispc_dev_stub_")+sym->name;
|
||||||
|
std::string paramStruct = emitOffloadParamStruct(paramStructName,sym,fct);
|
||||||
|
fprintf(file,"%s\n",paramStruct.c_str());
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// then, emit a fct stub that unpacks the parameters and pointers
|
||||||
|
// -------------------------------------------------------
|
||||||
|
|
||||||
|
std::string decl = fct->GetCDeclaration(sym->name);
|
||||||
|
fprintf(file, "extern %s {\n", decl.c_str());
|
||||||
|
int numPointers = 0;
|
||||||
|
fprintf(file, " %s __args;\n",paramStructName.c_str());
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// write args, and save pointers for later
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
std::stringstream pointerArgs;
|
||||||
|
for (int i=0;i<fct->GetNumParameters();i++) {
|
||||||
|
const Type *orgParamType = fct->GetParameterType(i);
|
||||||
|
std::string paramName = fct->GetParameterName(i);
|
||||||
|
if (orgParamType->IsPointerType() || orgParamType->IsArrayType()) {
|
||||||
|
/* we're passing pointers separately -- no pointers in that struct... */
|
||||||
|
if (numPointers)
|
||||||
|
pointerArgs << ",";
|
||||||
|
pointerArgs << "(void*)" << paramName;
|
||||||
|
numPointers++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(file," __args.%s = %s;\n",
|
||||||
|
paramName.c_str(),paramName.c_str());
|
||||||
|
}
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// writer pointer list
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
if (numPointers == 0)
|
||||||
|
pointerArgs << "NULL";
|
||||||
|
fprintf(file," void *ptr_args[] = { %s };\n" ,pointerArgs.str().c_str());
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// ... and call the kernel with those args
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
fprintf(file," static ispc_kernel_handle_t kernel_handle = NULL;\n");
|
||||||
|
fprintf(file," if (!kernel_handle) kernel_handle = ispc_host_get_kernel_handle(\"__ispc_dev_stub_%s\");\n",
|
||||||
|
sym->name.c_str());
|
||||||
|
fprintf(file," assert(kernel_handle);\n");
|
||||||
|
fprintf(file,
|
||||||
|
" ispc_host_call_kernel(kernel_handle,\n"
|
||||||
|
" &__args, sizeof(__args),\n"
|
||||||
|
" ptr_args,%i);\n",
|
||||||
|
numPointers);
|
||||||
|
fprintf(file,"}\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// end extern "C"
|
||||||
|
fprintf(file, "#ifdef __cplusplus\n");
|
||||||
|
fprintf(file, "}/* namespace */\n");
|
||||||
|
fprintf(file, "#endif // __cplusplus\n");
|
||||||
|
// fprintf(file, "#ifdef __cplusplus\n");
|
||||||
|
// fprintf(file, "}/* end extern C */\n");
|
||||||
|
// fprintf(file, "#endif // __cplusplus\n");
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Module::writeHeader(const char *fn) {
|
Module::writeHeader(const char *fn) {
|
||||||
FILE *f = fopen(fn, "w");
|
FILE *f = fopen(fn, "w");
|
||||||
@@ -1242,8 +1595,6 @@ Module::writeHeader(const char *fn) {
|
|||||||
|
|
||||||
fprintf(f, "#include <stdint.h>\n\n");
|
fprintf(f, "#include <stdint.h>\n\n");
|
||||||
|
|
||||||
fprintf(f, "#ifdef __cplusplus\nnamespace ispc {\n#endif // __cplusplus\n\n");
|
|
||||||
|
|
||||||
if (g->emitInstrumentation) {
|
if (g->emitInstrumentation) {
|
||||||
fprintf(f, "#define ISPC_INSTRUMENTATION 1\n");
|
fprintf(f, "#define ISPC_INSTRUMENTATION 1\n");
|
||||||
fprintf(f, "extern \"C\" {\n");
|
fprintf(f, "extern \"C\" {\n");
|
||||||
@@ -1251,6 +1602,11 @@ Module::writeHeader(const char *fn) {
|
|||||||
fprintf(f, "}\n");
|
fprintf(f, "}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// end namespace
|
||||||
|
fprintf(f, "\n");
|
||||||
|
fprintf(f, "\n#ifdef __cplusplus\nnamespace ispc { /* namespace */\n#endif // __cplusplus\n");
|
||||||
|
|
||||||
|
|
||||||
// Collect single linear arrays of the exported and extern "C"
|
// Collect single linear arrays of the exported and extern "C"
|
||||||
// functions
|
// functions
|
||||||
std::vector<Symbol *> exportedFuncs, externCFuncs;
|
std::vector<Symbol *> exportedFuncs, externCFuncs;
|
||||||
@@ -1303,7 +1659,8 @@ Module::writeHeader(const char *fn) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// end namespace
|
// end namespace
|
||||||
fprintf(f, "\n#ifdef __cplusplus\n}\n#endif // __cplusplus\n");
|
fprintf(f, "\n");
|
||||||
|
fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n");
|
||||||
|
|
||||||
// end guard
|
// end guard
|
||||||
fprintf(f, "\n#endif // %s\n", guard.c_str());
|
fprintf(f, "\n#endif // %s\n", guard.c_str());
|
||||||
@@ -1775,10 +2132,19 @@ lCreateDispatchModule(std::map<std::string, FunctionTargetVariants> &functions)
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
Module::CompileAndOutput(const char *srcFile, const char *arch, const char *cpu,
|
Module::CompileAndOutput(const char *srcFile,
|
||||||
const char *target, bool generatePIC, OutputType outputType,
|
const char *arch,
|
||||||
const char *outFileName, const char *headerFileName,
|
const char *cpu,
|
||||||
const char *includeFileName) {
|
const char *target,
|
||||||
|
bool generatePIC,
|
||||||
|
OutputType outputType,
|
||||||
|
const char *outFileName,
|
||||||
|
const char *headerFileName,
|
||||||
|
const char *includeFileName,
|
||||||
|
const char *depsFileName,
|
||||||
|
const char *hostStubFileName,
|
||||||
|
const char *devStubFileName)
|
||||||
|
{
|
||||||
if (target == NULL || strchr(target, ',') == NULL) {
|
if (target == NULL || strchr(target, ',') == NULL) {
|
||||||
// We're only compiling to a single target
|
// We're only compiling to a single target
|
||||||
if (!Target::GetTarget(arch, cpu, target, generatePIC, &g->target))
|
if (!Target::GetTarget(arch, cpu, target, generatePIC, &g->target))
|
||||||
@@ -1792,6 +2158,15 @@ Module::CompileAndOutput(const char *srcFile, const char *arch, const char *cpu,
|
|||||||
if (headerFileName != NULL)
|
if (headerFileName != NULL)
|
||||||
if (!m->writeOutput(Module::Header, headerFileName))
|
if (!m->writeOutput(Module::Header, headerFileName))
|
||||||
return 1;
|
return 1;
|
||||||
|
if (depsFileName != NULL)
|
||||||
|
if (!m->writeOutput(Module::Deps,depsFileName))
|
||||||
|
return 1;
|
||||||
|
if (hostStubFileName != NULL)
|
||||||
|
if (!m->writeOutput(Module::HostStub,hostStubFileName))
|
||||||
|
return 1;
|
||||||
|
if (devStubFileName != NULL)
|
||||||
|
if (!m->writeOutput(Module::DevStub,devStubFileName))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
++m->errorCount;
|
++m->errorCount;
|
||||||
|
|||||||
18
module.h
18
module.h
@@ -91,9 +91,12 @@ public:
|
|||||||
Bitcode, /** Generate LLVM IR bitcode output */
|
Bitcode, /** Generate LLVM IR bitcode output */
|
||||||
Object, /** Generate a native object file */
|
Object, /** Generate a native object file */
|
||||||
CXX, /** Generate a C++ file */
|
CXX, /** Generate a C++ file */
|
||||||
Header /** Generate a C/C++ header file with
|
Header, /** Generate a C/C++ header file with
|
||||||
declarations of 'export'ed functions, global
|
declarations of 'export'ed functions, global
|
||||||
variables, and the types used by them. */
|
variables, and the types used by them. */
|
||||||
|
Deps, /** generate dependencies */
|
||||||
|
DevStub, /** generate device-side offload stubs */
|
||||||
|
HostStub /** generate host-side offload stubs */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Compile the given source file, generating assembly, object file, or
|
/** Compile the given source file, generating assembly, object file, or
|
||||||
@@ -128,10 +131,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
static int CompileAndOutput(const char *srcFile, const char *arch,
|
static int CompileAndOutput(const char *srcFile, const char *arch,
|
||||||
const char *cpu, const char *targets,
|
const char *cpu, const char *targets,
|
||||||
bool generatePIC, OutputType outputType,
|
bool generatePIC,
|
||||||
|
OutputType outputType,
|
||||||
const char *outFileName,
|
const char *outFileName,
|
||||||
const char *headerFileName,
|
const char *headerFileName,
|
||||||
const char *includeFileName);
|
const char *includeFileName,
|
||||||
|
const char *depsFileName,
|
||||||
|
const char *hostStubFileName,
|
||||||
|
const char *devStubFileName);
|
||||||
|
|
||||||
/** Total number of errors encountered during compilation. */
|
/** Total number of errors encountered during compilation. */
|
||||||
int errorCount;
|
int errorCount;
|
||||||
@@ -159,6 +166,9 @@ private:
|
|||||||
bool writeOutput(OutputType ot, const char *filename,
|
bool writeOutput(OutputType ot, const char *filename,
|
||||||
const char *includeFileName = NULL);
|
const char *includeFileName = NULL);
|
||||||
bool writeHeader(const char *filename);
|
bool writeHeader(const char *filename);
|
||||||
|
bool writeDeps(const char *filename);
|
||||||
|
bool writeDevStub(const char *filename);
|
||||||
|
bool writeHostStub(const char *filename);
|
||||||
bool writeObjectFileOrAssembly(OutputType outputType, const char *filename);
|
bool writeObjectFileOrAssembly(OutputType outputType, const char *filename);
|
||||||
static bool writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine,
|
static bool writeObjectFileOrAssembly(llvm::TargetMachine *targetMachine,
|
||||||
llvm::Module *module, OutputType outputType,
|
llvm::Module *module, OutputType outputType,
|
||||||
|
|||||||
22
type.cpp
22
type.cpp
@@ -196,12 +196,32 @@ AtomicType::GetVariability() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Type::IsPointerType() const {
|
||||||
|
return (CastType<const PointerType*>(this) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Type::IsArrayType() const {
|
||||||
|
return (CastType<const ArrayType*>(this) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Type::IsReferenceType() const {
|
||||||
|
return (CastType<ReferenceType>(this) != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Type::IsVoidType() const {
|
||||||
|
return this == AtomicType::Void;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AtomicType::IsFloatType() const {
|
AtomicType::IsFloatType() const {
|
||||||
return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE);
|
return (basicType == TYPE_FLOAT || basicType == TYPE_DOUBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AtomicType::IsIntType() const {
|
AtomicType::IsIntType() const {
|
||||||
return (basicType == TYPE_INT8 || basicType == TYPE_UINT8 ||
|
return (basicType == TYPE_INT8 || basicType == TYPE_UINT8 ||
|
||||||
|
|||||||
12
type.h
12
type.h
@@ -115,6 +115,18 @@ public:
|
|||||||
integer types. */
|
integer types. */
|
||||||
virtual bool IsUnsignedType() const = 0;
|
virtual bool IsUnsignedType() const = 0;
|
||||||
|
|
||||||
|
/** Returns true if the underlying type is either a pointer type */
|
||||||
|
bool IsPointerType() const;
|
||||||
|
|
||||||
|
/** Returns true if the underlying type is a array type */
|
||||||
|
bool IsArrayType() const;
|
||||||
|
|
||||||
|
/** Returns true if the underlying type is a array type */
|
||||||
|
bool IsReferenceType() const;
|
||||||
|
|
||||||
|
/** Returns true if the underlying type is either a pointer or an array */
|
||||||
|
bool IsVoidType() const;
|
||||||
|
|
||||||
/** Returns true if this type is 'const'-qualified. */
|
/** Returns true if this type is 'const'-qualified. */
|
||||||
virtual bool IsConstType() const = 0;
|
virtual bool IsConstType() const = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user