Merge pull request #687 from jbrodman/nomosoa

Add support for pointers to varying data in exported functions.
This commit is contained in:
Dmitry Babokin
2014-01-13 09:03:45 -08:00
8 changed files with 488 additions and 59 deletions

View File

@@ -4743,13 +4743,13 @@ have a declaration like:
};
Because ``varying`` types have size that depends on the size of the gang of
program instances, ``ispc`` prohibits any varying types from being used in
parameters to functions with the ``export`` qualifier. (``ispc`` also
prohibits passing structures that themselves have varying types as members,
etc.) Thus, all datatypes that are shared with the application must have
the ``uniform`` or ``soa`` rate qualifier applied to them. (See `Use
"Structure of Arrays" Layout When Possible`_ in the Performance Guide for
more discussion of how to load vectors of SOA data from the application.)
program instances, ``ispc`` has restrictrictions on using varying types in
parameters to functions with the ``export`` qualifier. ``ispc `` prohibits
parameters to exported functions to have varying type unless the parameter is
of pointer type. (That is, ``varying float`` isn't allowed, but ``varying float * uniform``
(uniform pointer to varying float) is permitted.) Care must be taken
by the programmer to ensure that the data being accessed through any
pointers to varying data has the correct organization.
Similarly, ``struct`` types shared with the application can also have
embedded pointers.
@@ -4770,6 +4770,30 @@ On the ``ispc`` side, the corresponding ``struct`` declaration is:
float * uniform foo, * uniform bar;
};
If a pointer to a varying ``struct`` type appears in an exported function,
the generated header file will have a definition like (for 8-wide SIMD):
::
// C/C++ code
struct Node {
int count[8];
float pos[3][8];
};
In the case of multiple target compilation, ``ispc`` will generate multiple
header files and a "general" header file with definitions for multiple sizes.
Any pointers to varyings in exported functions will be rewritten as ``void *``.
At runtime, the ``ispc`` dispatch mechanism will cast these pointers to the appropriate
types. Programmers can
provide C/C++ code with a mechanism to determine the gang width used
at runtime by ``ispc`` by creating an exported function that simply
returns the value of ``programCount``. An example of such a function
is provided in the file ``examples/util/util.isph`` included in the ``ispc``
distribution.
There is one subtlety related to data layout to be aware of: ``ispc``
stores ``uniform`` short-vector types in memory with their first element at
the machine's natural vector alignment (i.e. 16 bytes for a target that is

View File

@@ -69,6 +69,7 @@ static PerfTest tests[] = {
{ xyzSumAOS, "serial", ispc::xyzSumAOSStdlib, "ispc", "AOS vector element sum (stdlib swizzle)" },
{ xyzSumAOS, "serial", ispc::xyzSumAOSNoCoalesce, "ispc", "AOS vector element sum (no coalescing)" },
{ xyzSumSOA, "serial", ispc::xyzSumSOA, "ispc", "SOA vector element sum" },
{ xyzSumSOA, "serial", (FuncType *) ispc::xyzSumVarying, "ispc", "Varying vector element sum" },
{ ispc::gathers, "gather", ispc::loads, "vector load", "Memory reads" },
{ ispc::scatters, "scatter", ispc::stores, "vector store", "Memory writes" },
};

View File

@@ -104,6 +104,52 @@ export void xyzSumSOA(uniform float array[], uniform int count,
result[2] = reduce_add(zsum);
}
export void xyzSumVarying(varying float array[], uniform int count,
uniform float zeros[], uniform float result[]) {
float xsum = 0, ysum = 0, zsum = 0;
varying float * uniform ap = array;
assert(programCount <= 8);
if (programCount == 4) {
for (uniform int i = 0; i < count/3; i += 8) {
float x0 = ap[0];
float y0 = ap[2];
float z0 = ap[4];
xsum += x0;
ysum += y0;
zsum += z0;
float x1 = ap[1];
float y1 = ap[3];
float z1 = ap[5];
xsum += x1;
ysum += y1;
zsum += z1;
ap += 6;
}
}
else {
for (uniform int i = 0; i < count/3; i += 8) {
// programCount == 8
float x = ap[0];
float y = ap[1];
float z = ap[2];
xsum += x;
ysum += y;
zsum += z;
ap += 3;
}
}
result[0] = reduce_add(xsum);
result[1] = reduce_add(ysum);
result[2] = reduce_add(zsum);
}
export void gathers(uniform float array[], uniform int count,
uniform float zeros[], uniform float result[]) {
float sum = 0;

5
examples/util/util.isph Normal file
View File

@@ -0,0 +1,5 @@
// utility function to read the value of programCount from C/C++
export uniform int32 get_programCount() {
return programCount;
}

View File

@@ -567,9 +567,7 @@ Module::AddGlobalVariable(const std::string &name, const Type *type, Expr *initE
/** Given an arbitrary type, see if it or any of the leaf types contained
in it has a type that's illegal to have exported to C/C++
code--specifically, that it has a varying value in memory, or a pointer
to SOA data (which has a different representation than a regular
pointer.
code.
(Note that it's fine for the original struct or a contained struct to
be varying, so long as all of its members have bound 'uniform'
@@ -601,15 +599,18 @@ lRecursiveCheckValidParamType(const Type *t, bool vectorOk) {
const PointerType *pt = CastType<PointerType>(t);
if (pt != NULL) {
if (pt->IsSlice() || pt->IsVaryingType())
return false;
// Only allow exported uniform pointers
// Uniform pointers to varying data, however, are ok.
if (pt->IsVaryingType())
return false;
else
return lRecursiveCheckValidParamType(pt->GetBaseType(), true);
}
if (t->IsVaryingType())
return false;
else
return true;
if (t->IsVaryingType() && !vectorOk)
return false;
else
return true;
}
@@ -625,8 +626,8 @@ lCheckExportedParameterTypes(const Type *type, const std::string &name,
if (CastType<PointerType>(type))
Error(pos, "Varying pointer type parameter \"%s\" is illegal "
"in an exported function.", name.c_str());
else if (CastType<StructType>(type->GetBaseType()))
Error(pos, "Struct parameter \"%s\" with varying or vector typed "
if (CastType<StructType>(type->GetBaseType()))
Error(pos, "Struct parameter \"%s\" with vector typed "
"member(s) is illegal in an exported function.", name.c_str());
else if (CastType<VectorType>(type))
Error(pos, "Vector-typed parameter \"%s\" is illegal in an exported "
@@ -830,9 +831,11 @@ Module::AddFunctionDeclaration(const std::string &name,
const SourcePos &argPos = functionType->GetParameterSourcePos(i);
// If the function is exported, make sure that the parameter
// doesn't have any varying stuff going on in it.
if (functionType->isExported)
lCheckExportedParameterTypes(argType, argName, argPos);
// doesn't have any funky stuff going on in it.
// JCB nomosoa - Varying is now a-ok.
if (functionType->isExported) {
lCheckExportedParameterTypes(argType, argName, argPos);
}
// ISPC assumes that no pointers alias. (It should be possible to
// specify when this is not the case, but this should be the
@@ -935,7 +938,7 @@ Module::AddExportedTypes(const std::vector<std::pair<const Type *,
bool
Module::writeOutput(OutputType outputType, const char *outFileName,
const char *includeFileName) {
const char *includeFileName, DispatchHeaderInfo *DHI) {
if (diBuilder != NULL && (outputType != Header && outputType != Deps)) {
diBuilder->finalize();
@@ -996,8 +999,12 @@ Module::writeOutput(OutputType outputType, const char *outFileName,
"has suffix \"%s\"?", fileType, outFileName, suffix);
}
if (outputType == Header)
return writeHeader(outFileName);
if (outputType == Header) {
if (DHI)
return writeDispatchHeader(DHI);
else
return writeHeader(outFileName);
}
else if (outputType == Deps)
return writeDeps(outFileName);
else if (outputType == HostStub)
@@ -1121,6 +1128,19 @@ lGetElementStructType(const Type *t) {
return NULL;
}
static bool
lContainsPtrToVarying(const StructType *st) {
int numElts = st->GetElementCount();
for (int j = 0; j < numElts; ++j) {
const Type *t = st->GetElementType(j);
if (t->IsVaryingType()) return true;
}
return false;
}
/** Emits a declaration for the given struct to the given file. This
function first makes sure that declarations for any structs that are
@@ -1128,7 +1148,14 @@ lGetElementStructType(const Type *t) {
*/
static void
lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedStructs,
FILE *file) {
FILE *file, bool printGenericHeader=false, bool emitUnifs=true) {
// if we're emitting this for a generic dispatch header file and it's
// struct that only contains uniforms, don't bother if we're emitting uniforms
if (printGenericHeader && !emitUnifs && !lContainsPtrToVarying(st)) {
return;
}
// Has this struct type already been declared? (This happens if it's a
// member of another struct for which we emitted a declaration
// previously.)
@@ -1141,19 +1168,33 @@ lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedSt
const StructType *elementStructType =
lGetElementStructType(st->GetElementType(i));
if (elementStructType != NULL)
lEmitStructDecl(elementStructType, emittedStructs, file);
lEmitStructDecl(elementStructType, emittedStructs, file, printGenericHeader, emitUnifs);
}
// And now it's safe to declare this one
emittedStructs->push_back(st);
fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetStructName().c_str());
fprintf(file, "#define __ISPC_STRUCT_%s__\n",st->GetStructName().c_str());
if (printGenericHeader && lContainsPtrToVarying(st)) {
fprintf(file, "#ifndef __ISPC_STRUCT_%s%d__\n",
st->GetStructName().c_str(),
g->target->getVectorWidth());
fprintf(file, "#define __ISPC_STRUCT_%s%d__\n",
st->GetStructName().c_str(),
g->target->getVectorWidth());
}
else {
fprintf(file, "#ifndef __ISPC_STRUCT_%s__\n",st->GetStructName().c_str());
fprintf(file, "#define __ISPC_STRUCT_%s__\n",st->GetStructName().c_str());
}
fprintf(file, "struct %s", st->GetStructName().c_str());
if (st->GetSOAWidth() > 0)
// This has to match the naming scheme in
// StructType::GetCDeclaration().
fprintf(file, "_SOA%d", st->GetSOAWidth());
if (printGenericHeader && lContainsPtrToVarying(st)) {
fprintf(file, "%d", g->target->getVectorWidth());
}
fprintf(file, " {\n");
for (int i = 0; i < st->GetElementCount(); ++i) {
@@ -1170,10 +1211,10 @@ lEmitStructDecl(const StructType *st, std::vector<const StructType *> *emittedSt
header file, emit their declarations.
*/
static void
lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file) {
lEmitStructDecls(std::vector<const StructType *> &structTypes, FILE *file, bool printGenericHeader=false, bool emitUnifs=true) {
std::vector<const StructType *> emittedStructs;
for (unsigned int i = 0; i < structTypes.size(); ++i)
lEmitStructDecl(structTypes[i], &emittedStructs, file);
lEmitStructDecl(structTypes[i], &emittedStructs, file, printGenericHeader, emitUnifs);
}
@@ -1338,14 +1379,20 @@ lGetExportedParamTypes(const std::vector<Symbol *> &funcs,
static void
lPrintFunctionDeclarations(FILE *file, const std::vector<Symbol *> &funcs,
bool useExternC=1) {
bool useExternC=1, bool rewriteForDispatch=false) {
if (useExternC)
fprintf(file, "#if defined(__cplusplus) && !defined(__ISPC_NO_EXTERN_C)\nextern \"C\" {\n#endif // __cplusplus\n");
// fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif // __cplusplus\n");
for (unsigned int i = 0; i < funcs.size(); ++i) {
const FunctionType *ftype = CastType<FunctionType>(funcs[i]->type);
Assert(ftype);
std::string decl = ftype->GetCDeclaration(funcs[i]->name);
std::string decl;
if (rewriteForDispatch) {
decl = ftype->GetCDeclarationForDispatch(funcs[i]->name);
}
else {
decl = ftype->GetCDeclaration(funcs[i]->name);
}
fprintf(file, " extern %s;\n", decl.c_str());
}
if (useExternC)
@@ -1791,6 +1838,137 @@ Module::writeHeader(const char *fn) {
return true;
}
struct DispatchHeaderInfo {
bool EmitUnifs;
bool EmitFuncs;
bool EmitFrontMatter;
bool EmitBackMatter;
bool Emit4;
bool Emit8;
bool Emit16;
FILE *file;
const char *fn;
};
bool
Module::writeDispatchHeader(DispatchHeaderInfo *DHI) {
FILE *f = DHI->file;
if (DHI->EmitFrontMatter) {
fprintf(f, "//\n// %s\n// (Header automatically generated by the ispc compiler.)\n", DHI->fn);
fprintf(f, "// DO NOT EDIT THIS FILE.\n//\n\n");
}
// Create a nice guard string from the filename, turning any
// non-number/letter characters into underbars
std::string guard = "ISPC_";
const char *p = DHI->fn;
while (*p) {
if (isdigit(*p))
guard += *p;
else if (isalpha(*p))
guard += toupper(*p);
else
guard += "_";
++p;
}
if (DHI->EmitFrontMatter) {
fprintf(f, "#ifndef %s\n#define %s\n\n", guard.c_str(), guard.c_str());
fprintf(f, "#include <stdint.h>\n\n");
if (g->emitInstrumentation) {
fprintf(f, "#define ISPC_INSTRUMENTATION 1\n");
fprintf(f, "extern \"C\" {\n");
fprintf(f, " void ISPCInstrument(const char *fn, const char *note, int line, uint64_t mask);\n");
fprintf(f, "}\n");
}
// end namespace
fprintf(f, "\n");
fprintf(f, "\n#ifdef __cplusplus\nnamespace ispc { /* namespace */\n#endif // __cplusplus\n\n");
DHI->EmitFrontMatter = false;
}
// Collect single linear arrays of the exported and extern "C"
// functions
std::vector<Symbol *> exportedFuncs, externCFuncs;
m->symbolTable->GetMatchingFunctions(lIsExported, &exportedFuncs);
m->symbolTable->GetMatchingFunctions(lIsExternC, &externCFuncs);
int programCount = g->target->getVectorWidth();
if ((DHI->Emit4 && (programCount == 4)) ||
(DHI->Emit8 && (programCount == 8)) ||
(DHI->Emit16 && (programCount == 16))) {
// 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);
lGetExportedParamTypes(externCFuncs, &exportedStructTypes,
&exportedEnumTypes, &exportedVectorTypes);
// Go through the explicitly exported types
for (int i = 0; i < (int)exportedTypes.size(); ++i) {
if (const StructType *st = CastType<StructType>(exportedTypes[i].first))
exportedStructTypes.push_back(st->GetAsUniformType());
else if (const EnumType *et = CastType<EnumType>(exportedTypes[i].first))
exportedEnumTypes.push_back(et->GetAsUniformType());
else if (const VectorType *vt = CastType<VectorType>(exportedTypes[i].first))
exportedVectorTypes.push_back(vt->GetAsUniformType());
else
FATAL("Unexpected type in export list");
}
// And print them
if (DHI->EmitUnifs) {
lEmitVectorTypedefs(exportedVectorTypes, f);
lEmitEnumDecls(exportedEnumTypes, f);
}
lEmitStructDecls(exportedStructTypes, f, true, DHI->EmitUnifs);
// Update flags
DHI->EmitUnifs = false;
if (programCount == 4) {
DHI->Emit4 = false;
}
else if (programCount == 8) {
DHI->Emit8 = false;
}
else if (programCount == 16) {
DHI->Emit16 = false;
}
}
if (DHI->EmitFuncs) {
// emit function declarations for exported stuff...
if (exportedFuncs.size() > 0) {
fprintf(f, "\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
fprintf(f, "// Functions exported from ispc code\n");
fprintf(f, "///////////////////////////////////////////////////////////////////////////\n");
lPrintFunctionDeclarations(f, exportedFuncs, 1, true);
fprintf(f, "\n");
}
DHI->EmitFuncs = false;
}
if (DHI->EmitBackMatter) {
// end namespace
fprintf(f, "\n");
fprintf(f, "\n#ifdef __cplusplus\n} /* namespace */\n#endif // __cplusplus\n");
// end guard
fprintf(f, "\n#endif // %s\n", guard.c_str());
DHI->EmitBackMatter = false;
}
return true;
}
void
Module::execPreprocessor(const char *infilename, llvm::raw_string_ostream *ostream) const
@@ -1988,13 +2166,16 @@ lSymbolIsExported(const Symbol *s) {
// llvm::Function that were compiled for different compilation target ISAs.
struct FunctionTargetVariants {
FunctionTargetVariants() {
for (int i = 0; i < Target::NUM_ISAS; ++i)
for (int i = 0; i < Target::NUM_ISAS; ++i) {
func[i] = NULL;
FTs[i] = NULL;
}
}
// The func array is indexed with the Target::ISA enumerant. Some
// values may be NULL, indicating that the original function wasn't
// compiled to the corresponding target ISA.
llvm::Function *func[Target::NUM_ISAS];
const FunctionType *FTs[Target::NUM_ISAS];
};
@@ -2009,6 +2190,7 @@ lGetExportedFunctions(SymbolTable *symbolTable,
for (unsigned int i = 0; i < syms.size(); ++i) {
FunctionTargetVariants &ftv = functions[syms[i]->name];
ftv.func[g->target->getISA()] = syms[i]->exportedFunction;
ftv.FTs[g->target->getISA()] = CastType<FunctionType>(syms[i]->type);
}
}
@@ -2115,6 +2297,51 @@ lAddExtractedGlobals(llvm::Module *module,
}
}
static llvm::FunctionType *
lGetVaryingDispatchType(FunctionTargetVariants &funcs) {
llvm::Type *ptrToInt8Ty = llvm::Type::getInt8PtrTy(*g->ctx);
llvm::FunctionType *resultFuncTy = NULL;
for (int i = 0; i < Target::NUM_ISAS; ++i) {
if (funcs.func[i] == NULL) {
continue;
}
else {
bool foundVarying = false;
const FunctionType *ft = funcs.FTs[i];
resultFuncTy = funcs.func[i]->getFunctionType();
int numArgs = ft->GetNumParameters();
llvm::SmallVector<llvm::Type *, 8> ftype;
for (int j = 0; j < numArgs; ++j) {
ftype.push_back(resultFuncTy->getParamType(j));
}
for (int j = 0; j < numArgs; ++j) {
const Type *arg = ft->GetParameterType(j);
if (arg->IsPointerType()) {
const Type *baseType = CastType<PointerType>(arg)->GetBaseType();
// For each varying type pointed to, swap the LLVM pointer type
// with i8 * (as close as we can get to void *)
if (baseType->IsVaryingType()) {
ftype[j] = ptrToInt8Ty;
foundVarying = true;
}
}
}
if (foundVarying) {
resultFuncTy = llvm::FunctionType::get(resultFuncTy->getReturnType(), ftype, false);
}
}
}
// We should've found at least one variant here
// or else something fishy is going on.
Assert(resultFuncTy);
return resultFuncTy;
}
/** Create the dispatch function for an exported ispc function.
This function checks to see which vector ISAs the system the
@@ -2142,11 +2369,12 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
// we'll start by generating an 'extern' declaration of each one that
// we have in the current module so that we can then call out to that.
llvm::Function *targetFuncs[Target::NUM_ISAS];
llvm::FunctionType *ftype = NULL;
llvm::FunctionType *ftypes[Target::NUM_ISAS];
for (int i = 0; i < Target::NUM_ISAS; ++i) {
if (funcs.func[i] == NULL) {
targetFuncs[i] = NULL;
ftypes[i] = NULL;
continue;
}
@@ -2157,14 +2385,23 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
// because we only allow uniform stuff to pass through the
// export'ed function layer, they should all have the same memory
// layout, so this is benign..
if (ftype == NULL)
ftype = funcs.func[i]->getFunctionType();
// JCB nomosoa - not anymore...
// add a helper to see if this type has any varying thingies?
// might be hard to detect....
// If so, return a new type with the pointers to those replaced
// by i8 *'s.
// if (ftype == NULL)
ftypes[i] = funcs.func[i]->getFunctionType();
targetFuncs[i] =
llvm::Function::Create(ftype, llvm::GlobalValue::ExternalLinkage,
llvm::Function::Create(ftypes[i], llvm::GlobalValue::ExternalLinkage,
funcs.func[i]->getName(), module);
}
// New helper function checks to see if we need to rewrite the
// type for the dispatch function in case of pointers to varyings
llvm::FunctionType *ftype = lGetVaryingDispatchType(funcs);
bool voidReturn = ftype->getReturnType()->isVoidTy();
// Now we can emit the definition of the dispatch function..
@@ -2209,8 +2446,21 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
// the target-specific function.
std::vector<llvm::Value *> args;
llvm::Function::arg_iterator argIter = dispatchFunc->arg_begin();
for (; argIter != dispatchFunc->arg_end(); ++argIter)
llvm::Function::arg_iterator targsIter = targetFuncs[i]->arg_begin();
for (; argIter != dispatchFunc->arg_end(); ++argIter, ++targsIter) {
// Check to see if we rewrote any types in the dispatch function.
// If so, create bitcasts for the appropriate pointer types.
if (argIter->getType() == targsIter->getType()) {
args.push_back(argIter);
}
else {
llvm::CastInst *argCast =
llvm::CastInst::CreatePointerCast(argIter, targsIter->getType(),
"dpatch_arg_bitcast", callBBlock);
args.push_back(argCast);
}
}
if (voidReturn) {
llvm::CallInst::Create(targetFuncs[i], args, "", callBBlock);
llvm::ReturnInst::Create(*g->ctx, callBBlock);
@@ -2247,7 +2497,6 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
}
}
// Given a map that holds the mapping from each of the 'export'ed functions
// in the ispc program to the target-specific variants of the function,
// create a llvm::Module that has a dispatch function for each exported
@@ -2387,6 +2636,28 @@ Module::CompileAndOutput(const char *srcFile,
std::map<std::string, FunctionTargetVariants> exportedFunctions;
std::vector<RewriteGlobalInfo> globals[Target::NUM_ISAS];
int errorCount = 0;
// Handle creating a "generic" header file for multiple targets
// that use exported varyings
DispatchHeaderInfo DHI;
if ((targets.size() > 1) && (headerFileName != NULL)) {
DHI.file = fopen(headerFileName, "w");
if (!DHI.file) {
perror("fopen");
return false;
}
DHI.fn = headerFileName;
DHI.EmitUnifs = true;
DHI.EmitFuncs = true;
DHI.EmitFrontMatter = true;
DHI.Emit4 = true;
DHI.Emit8 = true;
DHI.Emit16 = true;
// This is toggled later.
DHI.EmitBackMatter = false;
}
for (unsigned int i = 0; i < targets.size(); ++i) {
g->target = new Target(arch, cpu, targets[i].c_str(), generatePIC);
if (!g->target->isValid())
@@ -2423,9 +2694,26 @@ Module::CompileAndOutput(const char *srcFile,
// Only write the generate header file, if desired, the first
// time through the loop here.
if (i == 0 && headerFileName != NULL)
if (!m->writeOutput(Module::Header, headerFileName))
return 1;
if (headerFileName != NULL) {
if (i == targets.size()-1) {
// only print backmatter on the last target.
DHI.EmitBackMatter = true;
}
const char *isaName = g->target->GetISAString();
std::string targetHeaderFileName =
lGetTargetFileName(headerFileName, isaName);
// write out a header w/o target name for the first target only
if (!m->writeOutput(Module::Header, headerFileName, "", &DHI)) {
return 1;
}
if (!m->writeOutput(Module::Header, targetHeaderFileName.c_str())) {
return 1;
}
if (i == targets.size()-1) {
fclose(DHI.file);
}
}
delete g->target;
g->target = NULL;

View File

@@ -50,6 +50,8 @@ namespace llvm
class raw_string_ostream;
}
struct DispatchHeaderInfo;
class Module {
public:
/** The name of the source file being compiled should be passed as the
@@ -171,8 +173,10 @@ private:
filename may be NULL, indicating that output should go to standard
output. */
bool writeOutput(OutputType ot, const char *filename,
const char *includeFileName = NULL);
const char *includeFileName = NULL,
DispatchHeaderInfo *DHI = 0);
bool writeHeader(const char *filename);
bool writeDispatchHeader(DispatchHeaderInfo *DHI);
bool writeDeps(const char *filename);
bool writeDevStub(const char *filename);
bool writeHostStub(const char *filename);

View File

@@ -429,8 +429,7 @@ AtomicType::Mangle() const {
std::string
AtomicType::GetCDeclaration(const std::string &name) const {
std::string ret;
if (variability != Variability::Uniform &&
variability != Variability::SOA) {
if (variability == Variability::Unbound) {
Assert(m->errorCount > 0);
return ret;
}
@@ -457,9 +456,15 @@ AtomicType::GetCDeclaration(const std::string &name) const {
ret += name;
}
if (variability == Variability::SOA) {
if (variability == Variability::Varying ||
variability == Variability::SOA) {
char buf[32];
sprintf(buf, "[%d]", variability.soaWidth);
// get program count
// g->mangleFunctionsNamesWithTarget - hack check for void *
int vWidth = (variability == Variability::Varying) ?
g->target->getVectorWidth() :
variability.soaWidth;
sprintf(buf, "[%d]", vWidth);
ret += buf;
}
@@ -751,8 +756,7 @@ EnumType::Mangle() const {
std::string
EnumType::GetCDeclaration(const std::string &varName) const {
if (variability != Variability::Uniform &&
variability != Variability::SOA) {
if (variability == Variability::Unbound) {
Assert(m->errorCount > 0);
return "";
}
@@ -768,9 +772,13 @@ EnumType::GetCDeclaration(const std::string &varName) const {
ret += varName;
}
if (variability == Variability::SOA) {
if (variability == Variability::SOA ||
variability == Variability::Varying) {
int vWidth = (variability == Variability::Varying) ?
g->target->getVectorWidth() :
variability.soaWidth;
char buf[32];
sprintf(buf, "[%d]", variability.soaWidth);
sprintf(buf, "[%d]", vWidth);
ret += buf;
}
@@ -1077,8 +1085,7 @@ PointerType::Mangle() const {
std::string
PointerType::GetCDeclaration(const std::string &name) const {
if (isSlice ||
(variability != Variability::Uniform &&
variability != Variability::SOA)) {
(variability == Variability::Unbound)) {
Assert(m->errorCount > 0);
return "";
}
@@ -1094,9 +1101,13 @@ PointerType::GetCDeclaration(const std::string &name) const {
ret += std::string(" ");
ret += name;
if (variability == Variability::SOA) {
if (variability == Variability::SOA ||
variability == Variability::Varying) {
int vWidth = (variability == Variability::Varying) ?
g->target->getVectorWidth() :
variability.soaWidth;
char buf[32];
sprintf(buf, "[%d]", variability.soaWidth);
sprintf(buf, "[%d]", vWidth);
ret += buf;
}
@@ -1422,6 +1433,7 @@ ArrayType::GetCDeclaration(const std::string &name) const {
}
int soaWidth = base->GetSOAWidth();
int vWidth = (base->IsVaryingType()) ? g->target->getVectorWidth() : 0;
base = base->GetAsUniformType();
std::string s = base->GetCDeclaration(name);
@@ -1443,6 +1455,12 @@ ArrayType::GetCDeclaration(const std::string &name) const {
s += buf;
}
if (vWidth > 0) {
char buf[16];
sprintf(buf, "[%d]", vWidth);
s += buf;
}
return s;
}
@@ -2851,13 +2869,55 @@ FunctionType::GetCDeclaration(const std::string &fname) const {
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
if (paramNames[i] != "")
ret += type->GetCDeclaration(paramNames[i]);
ret += type->GetCDeclaration(paramNames[i]);
else
ret += type->GetString();
ret += type->GetString();
if (i != paramTypes.size() - 1)
ret += ", ";
ret += ", ";
}
ret += ")";
return ret;
}
std::string
FunctionType::GetCDeclarationForDispatch(const std::string &fname) const {
std::string ret;
ret += returnType->GetCDeclaration("");
ret += " ";
ret += fname;
ret += "(";
for (unsigned int i = 0; i < paramTypes.size(); ++i) {
const Type *type = paramTypes[i];
// Convert pointers to arrays to unsized arrays, which are more clear
// to print out for multidimensional arrays (i.e. "float foo[][4] "
// versus "float (foo *)[4]").
const PointerType *pt = CastType<PointerType>(type);
if (pt != NULL &&
CastType<ArrayType>(pt->GetBaseType()) != NULL) {
type = new ArrayType(pt->GetBaseType(), 0);
}
// Change pointers to varying thingies to void *
if (pt != NULL && pt->GetBaseType()->IsVaryingType()) {
PointerType *t = PointerType::Void;
if (paramNames[i] != "")
ret += t->GetCDeclaration(paramNames[i]);
else
ret += t->GetString();
}
else {
if (paramNames[i] != "")
ret += type->GetCDeclaration(paramNames[i]);
else
ret += type->GetString();
}
if (i != paramTypes.size() - 1)
ret += ", ";
}
ret += ")";
return ret;

1
type.h
View File

@@ -872,6 +872,7 @@ public:
std::string GetString() const;
std::string Mangle() const;
std::string GetCDeclaration(const std::string &fname) const;
std::string GetCDeclarationForDispatch(const std::string &fname) const;
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;