Add support for forward declarations of structures.
Now a declaration like 'struct Foo;' can be used to establish the name of a struct type, without providing a definition. One can pass pointers to such types around the system, but can't do much else with them (as in C/C++). Issue #125.
This commit is contained in:
24
ctx.cpp
24
ctx.cpp
@@ -2609,14 +2609,22 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr,
|
||||
const PointerType *pt = dynamic_cast<const PointerType *>(valueType);
|
||||
if (pt != NULL) {
|
||||
if (pt->IsSlice()) {
|
||||
// For masked stores of (varying) slice pointers to memory, we
|
||||
// grab the equivalent StructType and make a recursive call to
|
||||
// maskedStore, giving it that type for the pointer type; that
|
||||
// in turn will lead to the base pointer and offset index being
|
||||
// mask stored to memory..
|
||||
const StructType *sliceStructType = pt->GetSliceStructType();
|
||||
ptrType = PointerType::GetUniform(sliceStructType);
|
||||
maskedStore(value, ptr, ptrType, mask);
|
||||
// Masked store of (varying) slice pointer.
|
||||
Assert(pt->IsVaryingType());
|
||||
|
||||
// First, extract the pointer from the slice struct and masked
|
||||
// store that.
|
||||
llvm::Value *v0 = ExtractInst(value, 0);
|
||||
llvm::Value *p0 = AddElementOffset(ptr, 0, ptrType);
|
||||
maskedStore(v0, p0, PointerType::GetUniform(pt->GetAsNonSlice()),
|
||||
mask);
|
||||
|
||||
// And then do same for the integer offset
|
||||
llvm::Value *v1 = ExtractInst(value, 1);
|
||||
llvm::Value *p1 = AddElementOffset(ptr, 1, ptrType);
|
||||
const Type *offsetType = AtomicType::VaryingInt32;
|
||||
maskedStore(v1, p1, PointerType::GetUniform(offsetType), mask);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
13
expr.cpp
13
expr.cpp
@@ -4692,12 +4692,13 @@ MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos,
|
||||
exprType = pointerType->GetBaseType();
|
||||
|
||||
if (derefLValue == true && pointerType == NULL) {
|
||||
if (dynamic_cast<const StructType *>(exprType->GetReferenceTarget()) != NULL)
|
||||
Error(p, "Dereference operator \"->\" can't be applied to non-pointer "
|
||||
const Type *targetType = exprType->GetReferenceTarget();
|
||||
if (dynamic_cast<const StructType *>(targetType) != NULL)
|
||||
Error(p, "Member operator \"->\" can't be applied to non-pointer "
|
||||
"type \"%s\". Did you mean to use \".\"?",
|
||||
exprType->GetString().c_str());
|
||||
else
|
||||
Error(p, "Dereference operator \"->\" can't be applied to non-struct "
|
||||
Error(p, "Member operator \"->\" can't be applied to non-struct "
|
||||
"pointer type \"%s\".", exprType->GetString().c_str());
|
||||
return NULL;
|
||||
}
|
||||
@@ -4713,6 +4714,12 @@ MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos,
|
||||
return new StructMemberExpr(e, id, p, idpos, derefLValue);
|
||||
else if (dynamic_cast<const VectorType *>(exprType) != NULL)
|
||||
return new VectorMemberExpr(e, id, p, idpos, derefLValue);
|
||||
else if (dynamic_cast<const UndefinedStructType *>(exprType)) {
|
||||
Error(p, "Member operator \"%s\" can't be applied to declared "
|
||||
"but not defined struct type \"%s\".", derefLValue ? "->" : ".",
|
||||
exprType->GetString().c_str());
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
Error(p, "Member operator \"%s\" can't be used with expression of "
|
||||
"\"%s\" type.", derefLValue ? "->" : ".",
|
||||
|
||||
12
module.cpp
12
module.cpp
@@ -1477,10 +1477,14 @@ lCreateDispatchFunction(llvm::Module *module, llvm::Function *setISAFunc,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab the type of the function as well.
|
||||
if (ftype != NULL)
|
||||
Assert(ftype == funcs.func[i]->getFunctionType());
|
||||
else
|
||||
// Grab the type of the function as well. Note that the various
|
||||
// functions will have different types if they have arguments that
|
||||
// are pointers to structs, due to the fact that we mangle LLVM
|
||||
// struct type names with the target vector width. However,
|
||||
// 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();
|
||||
|
||||
targetFuncs[i] =
|
||||
|
||||
8
parse.yy
8
parse.yy
@@ -874,7 +874,6 @@ struct_or_union_specifier
|
||||
std::vector<SourcePos> elementPositions;
|
||||
GetStructTypesNamesPositions(*$3, &elementTypes, &elementNames,
|
||||
&elementPositions);
|
||||
// FIXME: should be unbound
|
||||
$$ = new StructType("", elementTypes, elementNames, elementPositions,
|
||||
false, Variability::Unbound, @1);
|
||||
}
|
||||
@@ -892,10 +891,9 @@ struct_or_union_specifier
|
||||
| struct_or_union struct_or_union_name
|
||||
{
|
||||
const Type *st = m->symbolTable->LookupType($2);
|
||||
if (!st) {
|
||||
std::vector<std::string> alternates = m->symbolTable->ClosestTypeMatch($2);
|
||||
std::string alts = lGetAlternates(alternates);
|
||||
Error(@2, "Struct type \"%s\" unknown.%s", $2, alts.c_str());
|
||||
if (st == NULL) {
|
||||
st = new UndefinedStructType($2, Variability::Unbound, false, @2);
|
||||
m->symbolTable->AddType($2, st, @2);
|
||||
}
|
||||
else if (dynamic_cast<const StructType *>(st) == NULL)
|
||||
Error(@2, "Type \"%s\" is not a struct type! (%s)", $2,
|
||||
|
||||
95
sym.cpp
95
sym.cpp
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011, Intel Corporation
|
||||
Copyright (c) 2010-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -66,7 +66,7 @@ SymbolTable::SymbolTable() {
|
||||
|
||||
SymbolTable::~SymbolTable() {
|
||||
// Otherwise we have mismatched push/pop scopes
|
||||
Assert(variables.size() == 1 && types.size() == 1);
|
||||
Assert(variables.size() == 1);
|
||||
PopScope();
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ SymbolTable::~SymbolTable() {
|
||||
void
|
||||
SymbolTable::PushScope() {
|
||||
variables.push_back(new SymbolMapType);
|
||||
types.push_back(new TypeMapType);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +82,6 @@ SymbolTable::PopScope() {
|
||||
Assert(variables.size() > 1);
|
||||
delete variables.back();
|
||||
variables.pop_back();
|
||||
|
||||
Assert(types.size() > 1);
|
||||
delete types.back();
|
||||
types.pop_back();
|
||||
}
|
||||
|
||||
|
||||
@@ -186,26 +181,17 @@ SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
|
||||
|
||||
bool
|
||||
SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {
|
||||
// Like AddVariable(), we go backwards through the type maps, working
|
||||
// from innermost scope to outermost.
|
||||
for (int i = types.size()-1; i >= 0; --i) {
|
||||
TypeMapType &sm = *(types[i]);
|
||||
if (sm.find(name) != sm.end()) {
|
||||
if (i == (int)types.size() - 1) {
|
||||
Error(pos, "Ignoring redefinition of type \"%s\".", name);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
Warning(pos, "Type \"%s\" shadows type declared in outer scope.", name);
|
||||
TypeMapType &sm = *(types.back());
|
||||
sm[name] = type;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const Type *t = LookupType(name);
|
||||
if (t != NULL && dynamic_cast<const UndefinedStructType *>(t) == NULL) {
|
||||
// If we have a previous declaration of anything other than an
|
||||
// UndefinedStructType with this struct name, issue an error. If
|
||||
// we have an UndefinedStructType, then we'll fall through to the
|
||||
// code below that adds the definition to the type map.
|
||||
Error(pos, "Ignoring redefinition of type \"%s\".", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeMapType &sm = *(types.back());
|
||||
sm[name] = type;
|
||||
types[name] = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -213,11 +199,9 @@ SymbolTable::AddType(const char *name, const Type *type, SourcePos pos) {
|
||||
const Type *
|
||||
SymbolTable::LookupType(const char *name) const {
|
||||
// Again, search through the type maps backward to get scoping right.
|
||||
for (int i = types.size()-1; i >= 0; --i) {
|
||||
TypeMapType &sm = *(types[i]);
|
||||
if (sm.find(name) != sm.end())
|
||||
return sm[name];
|
||||
}
|
||||
TypeMapType::const_iterator iter = types.find(name);
|
||||
if (iter != types.end())
|
||||
return iter->second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -282,21 +266,19 @@ SymbolTable::closestTypeMatch(const char *str, bool structsVsEnums) const {
|
||||
const int maxDelta = 2;
|
||||
std::vector<std::string> matches[maxDelta+1];
|
||||
|
||||
for (unsigned int i = 0; i < types.size(); ++i) {
|
||||
TypeMapType::const_iterator iter;
|
||||
for (iter = types[i]->begin(); iter != types[i]->end(); ++iter) {
|
||||
// Skip over either StructTypes or EnumTypes, depending on the
|
||||
// value of the structsVsEnums parameter
|
||||
bool isEnum = (dynamic_cast<const EnumType *>(iter->second) != NULL);
|
||||
if (isEnum && structsVsEnums)
|
||||
continue;
|
||||
else if (!isEnum && !structsVsEnums)
|
||||
continue;
|
||||
TypeMapType::const_iterator iter;
|
||||
for (iter = types.begin(); iter != types.end(); ++iter) {
|
||||
// Skip over either StructTypes or EnumTypes, depending on the
|
||||
// value of the structsVsEnums parameter
|
||||
bool isEnum = (dynamic_cast<const EnumType *>(iter->second) != NULL);
|
||||
if (isEnum && structsVsEnums)
|
||||
continue;
|
||||
else if (!isEnum && !structsVsEnums)
|
||||
continue;
|
||||
|
||||
int dist = StringEditDistance(str, iter->first, maxDelta+1);
|
||||
if (dist <= maxDelta)
|
||||
matches[dist].push_back(iter->first);
|
||||
}
|
||||
int dist = StringEditDistance(str, iter->first, maxDelta+1);
|
||||
if (dist <= maxDelta)
|
||||
matches[dist].push_back(iter->first);
|
||||
}
|
||||
|
||||
for (int i = 0; i <= maxDelta; ++i) {
|
||||
@@ -336,16 +318,12 @@ SymbolTable::Print() {
|
||||
|
||||
depth = 0;
|
||||
fprintf(stderr, "Named types:\n---------------\n");
|
||||
for (unsigned int i = 0; i < types.size(); ++i) {
|
||||
TypeMapType &sm = *types[i];
|
||||
TypeMapType::iterator siter = sm.begin();
|
||||
while (siter != sm.end()) {
|
||||
fprintf(stderr, "%*c", depth, ' ');
|
||||
fprintf(stderr, "%s -> %s\n", siter->first.c_str(),
|
||||
siter->second->GetString().c_str());
|
||||
++siter;
|
||||
}
|
||||
depth += 4;
|
||||
TypeMapType::iterator siter = types.begin();
|
||||
while (siter != types.end()) {
|
||||
fprintf(stderr, "%*c", depth, ' ');
|
||||
fprintf(stderr, "%s -> %s\n", siter->first.c_str(),
|
||||
siter->second->GetString().c_str());
|
||||
++siter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,14 +354,11 @@ SymbolTable::RandomSymbol() {
|
||||
|
||||
const Type *
|
||||
SymbolTable::RandomType() {
|
||||
int v = ispcRand() % types.size();
|
||||
if (types[v]->size() == 0)
|
||||
return NULL;
|
||||
int count = ispcRand() % types[v]->size();
|
||||
TypeMapType::iterator iter = types[v]->begin();
|
||||
int count = types.size();
|
||||
TypeMapType::iterator iter = types.begin();
|
||||
while (count-- > 0) {
|
||||
++iter;
|
||||
Assert(iter != types[v]->end());
|
||||
Assert(iter != types.end());
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
11
sym.h
11
sym.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2010-2011, Intel Corporation
|
||||
Copyright (c) 2010-2012, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@@ -201,6 +201,9 @@ public:
|
||||
/** Adds the named type to the symbol table. This is used for both
|
||||
struct definitions (where <tt>struct Foo</tt> causes type \c Foo to
|
||||
be added to the symbol table) as well as for <tt>typedef</tt>s.
|
||||
For structs with forward declarations ("struct Foo;") and are thus
|
||||
UndefinedStructTypes, this method replaces these with an actual
|
||||
struct definition if one is provided.
|
||||
|
||||
@param name Name of the type to be added
|
||||
@param type Type that \c name represents
|
||||
@@ -265,12 +268,10 @@ private:
|
||||
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
|
||||
FunctionMapType functions;
|
||||
|
||||
/** Type definitions can also be scoped. A new \c TypeMapType
|
||||
is added to the back of the \c types \c vector each time a new scope
|
||||
is entered. (And it's removed when the scope exits).
|
||||
/** Type definitions can't currently be scoped.
|
||||
*/
|
||||
typedef std::map<std::string, const Type *> TypeMapType;
|
||||
std::vector<TypeMapType *> types;
|
||||
TypeMapType types;
|
||||
};
|
||||
|
||||
|
||||
|
||||
36
tests/struct-forward-decl-2.ispc
Normal file
36
tests/struct-forward-decl-2.ispc
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
struct Foo;
|
||||
|
||||
void bing(Foo * uniform);
|
||||
|
||||
struct Foo {
|
||||
int i;
|
||||
varying float f;
|
||||
Foo * uniform next;
|
||||
};
|
||||
|
||||
void bar(Foo * uniform f) {
|
||||
bing(f);
|
||||
}
|
||||
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
uniform Foo fa, fb;
|
||||
fa.next = &fb;
|
||||
fb.f = aFOO[programIndex];
|
||||
fb.i = 100;
|
||||
bar(&fa);
|
||||
RET[programIndex] = fb.f;
|
||||
}
|
||||
|
||||
|
||||
void bing(Foo * uniform f) {
|
||||
f = f->next;
|
||||
f->f *= 2;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 2 + 2*programIndex;
|
||||
}
|
||||
33
tests/struct-forward-decl.ispc
Normal file
33
tests/struct-forward-decl.ispc
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
struct Foo;
|
||||
|
||||
void bing(varying Foo * uniform);
|
||||
|
||||
struct Foo {
|
||||
float f;
|
||||
int i;
|
||||
};
|
||||
|
||||
void bar(varying Foo * uniform f) {
|
||||
bing(f);
|
||||
}
|
||||
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
Foo f;
|
||||
f.f = aFOO[programIndex];
|
||||
f.i = programIndex;
|
||||
bar(&f);
|
||||
RET[programIndex] = f.f;
|
||||
}
|
||||
|
||||
|
||||
void bing(varying Foo * uniform f) {
|
||||
f->f *= 2;
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = 2 + 2*programIndex;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Dereference operator "->" can't be applied to non-pointer type "varying struct Foo"
|
||||
// Member operator "->" can't be applied to non-pointer type "varying struct Foo"
|
||||
|
||||
struct Foo { int x; };
|
||||
|
||||
|
||||
5
tests_errors/struct-ref-undecl-1.ispc
Normal file
5
tests_errors/struct-ref-undecl-1.ispc
Normal file
@@ -0,0 +1,5 @@
|
||||
// Member operator "." can't be applied to declared but not defined struct type
|
||||
|
||||
struct Foo;
|
||||
|
||||
int bar(Foo & foo) { return foo.x; }
|
||||
5
tests_errors/struct-ref-undecl-2.ispc
Normal file
5
tests_errors/struct-ref-undecl-2.ispc
Normal file
@@ -0,0 +1,5 @@
|
||||
// Member operator "->" can't be applied to declared but not defined struct type
|
||||
|
||||
struct Foo;
|
||||
|
||||
int bar(Foo * uniform foo) { return foo->x; }
|
||||
417
type.cpp
417
type.cpp
@@ -42,6 +42,7 @@
|
||||
#include "module.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <map>
|
||||
#include <llvm/Value.h>
|
||||
#include <llvm/Module.h>
|
||||
#include <llvm/Analysis/DIBuilder.h>
|
||||
@@ -59,7 +60,7 @@ static bool
|
||||
lShouldPrintName(const std::string &name) {
|
||||
if (name.size() == 0)
|
||||
return false;
|
||||
else if (name[0] != '_')
|
||||
else if (name[0] != '_' && name[0] != '$')
|
||||
return true;
|
||||
else
|
||||
return (name.size() == 1) || (name[1] != '_');
|
||||
@@ -946,42 +947,6 @@ PointerType::GetAsFrozenSlice() const {
|
||||
}
|
||||
|
||||
|
||||
/** Returns a structure corresponding to the pointer representation for
|
||||
slice pointers; the first member of this structure is a uniform or
|
||||
varying pointer, and the second element is either a uniform or varying
|
||||
int32.
|
||||
*/
|
||||
const StructType *
|
||||
PointerType::GetSliceStructType() const {
|
||||
Assert(isSlice == true);
|
||||
|
||||
std::vector<const Type *> eltTypes;
|
||||
eltTypes.push_back(GetAsNonSlice());
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform:
|
||||
eltTypes.push_back(AtomicType::UniformInt32);
|
||||
break;
|
||||
case Variability::Varying:
|
||||
eltTypes.push_back(AtomicType::VaryingInt32);
|
||||
break;
|
||||
default:
|
||||
FATAL("Unexpected variability in PointerType::GetSliceStructType()");
|
||||
}
|
||||
|
||||
std::vector<std::string> eltNames;
|
||||
std::vector<SourcePos> eltPos;
|
||||
|
||||
eltNames.push_back("ptr");
|
||||
eltNames.push_back("offset");
|
||||
|
||||
eltPos.push_back(SourcePos());
|
||||
eltPos.push_back(SourcePos());
|
||||
|
||||
return new StructType("__ptr_slice_tmp", eltTypes, eltNames, eltPos, isConst,
|
||||
Variability::Uniform, SourcePos());
|
||||
}
|
||||
|
||||
|
||||
const PointerType *
|
||||
PointerType::ResolveUnboundVariability(Variability v) const {
|
||||
if (baseType == NULL) {
|
||||
@@ -1090,11 +1055,30 @@ PointerType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (isSlice)
|
||||
// Slice pointers are represented as a structure with a pointer and
|
||||
// an integer offset; the corresponding ispc type is returned by
|
||||
// GetSliceStructType().
|
||||
return GetSliceStructType()->LLVMType(ctx);
|
||||
if (isSlice) {
|
||||
llvm::Type *types[2];
|
||||
types[0] = GetAsNonSlice()->LLVMType(ctx);
|
||||
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform:
|
||||
types[1] = LLVMTypes::Int32Type;
|
||||
break;
|
||||
case Variability::Varying:
|
||||
types[1] = LLVMTypes::Int32VectorType;
|
||||
break;
|
||||
case Variability::SOA:
|
||||
types[1] = llvm::ArrayType::get(LLVMTypes::Int32Type,
|
||||
variability.soaWidth);
|
||||
break;
|
||||
default:
|
||||
FATAL("unexpected variability for slice pointer in "
|
||||
"PointerType::LLVMType");
|
||||
}
|
||||
|
||||
llvm::ArrayRef<llvm::Type *> typesArrayRef =
|
||||
llvm::ArrayRef<llvm::Type *>(types, 2);
|
||||
return llvm::StructType::get(*g->ctx, typesArrayRef);
|
||||
}
|
||||
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform: {
|
||||
@@ -1721,12 +1705,103 @@ VectorType::getVectorMemoryCount() const {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// StructType
|
||||
|
||||
// We maintain a map from struct names to LLVM struct types so that we can
|
||||
// uniquely get the llvm::StructType * for a given ispc struct type. Note
|
||||
// that we need to mangle the name a bit so that we can e.g. differentiate
|
||||
// between the uniform and varying variants of a given struct type. This
|
||||
// is handled by lMangleStructName() below.
|
||||
static std::map<std::string, llvm::StructType *> lStructTypeMap;
|
||||
|
||||
/** Using a struct's name, its variability, and the vector width for the
|
||||
current compilation target, this function generates a string that
|
||||
encodes that full structure type, for use in the lStructTypeMap. Note
|
||||
that the vector width is needed in order to differentiate between
|
||||
'varying' structs with different compilation targets, which have
|
||||
different memory layouts...
|
||||
*/
|
||||
static std::string
|
||||
lMangleStructName(const std::string &name, Variability variability) {
|
||||
char buf[32];
|
||||
std::string n;
|
||||
|
||||
// Encode vector width
|
||||
sprintf(buf, "v%d", g->target.vectorWidth);
|
||||
n += buf;
|
||||
|
||||
// Variability
|
||||
switch (variability.type) {
|
||||
case Variability::Uniform:
|
||||
n += "_uniform_";
|
||||
break;
|
||||
case Variability::Varying:
|
||||
n += "_varying_";
|
||||
break;
|
||||
case Variability::SOA:
|
||||
sprintf(buf, "_soa%d_", variability.soaWidth);
|
||||
n += buf;
|
||||
break;
|
||||
default:
|
||||
FATAL("Unexpected varaibility in lMangleStructName()");
|
||||
}
|
||||
|
||||
// And stuff the name at the end....
|
||||
n += name;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
StructType::StructType(const std::string &n, const std::vector<const Type *> &elts,
|
||||
const std::vector<std::string> &en,
|
||||
const std::vector<SourcePos> &ep,
|
||||
bool ic, Variability v, SourcePos p)
|
||||
: name(n), elementTypes(elts), elementNames(en), elementPositions(ep),
|
||||
variability(v), isConst(ic), pos(p) {
|
||||
if (variability != Variability::Unbound) {
|
||||
// For structs with non-unbound variability, we'll create the
|
||||
// correspoing LLVM struct type now, if one hasn't been made
|
||||
// already.
|
||||
|
||||
// Create a unique anonymous struct name if we have an anonymous
|
||||
// struct (name == ""), or if we are creating a derived type from
|
||||
// an anonymous struct (e.g. the varying variant--name == '$').
|
||||
if (name == "" || name[0] == '$') {
|
||||
char buf[16];
|
||||
static int count = 0;
|
||||
sprintf(buf, "$anon%d", count);
|
||||
name = buf;
|
||||
++count;
|
||||
}
|
||||
|
||||
// If a non-opaque LLVM struct for this type has already been
|
||||
// created, we're done. For an opaque struct type, we'll override
|
||||
// the old definition now that we have a full definition.
|
||||
std::string mname = lMangleStructName(name, variability);
|
||||
if (lStructTypeMap.find(mname) != lStructTypeMap.end() &&
|
||||
lStructTypeMap[mname]->isOpaque() == false)
|
||||
return;
|
||||
|
||||
// Actually make the LLVM struct
|
||||
std::vector<llvm::Type *> elementTypes;
|
||||
for (int i = 0; i < GetElementCount(); ++i) {
|
||||
const Type *type = GetElementType(i);
|
||||
if (type == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return;
|
||||
}
|
||||
elementTypes.push_back(type->LLVMType(g->ctx));
|
||||
}
|
||||
|
||||
if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
|
||||
// New struct definition
|
||||
llvm::StructType *st =
|
||||
llvm::StructType::create(*g->ctx, elementTypes, mname);
|
||||
lStructTypeMap[mname] = st;
|
||||
}
|
||||
else {
|
||||
// Definition for what was before just a declaration
|
||||
lStructTypeMap[mname]->setBody(elementTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1854,31 +1929,34 @@ StructType::GetAsNonConstType() const {
|
||||
std::string
|
||||
StructType::GetString() const {
|
||||
std::string ret;
|
||||
if (isConst) ret += "const ";
|
||||
if (isConst)
|
||||
ret += "const ";
|
||||
ret += variability.GetString();
|
||||
ret += " ";
|
||||
|
||||
// Don't print the entire struct declaration, just print the struct's name.
|
||||
// @todo Do we need a separate method that prints the declaration?
|
||||
#if 0
|
||||
ret += std::string("struct { ") + name;
|
||||
for (unsigned int i = 0; i < elementTypes.size(); ++i) {
|
||||
ret += elementTypes[i]->GetString();
|
||||
ret += " ";
|
||||
ret += elementNames[i];
|
||||
ret += "; ";
|
||||
if (name[0] == '$') {
|
||||
// Print the whole anonymous struct declaration
|
||||
ret += std::string("struct { ") + name;
|
||||
for (unsigned int i = 0; i < elementTypes.size(); ++i) {
|
||||
ret += elementTypes[i]->GetString();
|
||||
ret += " ";
|
||||
ret += elementNames[i];
|
||||
ret += "; ";
|
||||
}
|
||||
ret += "}";
|
||||
}
|
||||
ret += "}";
|
||||
#else
|
||||
ret += "struct ";
|
||||
ret += name;
|
||||
#endif
|
||||
else {
|
||||
ret += "struct ";
|
||||
ret += name;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StructType::Mangle() const {
|
||||
/** Mangle a struct name for use in function name mangling. */
|
||||
static std::string
|
||||
lMangleStruct(Variability variability, bool isConst, const std::string &name) {
|
||||
Assert(variability != Variability::Unbound);
|
||||
|
||||
std::string ret;
|
||||
@@ -1890,6 +1968,12 @@ StructType::Mangle() const {
|
||||
ret += name + std::string("]");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
StructType::Mangle() const {
|
||||
return lMangleStruct(variability, isConst, name);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
@@ -1897,15 +1981,16 @@ StructType::GetCDeclaration(const std::string &n) const {
|
||||
std::string ret;
|
||||
if (isConst) ret += "const ";
|
||||
ret += std::string("struct ") + name;
|
||||
if (lShouldPrintName(n))
|
||||
if (lShouldPrintName(n)) {
|
||||
ret += std::string(" ") + n;
|
||||
|
||||
if (variability.soaWidth > 0) {
|
||||
char buf[32];
|
||||
// This has to match the naming scheme used in lEmitStructDecls()
|
||||
// in module.cpp
|
||||
sprintf(buf, "_SOA%d", variability.soaWidth);
|
||||
ret += buf;
|
||||
if (variability.soaWidth > 0) {
|
||||
char buf[32];
|
||||
// This has to match the naming scheme used in lEmitStructDecls()
|
||||
// in module.cpp
|
||||
sprintf(buf, "_SOA%d", variability.soaWidth);
|
||||
ret += buf;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1914,14 +1999,13 @@ StructType::GetCDeclaration(const std::string &n) const {
|
||||
|
||||
llvm::Type *
|
||||
StructType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
std::vector<llvm::Type *> llvmTypes;
|
||||
for (int i = 0; i < GetElementCount(); ++i) {
|
||||
const Type *type = GetElementType(i);
|
||||
if (type == NULL)
|
||||
return NULL;
|
||||
llvmTypes.push_back(type->LLVMType(ctx));
|
||||
Assert(variability != Variability::Unbound);
|
||||
std::string mname = lMangleStructName(name, variability);
|
||||
if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
return llvm::StructType::get(*ctx, llvmTypes);
|
||||
return lStructTypeMap[mname];
|
||||
}
|
||||
|
||||
|
||||
@@ -2037,6 +2121,170 @@ StructType::checkIfCanBeSOA(const StructType *st) {
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// UndefinedStructType
|
||||
|
||||
UndefinedStructType::UndefinedStructType(const std::string &n,
|
||||
const Variability var, bool ic,
|
||||
SourcePos p)
|
||||
: name(n), variability(var), isConst(ic), pos(p) {
|
||||
Assert(name != "");
|
||||
if (variability != Variability::Unbound) {
|
||||
// Create a new opaque LLVM struct type for this struct name
|
||||
std::string mname = lMangleStructName(name, variability);
|
||||
if (lStructTypeMap.find(mname) == lStructTypeMap.end())
|
||||
lStructTypeMap[mname] = llvm::StructType::create(*g->ctx, mname);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Variability
|
||||
UndefinedStructType::GetVariability() const {
|
||||
return variability;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UndefinedStructType::IsBoolType() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UndefinedStructType::IsFloatType() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UndefinedStructType::IsIntType() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UndefinedStructType::IsUnsignedType() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UndefinedStructType::IsConstType() const {
|
||||
return isConst;
|
||||
}
|
||||
|
||||
|
||||
const Type *
|
||||
UndefinedStructType::GetBaseType() const {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsVaryingType() const {
|
||||
if (variability == Variability::Varying)
|
||||
return this;
|
||||
return new UndefinedStructType(name, Variability::Varying, isConst, pos);
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsUniformType() const {
|
||||
if (variability == Variability::Uniform)
|
||||
return this;
|
||||
return new UndefinedStructType(name, Variability::Uniform, isConst, pos);
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsUnboundVariabilityType() const {
|
||||
if (variability == Variability::Unbound)
|
||||
return this;
|
||||
return new UndefinedStructType(name, Variability::Unbound, isConst, pos);
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsSOAType(int width) const {
|
||||
FATAL("UndefinedStructType::GetAsSOAType() shouldn't be called.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::ResolveUnboundVariability(Variability v) const {
|
||||
if (variability != Variability::Unbound)
|
||||
return this;
|
||||
return new UndefinedStructType(name, v, isConst, pos);
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsConstType() const {
|
||||
if (isConst)
|
||||
return this;
|
||||
return new UndefinedStructType(name, variability, true, pos);
|
||||
}
|
||||
|
||||
|
||||
const UndefinedStructType *
|
||||
UndefinedStructType::GetAsNonConstType() const {
|
||||
if (isConst == false)
|
||||
return this;
|
||||
return new UndefinedStructType(name, variability, false, pos);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
UndefinedStructType::GetString() const {
|
||||
std::string ret;
|
||||
if (isConst) ret += "const ";
|
||||
ret += variability.GetString();
|
||||
ret += " struct ";
|
||||
ret += name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
UndefinedStructType::Mangle() const {
|
||||
return lMangleStruct(variability, isConst, name);
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
UndefinedStructType::GetCDeclaration(const std::string &n) const {
|
||||
std::string ret;
|
||||
if (isConst) ret += "const ";
|
||||
ret += std::string("struct ") + name;
|
||||
if (lShouldPrintName(n))
|
||||
ret += std::string(" ") + n;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
llvm::Type *
|
||||
UndefinedStructType::LLVMType(llvm::LLVMContext *ctx) const {
|
||||
Assert(variability != Variability::Unbound);
|
||||
std::string mname = lMangleStructName(name, variability);
|
||||
if (lStructTypeMap.find(mname) == lStructTypeMap.end()) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
return lStructTypeMap[mname];
|
||||
}
|
||||
|
||||
|
||||
llvm::DIType
|
||||
UndefinedStructType::GetDIType(llvm::DIDescriptor scope) const {
|
||||
llvm::DIFile diFile = pos.GetDIFile();
|
||||
llvm::DIArray elements;
|
||||
return m->diBuilder->createStructType(scope, name, diFile, pos.first_line,
|
||||
0 /* size */, 0 /* align */,
|
||||
0 /* flags */, elements);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ReferenceType
|
||||
|
||||
@@ -2889,20 +3137,19 @@ lCheckTypeEquality(const Type *a, const Type *b, bool ignoreConst) {
|
||||
|
||||
const StructType *sta = dynamic_cast<const StructType *>(a);
|
||||
const StructType *stb = dynamic_cast<const StructType *>(b);
|
||||
if (sta != NULL && stb != NULL) {
|
||||
if (sta->GetElementCount() != stb->GetElementCount())
|
||||
const UndefinedStructType *usta =
|
||||
dynamic_cast<const UndefinedStructType *>(a);
|
||||
const UndefinedStructType *ustb =
|
||||
dynamic_cast<const UndefinedStructType *>(b);
|
||||
if ((sta != NULL || usta != NULL) && (stb != NULL || ustb != NULL)) {
|
||||
// Report both defuned and undefined structs as equal if their
|
||||
// names are the same.
|
||||
if (a->GetVariability() != b->GetVariability())
|
||||
return false;
|
||||
if (sta->GetStructName() != stb->GetStructName())
|
||||
return false;
|
||||
if (sta->GetVariability() != stb->GetVariability())
|
||||
return false;
|
||||
for (int i = 0; i < sta->GetElementCount(); ++i)
|
||||
// FIXME: is this redundant now?
|
||||
if (!lCheckTypeEquality(sta->GetElementType(i), stb->GetElementType(i),
|
||||
ignoreConst))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
std::string namea = sta ? sta->GetStructName() : usta->GetStructName();
|
||||
std::string nameb = stb ? stb->GetStructName() : ustb->GetStructName();
|
||||
return (namea == nameb);
|
||||
}
|
||||
|
||||
const PointerType *pta = dynamic_cast<const PointerType *>(a);
|
||||
|
||||
49
type.h
49
type.h
@@ -409,7 +409,6 @@ public:
|
||||
const PointerType *GetAsSlice() const;
|
||||
const PointerType *GetAsNonSlice() const;
|
||||
const PointerType *GetAsFrozenSlice() const;
|
||||
const StructType *GetSliceStructType() const;
|
||||
|
||||
const Type *GetBaseType() const;
|
||||
const PointerType *GetAsVaryingType() const;
|
||||
@@ -668,7 +667,7 @@ public:
|
||||
private:
|
||||
static bool checkIfCanBeSOA(const StructType *st);
|
||||
|
||||
const std::string name;
|
||||
/*const*/ std::string name;
|
||||
/** The types of the struct elements. Note that we store these with
|
||||
uniform/varying exactly as they were declared in the source file.
|
||||
(In other words, even if this struct has a varying qualifier and
|
||||
@@ -690,6 +689,52 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/** Type implementation representing a struct name that has been declared
|
||||
but where the struct members haven't been defined (i.e. "struct Foo;").
|
||||
This class doesn't do much besides serve as a placeholder that other
|
||||
code can use to detect the presence of such as truct.
|
||||
*/
|
||||
class UndefinedStructType : public Type {
|
||||
public:
|
||||
UndefinedStructType(const std::string &name, const Variability variability,
|
||||
bool isConst, SourcePos pos);
|
||||
|
||||
Variability GetVariability() const;
|
||||
|
||||
bool IsBoolType() const;
|
||||
bool IsFloatType() const;
|
||||
bool IsIntType() const;
|
||||
bool IsUnsignedType() const;
|
||||
bool IsConstType() const;
|
||||
|
||||
const Type *GetBaseType() const;
|
||||
const UndefinedStructType *GetAsVaryingType() const;
|
||||
const UndefinedStructType *GetAsUniformType() const;
|
||||
const UndefinedStructType *GetAsUnboundVariabilityType() const;
|
||||
const UndefinedStructType *GetAsSOAType(int width) const;
|
||||
const UndefinedStructType *ResolveUnboundVariability(Variability v) const;
|
||||
|
||||
const UndefinedStructType *GetAsConstType() const;
|
||||
const UndefinedStructType *GetAsNonConstType() const;
|
||||
|
||||
std::string GetString() const;
|
||||
std::string Mangle() const;
|
||||
std::string GetCDeclaration(const std::string &name) const;
|
||||
|
||||
llvm::Type *LLVMType(llvm::LLVMContext *ctx) const;
|
||||
llvm::DIType GetDIType(llvm::DIDescriptor scope) const;
|
||||
|
||||
/** Returns the name of the structure type. (e.g. struct Foo -> "Foo".) */
|
||||
const std::string &GetStructName() const { return name; }
|
||||
|
||||
private:
|
||||
const std::string name;
|
||||
const Variability variability;
|
||||
const bool isConst;
|
||||
const SourcePos pos;
|
||||
};
|
||||
|
||||
|
||||
/** @brief Type representing a reference to another (non-reference) type.
|
||||
*/
|
||||
class ReferenceType : public Type {
|
||||
|
||||
Reference in New Issue
Block a user