diff --git a/ctx.cpp b/ctx.cpp index 4e7b3479..c76ec1b8 100644 --- a/ctx.cpp +++ b/ctx.cpp @@ -2609,14 +2609,22 @@ FunctionEmitContext::maskedStore(llvm::Value *value, llvm::Value *ptr, const PointerType *pt = dynamic_cast(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; } diff --git a/expr.cpp b/expr.cpp index fdaf878c..b43f9e54 100644 --- a/expr.cpp +++ b/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(exprType->GetReferenceTarget()) != NULL) - Error(p, "Dereference operator \"->\" can't be applied to non-pointer " + const Type *targetType = exprType->GetReferenceTarget(); + if (dynamic_cast(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(exprType) != NULL) return new VectorMemberExpr(e, id, p, idpos, derefLValue); + else if (dynamic_cast(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 ? "->" : ".", diff --git a/module.cpp b/module.cpp index 48bbf81b..d082255f 100644 --- a/module.cpp +++ b/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] = diff --git a/parse.yy b/parse.yy index 8a1e02ee..30144a67 100644 --- a/parse.yy +++ b/parse.yy @@ -874,7 +874,6 @@ struct_or_union_specifier std::vector 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 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(st) == NULL) Error(@2, "Type \"%s\" is not a struct type! (%s)", $2, diff --git a/sym.cpp b/sym.cpp index 1a503c91..8c7e04a6 100644 --- a/sym.cpp +++ b/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(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 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(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(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; } diff --git a/sym.h b/sym.h index 24eb810f..43c8ff16 100644 --- a/sym.h +++ b/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 struct Foo causes type \c Foo to be added to the symbol table) as well as for typedefs. + 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 > 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 TypeMapType; - std::vector types; + TypeMapType types; }; diff --git a/tests/struct-forward-decl-2.ispc b/tests/struct-forward-decl-2.ispc new file mode 100644 index 00000000..2660c541 --- /dev/null +++ b/tests/struct-forward-decl-2.ispc @@ -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; +} diff --git a/tests/struct-forward-decl.ispc b/tests/struct-forward-decl.ispc new file mode 100644 index 00000000..54f09be6 --- /dev/null +++ b/tests/struct-forward-decl.ispc @@ -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; +} diff --git a/tests_errors/deref-3.ispc b/tests_errors/deref-3.ispc index 19d4e82d..d7e6e906 100644 --- a/tests_errors/deref-3.ispc +++ b/tests_errors/deref-3.ispc @@ -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; }; diff --git a/tests_errors/struct-ref-undecl-1.ispc b/tests_errors/struct-ref-undecl-1.ispc new file mode 100644 index 00000000..0d851117 --- /dev/null +++ b/tests_errors/struct-ref-undecl-1.ispc @@ -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; } diff --git a/tests_errors/struct-ref-undecl-2.ispc b/tests_errors/struct-ref-undecl-2.ispc new file mode 100644 index 00000000..bb233ccc --- /dev/null +++ b/tests_errors/struct-ref-undecl-2.ispc @@ -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; } diff --git a/type.cpp b/type.cpp index 0e4ecfe1..64e832bb 100644 --- a/type.cpp +++ b/type.cpp @@ -42,6 +42,7 @@ #include "module.h" #include +#include #include #include #include @@ -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 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 eltNames; - std::vector 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 typesArrayRef = + llvm::ArrayRef(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 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 &elts, const std::vector &en, const std::vector &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 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 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(a); const StructType *stb = dynamic_cast(b); - if (sta != NULL && stb != NULL) { - if (sta->GetElementCount() != stb->GetElementCount()) + const UndefinedStructType *usta = + dynamic_cast(a); + const UndefinedStructType *ustb = + dynamic_cast(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(a); diff --git a/type.h b/type.h index f81ea062..e0560ce5 100644 --- a/type.h +++ b/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 {