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:
Matt Pharr
2012-04-16 06:27:21 -07:00
parent fefa86e0cf
commit 99a27fe241
13 changed files with 537 additions and 173 deletions

24
ctx.cpp
View File

@@ -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;
}

View File

@@ -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 ? "->" : ".",

View File

@@ -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] =

View File

@@ -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
View File

@@ -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
View File

@@ -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;
};

View 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;
}

View 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;
}

View File

@@ -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; };

View 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; }

View 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
View File

@@ -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
View File

@@ -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 {