From a3a511ca55d6c28fa4334cddc9a17defb5e8a5ce Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 20 Dec 2012 21:30:29 +0100 Subject: [PATCH] Refactored IrType construction to use static get() method. This also allows us to enable the assert in IrType::IrType. Unfortunately, this is mostly a "peace of mind" commit, there doesn't seem to have been a bug actually caused by the transitory duplicate IrTypePointer/IrTypeStruct instances. The remaining xyz2llvm static methods are not exactly pretty, they should probably just be folded into get. --- gen/tollvm.cpp | 49 +++++++++++++++----------- ir/irtype.cpp | 80 ++++++++++++++++++++++--------------------- ir/irtype.h | 72 +++++++++++++++++--------------------- ir/irtypeclass.cpp | 19 +++++----- ir/irtypeclass.h | 8 ++--- ir/irtypefunction.cpp | 54 +++++++++++++++-------------- ir/irtypefunction.h | 16 ++++----- ir/irtypestruct.cpp | 17 +++++---- ir/irtypestruct.h | 11 +++--- 9 files changed, 170 insertions(+), 156 deletions(-) diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 92a0440b..cc4b040b 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -113,55 +113,65 @@ LLType* DtoType(Type* t) case Twchar: case Tdchar: { - t->irtype = new IrTypeBasic(t); - return t->irtype->buildType(); + return IrTypeBasic::get(t)->getLLType(); } // pointers case Tnull: case Tpointer: { - t->irtype = new IrTypePointer(t); - return t->irtype->buildType(); + return IrTypePointer::get(t)->getLLType(); } // arrays case Tarray: { - t->irtype = new IrTypeArray(t); - return t->irtype->buildType(); + return IrTypeArray::get(t)->getLLType(); } case Tsarray: { - t->irtype = new IrTypeSArray(t); - return t->irtype->buildType(); + return IrTypeSArray::get(t)->getLLType(); } // aggregates - case Tstruct: { + case Tstruct: + { TypeStruct* ts = static_cast(t); - t->irtype = new IrTypeStruct(ts->sym); - return t->irtype->buildType(); + if (ts->sym->type->irtype) + { + // This should not happen, but the frontend seems to be buggy. Not + // sure if this is the best way to handle the situation, but we + // certainly don't want to override ts->sym->type->irtype. + IF_LOG Logger::cout() << "Struct with multiple Types detected: " << + ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl; + return ts->sym->type->irtype->getLLType(); + } + return IrTypeStruct::get(ts->sym)->getLLType(); } - case Tclass: { + case Tclass: + { TypeClass* tc = static_cast(t); - t->irtype = new IrTypeClass(tc->sym); - return t->irtype->buildType(); + if (tc->sym->type->irtype) + { + // See Tstruct case. + IF_LOG Logger::cout() << "Class with multiple Types detected: " << + tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl; + return tc->sym->type->irtype->getLLType(); + } + return IrTypeClass::get(tc->sym)->getLLType(); } // functions case Tfunction: { - t->irtype = new IrTypeFunction(t); - return t->irtype->buildType(); + return IrTypeFunction::get(t)->getLLType(); } // delegates case Tdelegate: { - t->irtype = new IrTypeDelegate(t); - return t->irtype->buildType(); + return IrTypeDelegate::get(t)->getLLType(); } // typedefs @@ -183,8 +193,7 @@ LLType* DtoType(Type* t) #if DMDV2 case Tvector: { - t->irtype = new IrTypeVector(t); - return t->irtype->buildType(); + return IrTypeVector::get(t)->getLLType(); } #endif diff --git a/ir/irtype.cpp b/ir/irtype.cpp index 499e855d..1ac9073f 100644 --- a/ir/irtype.cpp +++ b/ir/irtype.cpp @@ -13,6 +13,7 @@ #include "mtype.h" #include "gen/irstate.h" #include "gen/logger.h" +#include "gen/tollvm.h" #include "ir/irtype.h" // This code uses llvm::getGlobalContext() as these functions are invoked before gIR is set. @@ -20,21 +21,13 @@ ////////////////////////////////////////////////////////////////////////////// -extern LLType* DtoType(Type* dt); -extern LLIntegerType* DtoSize_t(); - -////////////////////////////////////////////////////////////////////////////// - IrType::IrType(Type* dt, LLType* lt) : dtype(dt), type(lt) { assert(dt && "null D Type"); assert(lt && "null LLVM Type"); -#if 0 - // FIXME: For some reason the assert fails - assert(dt->irtype == NULL && "already has IrType"); -#endif + assert(!dt->irtype && "already has IrType"); } ////////////////////////////////////////////////////////////////////////////// @@ -48,9 +41,11 @@ IrTypeBasic::IrTypeBasic(Type * dt) ////////////////////////////////////////////////////////////////////////////// -llvm::Type * IrTypeBasic::buildType() +IrTypeBasic* IrTypeBasic::get(Type* dt) { - return type; + IrTypeBasic* t = new IrTypeBasic(dt); + dt->irtype = t; + return t; } ////////////////////////////////////////////////////////////////////////////// @@ -145,35 +140,36 @@ llvm::Type * IrTypeBasic::basic2llvm(Type* t) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -IrTypePointer::IrTypePointer(Type * dt) -: IrType(dt, dt->ty == Tnull ? null2llvm(dt) : pointer2llvm(dt)) +IrTypePointer::IrTypePointer(Type* dt, LLType* lt) +: IrType(dt, lt) { } ////////////////////////////////////////////////////////////////////////////// -llvm::Type * IrTypePointer::buildType() +IrTypePointer* IrTypePointer::get(Type* dt) { - return type; -} + assert(!dt->irtype); + assert((dt->ty == Tpointer || dt->ty == Tnull) && "not pointer/null type"); -////////////////////////////////////////////////////////////////////////////// - -llvm::Type * IrTypePointer::pointer2llvm(Type * dt) -{ - assert(dt->ty == Tpointer && "not pointer type"); - - LLType* elemType = DtoType(dt->nextOf()); - if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext())) + LLType* elemType; + if (dt->ty == Tnull) + { elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); - return llvm::PointerType::get(elemType, 0); -} + } + else + { + elemType = DtoTypeNotVoid(dt->nextOf()); -llvm::Type* IrTypePointer::null2llvm(Type* dt) -{ - assert(dt->ty == Tnull && "not null type"); - LLType* elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); - return llvm::PointerType::get(elemType, 0); + // DtoTypeNotVoid could have already created the same type, e.g. for + // dt == Node* in struct Node { Node* n; }. + if (dt->irtype) + return dt->irtype->isPointer(); + } + + IrTypePointer* t = new IrTypePointer(dt, llvm::PointerType::get(elemType, 0)); + dt->irtype = t; + return t; } ////////////////////////////////////////////////////////////////////////////// @@ -187,9 +183,11 @@ IrTypeSArray::IrTypeSArray(Type * dt) ////////////////////////////////////////////////////////////////////////////// -llvm::Type * IrTypeSArray::buildType() +IrTypeSArray* IrTypeSArray::get(Type* dt) { - return type; + IrTypeSArray* t = new IrTypeSArray(dt); + dt->irtype = t; + return t; } ////////////////////////////////////////////////////////////////////////////// @@ -198,7 +196,7 @@ llvm::Type * IrTypeSArray::sarray2llvm(Type * t) { assert(t->ty == Tsarray && "not static array type"); TypeSArray* tsa = static_cast(t); - dim = static_cast(tsa->dim->toUInteger()); + uint64_t dim = static_cast(tsa->dim->toUInteger()); LLType* elemType = DtoType(t->nextOf()); if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext())) elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); @@ -216,9 +214,11 @@ IrTypeArray::IrTypeArray(Type * dt) ////////////////////////////////////////////////////////////////////////////// -llvm::Type * IrTypeArray::buildType() +IrTypeArray* IrTypeArray::get(Type* dt) { - return type; + IrTypeArray* t = new IrTypeArray(dt); + dt->irtype = t; + return t; } ////////////////////////////////////////////////////////////////////////////// @@ -255,9 +255,11 @@ IrTypeVector::IrTypeVector(Type* dt) ////////////////////////////////////////////////////////////////////////////// -llvm::Type* IrTypeVector::buildType() +IrTypeVector* IrTypeVector::get(Type* dt) { - return type; + IrTypeVector* t = new IrTypeVector(dt); + dt->irtype = t; + return t; } ////////////////////////////////////////////////////////////////////////////// @@ -268,7 +270,7 @@ llvm::Type* IrTypeVector::vector2llvm(Type* dt) TypeVector* tv = static_cast(dt); assert(tv->basetype->ty == Tsarray); TypeSArray* tsa = static_cast(tv->basetype); - dim = static_cast(tsa->dim->toUInteger()); + uint64_t dim = static_cast(tsa->dim->toUInteger()); LLType* elemType = DtoType(tsa->next); if (elemType == llvm::Type::getVoidTy(llvm::getGlobalContext())) elemType = llvm::Type::getInt8Ty(llvm::getGlobalContext()); diff --git a/ir/irtype.h b/ir/irtype.h index 1ba67e6d..21a43d23 100644 --- a/ir/irtype.h +++ b/ir/irtype.h @@ -8,8 +8,7 @@ //===----------------------------------------------------------------------===// // // The types derived from IrType are used to attach LLVM type information and -// other codegen metadata (e.g. for vtbl resolution) to frontend Types. There -// is an 1:1 correspondence between Type and IrType instances. +// other codegen metadata (e.g. for vtbl resolution) to frontend Types. // //===----------------------------------------------------------------------===// @@ -40,13 +39,17 @@ class IrTypeVector; ////////////////////////////////////////////////////////////////////////////// -/// Base class for IrTypeS. +/// Code generation state/metadata for D types. The mapping from IrType to +/// Type is injective but not surjective. +/// +/// Derived classes should be created using their static get() methods, which +/// makes sure that uniqueness is preserved in the face of forward references. +/// Note that the get() methods expect the IrType of the passed type/symbol to +/// be not yet set. This could be altered to just return the existing IrType +/// in order to bring the API entirely in line with the LLVM type get() methods. class IrType { public: - /// - IrType(Type* dt, llvm::Type* lt); - /// virtual IrTypeAggr* isAggr() { return NULL; } /// @@ -75,10 +78,10 @@ public: /// virtual llvm::Type* getLLType() { return type; } - /// - virtual llvm::Type* buildType() = 0; - protected: + /// + IrType(Type* dt, llvm::Type* lt); + /// Type* dtype; @@ -93,19 +96,18 @@ class IrTypeBasic : public IrType { public: /// - IrTypeBasic(Type* dt); + static IrTypeBasic* get(Type* dt); /// IrTypeBasic* isBasic() { return this; } - /// - llvm::Type* buildType(); - protected: /// - LLType* getComplexType(llvm::LLVMContext& ctx, LLType* type); + IrTypeBasic(Type* dt); /// - llvm::Type* basic2llvm(Type* t); + static LLType* getComplexType(llvm::LLVMContext& ctx, LLType* type); + /// + static llvm::Type* basic2llvm(Type* t); }; ////////////////////////////////////////////////////////////////////////////// @@ -115,19 +117,14 @@ class IrTypePointer : public IrType { public: /// - IrTypePointer(Type* dt); + static IrTypePointer* get(Type* dt); /// IrTypePointer* isPointer() { return this; } - /// - llvm::Type* buildType(); - protected: /// - llvm::Type* pointer2llvm(Type* t); - /// - llvm::Type* null2llvm(Type* t); + IrTypePointer(Type* dt, LLType *lt); }; ////////////////////////////////////////////////////////////////////////////// @@ -137,20 +134,17 @@ class IrTypeSArray : public IrType { public: /// - IrTypeSArray(Type* dt); + static IrTypeSArray* get(Type* dt); /// IrTypeSArray* isSArray() { return this; } - /// - llvm::Type* buildType(); - protected: /// - llvm::Type* sarray2llvm(Type* t); + IrTypeSArray(Type* dt); - /// Dimension. - uint64_t dim; + /// + static llvm::Type* sarray2llvm(Type* t); }; ////////////////////////////////////////////////////////////////////////////// @@ -160,17 +154,16 @@ class IrTypeArray : public IrType { public: /// - IrTypeArray(Type* dt); + static IrTypeArray* get(Type* dt); /// IrTypeArray* isArray() { return this; } - /// - llvm::Type* buildType(); - protected: /// - llvm::Type* array2llvm(Type* t); + IrTypeArray(Type* dt); + /// + static llvm::Type* array2llvm(Type* t); }; ////////////////////////////////////////////////////////////////////////////// @@ -181,17 +174,16 @@ class IrTypeVector : public IrType { public: /// - IrTypeVector(Type* dt); + static IrTypeVector* get(Type* dt); /// IrTypeVector* isVector() { return this; } - /// - llvm::Type* buildType(); protected: - llvm::Type* vector2llvm(Type* dt); - /// Dimension. - uint64_t dim; + /// + IrTypeVector(Type* dt); + + static llvm::Type* vector2llvm(Type* dt); }; #endif diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index 48788028..90eca230 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -222,8 +222,11 @@ void IrTypeClass::addBaseClassData( ////////////////////////////////////////////////////////////////////////////// -llvm::Type* IrTypeClass::buildType() +IrTypeClass* IrTypeClass::get(ClassDeclaration* cd) { + IrTypeClass* t = new IrTypeClass(cd); + cd->type->irtype = t; + IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; IF_LOG Logger::println("Instance size: %u", cd->structsize); @@ -235,12 +238,12 @@ llvm::Type* IrTypeClass::buildType() defaultTypes.reserve(32); // add vtbl - defaultTypes.push_back(llvm::PointerType::get(vtbl_type, 0)); + defaultTypes.push_back(llvm::PointerType::get(t->vtbl_type, 0)); // interfaces are just a vtable if (cd->isInterfaceDeclaration()) { - num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0; + t->num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0; } // classes have monitor and fields else @@ -253,7 +256,7 @@ llvm::Type* IrTypeClass::buildType() size_t field_index = 2; // add data members recursively - addBaseClassData(defaultTypes, cd, offset, field_index); + t->addBaseClassData(defaultTypes, cd, offset, field_index); #if 1 // tail padding? @@ -270,16 +273,16 @@ llvm::Type* IrTypeClass::buildType() fatal(); // set struct body - isaStruct(type)->setBody(defaultTypes, false); + isaStruct(t->type)->setBody(defaultTypes, false); // VTBL // set vtbl type body - vtbl_type->setBody(buildVtblType(ClassDeclaration::classinfo->type, &cd->vtbl)); + t->vtbl_type->setBody(t->buildVtblType(ClassDeclaration::classinfo->type, &cd->vtbl)); - IF_LOG Logger::cout() << "class type: " << *type << std::endl; + IF_LOG Logger::cout() << "class type: " << *t->type << std::endl; - return getLLType(); + return t; } ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtypeclass.h b/ir/irtypeclass.h index 17b4f900..346e3068 100644 --- a/ir/irtypeclass.h +++ b/ir/irtypeclass.h @@ -22,14 +22,11 @@ class IrTypeClass : public IrTypeAggr { public: /// - IrTypeClass(ClassDeclaration* cd); + static IrTypeClass* get(ClassDeclaration* cd); /// virtual IrTypeClass* isClass() { return this; } - /// - llvm::Type* buildType(); - /// llvm::Type* getLLType(); @@ -53,6 +50,9 @@ public: unsigned getNumInterfaceVtbls() { return num_interface_vtbls; } protected: + /// + IrTypeClass(ClassDeclaration* cd); + /// ClassDeclaration* cd; /// diff --git a/ir/irtypefunction.cpp b/ir/irtypefunction.cpp index 7ffeaf7b..cea54a77 100644 --- a/ir/irtypefunction.cpp +++ b/ir/irtypefunction.cpp @@ -16,47 +16,51 @@ #include "ir/irtypefunction.h" -IrTypeFunction::IrTypeFunction(Type* dt) -: IrType(dt, func2llvm(dt)) +IrTypeFunction::IrTypeFunction(Type* dt, LLType* lt) +: IrType(dt, lt) { - irfty = NULL; } -llvm::Type * IrTypeFunction::buildType() +IrTypeFunction* IrTypeFunction::get(Type* dt) { - return type; -} + assert(dt->ty == Tfunction); -llvm::Type* IrTypeFunction::func2llvm(Type* dt) -{ - llvm::Type* T; + // We can't get cycles here, but we can end up building the type as part of + // a class vtbl, ... + llvm::Type* lt; TypeFunction* tf = static_cast(dt); if (tf->funcdecl) - T = DtoFunctionType(tf->funcdecl); + lt = DtoFunctionType(tf->funcdecl); else - T = DtoFunctionType(tf,NULL,NULL); - return T; + lt = DtoFunctionType(tf,NULL,NULL); + + if (!dt->irtype) + dt->irtype = new IrTypeFunction(dt, lt); + return dt->irtype->isFunction(); } ////////////////////////////////////////////////////////////////////////////// -IrTypeDelegate::IrTypeDelegate(Type * dt) -: IrType(dt, delegate2llvm(dt)) +IrTypeDelegate::IrTypeDelegate(Type * dt, LLType* lt) +: IrType(dt, lt) { } -llvm::Type* IrTypeDelegate::buildType() -{ - return type; -} - -llvm::Type* IrTypeDelegate::delegate2llvm(Type* dt) +IrTypeDelegate* IrTypeDelegate::get(Type* dt) { assert(dt->ty == Tdelegate); + + // We can't get cycles here, but we can end up building the type as part of + // a class vtbl, ... LLType* func = DtoFunctionType(dt->nextOf(), NULL, Type::tvoid->pointerTo()); - llvm::SmallVector types; - types.push_back(getVoidPtrType()); - types.push_back(getPtrToType(func)); - LLStructType* dgtype = LLStructType::get(gIR->context(), types); - return dgtype; + if (!dt->irtype) + { + llvm::SmallVector types; + types.push_back(getVoidPtrType()); + types.push_back(getPtrToType(func)); + LLStructType* lt = LLStructType::get(gIR->context(), types); + dt->irtype = new IrTypeDelegate(dt, lt); + } + + return dt->irtype->isDelegate(); } diff --git a/ir/irtypefunction.h b/ir/irtypefunction.h index 528b07a3..ef9502f3 100644 --- a/ir/irtypefunction.h +++ b/ir/irtypefunction.h @@ -23,18 +23,17 @@ class IrTypeFunction : public IrType { public: /// - IrTypeFunction(Type* dt); + static IrTypeFunction* get(Type* dt); /// IrTypeFunction* isFunction() { return this; } - /// - llvm::Type* buildType(); - IrFuncTy* fty() { return irfty; } protected: - llvm::Type* func2llvm(Type* dt); + /// + IrTypeFunction(Type* dt, llvm::Type* lt); + /// IrFuncTy* irfty; }; @@ -44,15 +43,14 @@ class IrTypeDelegate : public IrType { public: /// - IrTypeDelegate(Type* dt); + static IrTypeDelegate* get(Type* dt); /// IrTypeDelegate* isDelegate() { return this; } - /// - llvm::Type* buildType(); protected: - llvm::Type* delegate2llvm(Type* dt); + /// + IrTypeDelegate(Type* dt, llvm::Type* lt); }; #endif diff --git a/ir/irtypestruct.cpp b/ir/irtypestruct.cpp index 0990c2b9..4b5edbe6 100644 --- a/ir/irtypestruct.cpp +++ b/ir/irtypestruct.cpp @@ -84,20 +84,23 @@ bool var_offset_sort_cb(const VarDeclaration* v1, const VarDeclaration* v2) // this is pretty much the exact same thing we need to do for fields in each // base class of a class -llvm::Type* IrTypeStruct::buildType() +IrTypeStruct* IrTypeStruct::get(StructDeclaration* sd) { + IrTypeStruct* t = new IrTypeStruct(sd); + sd->type->irtype = t; + IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->loc.toChars()); LOG_SCOPE; // if it's a forward declaration, all bets are off, stick with the opaque if (sd->sizeok != 1) - return type; + return t; // mirror the sd->fields array but only fill in contributors size_t n = sd->fields.dim; LLSmallVector data(n, NULL); - default_fields.reserve(n); + t->default_fields.reserve(n); // first fill in the fields with explicit initializers VarDeclarationIter field_it(sd->fields); @@ -197,7 +200,7 @@ llvm::Type* IrTypeStruct::buildType() assert(vd->offset >= offset); // add to default field list - default_fields.push_back(vd); + t->default_fields.push_back(vd); // get next aligned offset for this type size_t alignedoffset = offset; @@ -229,11 +232,11 @@ llvm::Type* IrTypeStruct::buildType() } // set struct body - isaStruct(type)->setBody(defaultTypes, packed); + isaStruct(t->type)->setBody(defaultTypes, packed); - IF_LOG Logger::cout() << "final struct type: " << *type << std::endl; + IF_LOG Logger::cout() << "final struct type: " << *t->type << std::endl; - return type; + return t; } ////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irtypestruct.h b/ir/irtypestruct.h index d1ad3e72..f52dff45 100644 --- a/ir/irtypestruct.h +++ b/ir/irtypestruct.h @@ -28,9 +28,6 @@ struct TypeStruct; class IrTypeAggr : public IrType { public: - /// - IrTypeAggr(AggregateDeclaration* ad); - /// IrTypeAggr* isAggr() { return this; } @@ -44,6 +41,9 @@ public: iterator def_end() { return default_fields.end(); } protected: + /// + IrTypeAggr(AggregateDeclaration* ad); + /// AggregateDeclaration this type represents. AggregateDeclaration* aggr; @@ -61,7 +61,7 @@ class IrTypeStruct : public IrTypeAggr { public: /// - IrTypeStruct(StructDeclaration* sd); + static IrTypeStruct* get(StructDeclaration* sd); /// IrTypeStruct* isStruct() { return this; } @@ -70,6 +70,9 @@ public: llvm::Type* buildType(); protected: + /// + IrTypeStruct(StructDeclaration* sd); + /// StructDeclaration this type represents. StructDeclaration* sd;