diff --git a/dmd/expression.c b/dmd/expression.c index 2e7c1255..b4647c12 100644 --- a/dmd/expression.c +++ b/dmd/expression.c @@ -3117,6 +3117,9 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * #endif this->soffset = 0; this->fillHoles = 1; +#if IN_LLVM + constType = NULL; +#endif } Expression *StructLiteralExp::syntaxCopy() diff --git a/dmd/expression.h b/dmd/expression.h index 94f07f54..c4536907 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -66,6 +66,7 @@ struct DValue; namespace llvm { class Constant; class ConstantInt; + class StructType; } #endif @@ -537,6 +538,7 @@ struct StructLiteralExp : Expression #elif IN_LLVM DValue* toElem(IRState* irs); llvm::Constant *toConstElem(IRState *irs); + llvm::StructType *constType; #endif }; diff --git a/dmd/init.c b/dmd/init.c index ae3b0848..9d05d4cd 100644 --- a/dmd/init.c +++ b/dmd/init.c @@ -114,6 +114,9 @@ StructInitializer::StructInitializer(Loc loc) : Initializer(loc) { ad = NULL; +#if IN_LLVM + ltype = NULL; +#endif } Initializer *StructInitializer::syntaxCopy() diff --git a/dmd/init.h b/dmd/init.h index aab5d043..1b893882 100644 --- a/dmd/init.h +++ b/dmd/init.h @@ -30,6 +30,12 @@ struct ExpInitializer; struct HdrGenState; #endif +#if IN_LLVM +namespace llvm { + class StructType; +} +#endif + struct Initializer : Object { Loc loc; @@ -91,6 +97,9 @@ struct StructInitializer : Initializer #endif StructInitializer *isStructInitializer() { return this; } +#if IN_LLVM + llvm::StructType *ltype; +#endif }; struct ArrayInitializer : Initializer diff --git a/dmd2/expression.c b/dmd2/expression.c index 253c4176..05092314 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -3737,6 +3737,9 @@ StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions * #endif this->soffset = 0; this->fillHoles = 1; +#if IN_LLVM + constType = NULL; +#endif } Expression *StructLiteralExp::syntaxCopy() diff --git a/dmd2/expression.h b/dmd2/expression.h index 604bc428..7f0508ad 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -74,6 +74,7 @@ struct DValue; namespace llvm { class Constant; class ConstantInt; + class StructType; } #endif @@ -590,6 +591,7 @@ struct StructLiteralExp : Expression #elif IN_LLVM DValue* toElem(IRState* irs); llvm::Constant *toConstElem(IRState *irs); + llvm::StructType *constType; #endif }; diff --git a/dmd2/init.c b/dmd2/init.c index b046b181..6a000220 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -114,6 +114,9 @@ StructInitializer::StructInitializer(Loc loc) : Initializer(loc) { ad = NULL; +#if IN_LLVM + ltype = NULL; +#endif } Initializer *StructInitializer::syntaxCopy() diff --git a/dmd2/init.h b/dmd2/init.h index d9038cca..d038dd9e 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -28,6 +28,12 @@ struct ArrayInitializer; struct ExpInitializer; struct HdrGenState; +#if IN_LLVM +namespace llvm { + class StructType; +} +#endif + struct Initializer : Object { @@ -91,6 +97,9 @@ struct StructInitializer : Initializer #endif StructInitializer *isStructInitializer() { return this; } +#if IN_LLVM + llvm::StructType *ltype; +#endif }; struct ArrayInitializer : Initializer diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 15b71b54..e95da271 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -15,6 +15,7 @@ #include "gen/logger.h" #include "gen/dvalue.h" #include "ir/irmodule.h" +#include "ir/irtypestruct.h" #include "gen/cl_options.h" @@ -361,6 +362,85 @@ void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr) ////////////////////////////////////////////////////////////////////////////////////////// +// The function is almost identical copy of DtoConstArrayInitializer but it returns +// initializer type not the initializer itself. +// FIXME: is there any way to merge this next two functions? +LLType* DtoConstArrayInitializerType(ArrayInitializer* arrinit) +{ + Type* arrty = arrinit->type->toBasetype(); + if (arrty->ty != Tsarray) + return DtoType(arrinit->type); + + TypeSArray* tsa = (TypeSArray*)arrty; + size_t arrlen = (size_t)tsa->dim->toInteger(); + + // get elem type + Type* elemty = arrty->nextOf(); + LLType* llelemty = DtoTypeNotVoid(elemty); + + // make sure the number of initializers is sane + if (arrinit->index.dim > arrlen || arrinit->dim > arrlen) + { + error(arrinit->loc, "too many initializers, %u, for array[%zu]", arrinit->index.dim, arrlen); + fatal(); + } + + // true if array elements differ in type, can happen with array of unions + bool mismatch = false; + + // allocate room for types + std::vector types(arrlen, NULL); + + // go through each initializer, they're not sorted by index by the frontend + size_t j = 0; + for (size_t i = 0; i < arrinit->index.dim; i++) + { + // get index + Expression* idx = (Expression*)arrinit->index.data[i]; + + // idx can be null, then it's just the next element + if (idx) + j = idx->toInteger(); + assert(j < arrlen); + + // get value + Initializer* val = (Initializer*)arrinit->value.data[i]; + assert(val); + + LLType* c = DtoConstInitializerType(elemty, val); + assert(c); + if (c != llelemty) + mismatch = true; + + types[j] = c; + j++; + } + + // fill out any null entries still left with default type + + // element default types + LLType* deftype = DtoConstInitializerType(elemty, 0); + bool mismatch2 = (deftype != llelemty); + + for (size_t i = 0; i < arrlen; i++) + { + if (types[i] != NULL) + continue; + + types[i] = deftype; + + if (mismatch2) + mismatch = true; + } + + if (mismatch) + return LLStructType::get(gIR->context(), types); // FIXME should this pack? + else + return LLArrayType::get(deftype, arrlen); +} + +////////////////////////////////////////////////////////////////////////////////////////// + LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) { Logger::println("DtoConstArrayInitializer: %s | %s", arrinit->toChars(), arrinit->type->toChars()); @@ -469,7 +549,7 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) #if DMDV2 if (arrty->ty == Tpointer) // we need to return pointer to the static array. - return gvar; + return DtoBitCast(gvar, DtoType(arrty)); #endif LLConstant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) }; @@ -477,7 +557,7 @@ LLConstant* DtoConstArrayInitializer(ArrayInitializer* arrinit) LLConstant* gep = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2); gep = llvm::ConstantExpr::getBitCast(gvar, getPtrToType(llelemty)); - return DtoConstSlice(DtoConstSize_t(arrlen),gep); + return DtoConstSlice(DtoConstSize_t(arrlen), gep, arrty); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/gen/arrays.h b/gen/arrays.h index eb0dd9e4..409cf123 100644 --- a/gen/arrays.h +++ b/gen/arrays.h @@ -9,6 +9,7 @@ llvm::StructType* DtoArrayType(Type* arrayTy); llvm::StructType* DtoArrayType(LLType* elemTy); llvm::ArrayType* DtoStaticArrayType(Type* sarrayTy); +LLType* DtoConstArrayInitializerType(ArrayInitializer* arrinit); LLConstant* DtoConstArrayInitializer(ArrayInitializer* si); LLConstant* DtoConstSlice(LLConstant* dim, LLConstant* ptr, Type *type = 0); diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 4f704066..cfed3a1e 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -6,6 +6,7 @@ #include "id.h" #include "mem.h" #include "template.h" +#include "init.h" #include "gen/irstate.h" #include "gen/tollvm.h" @@ -136,12 +137,10 @@ void VarDeclaration::codegen(Ir* p) ir.initialized = gIR->dmodule; std::string _name(mangle()); - // build the initializer - LLConstant* initVal = DtoConstInitializer(loc, type, init); - ir.irGlobal->type = initVal->getType(); + LLType *_type = DtoConstInitializerType(type, init); // create the global variable - LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, initVal->getType(), _isconst, + LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal()); this->ir.irGlobal->value = gvar; @@ -156,10 +155,6 @@ void VarDeclaration::codegen(Ir* p) if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); - // set the initializer if appropriate - assert(!ir.irGlobal->constInit); - ir.irGlobal->constInit = initVal; - // assign the initializer if (!(storage_class & STCextern) && mustDefineSymbol(this)) { @@ -171,7 +166,12 @@ void VarDeclaration::codegen(Ir* p) Logger::cout() << "init: " << *initVal << '\n'; #endif } + // build the initializer + LLConstant *initVal = DtoConstInitializer(loc, type, init); + // set the initializer + assert(!ir.irGlobal->constInit); + ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); #ifndef DISABLE_DEBUG_INFO diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 4c399797..5233f428 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1255,6 +1255,60 @@ LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr) // INITIALIZER HELPERS ////////////////////////////////////////////////////////////////////////////////////////*/ +LLType* DtoConstInitializerType(Type* type, Initializer* init) +{ + if (type->ty == Ttypedef) { + TypeTypedef *td = (TypeTypedef*)type; + if (td->sym->init) + return DtoConstInitializerType(td->sym->basetype, td->sym->init); + } + + type = type->toBasetype(); + if (type->ty == Tsarray) + { + if (!init) + { + TypeSArray *tsa = (TypeSArray*)type; + LLType *llnext = DtoConstInitializerType(type->nextOf(), init); + return LLArrayType::get(llnext, tsa->dim->toUInteger()); + } + else if (ArrayInitializer* ai = init->isArrayInitializer()) + { + return DtoConstArrayInitializerType(ai); + } + } + else if (type->ty == Tstruct) + { + if (!init) + { + LdefaultInit: + TypeStruct *ts = (TypeStruct*)type; + DtoResolveStruct(ts->sym); + return ts->sym->ir.irStruct->getDefaultInit()->getType(); + } + else if (ExpInitializer* ex = init->isExpInitializer()) + { + if (ex->exp->op == TOKstructliteral) { + StructLiteralExp* le = (StructLiteralExp*)ex->exp; + if (!le->constType) + le->constType = LLStructType::create(gIR->context(), std::string(type->toChars()) + "_init"); + return le->constType; + } else if (ex->exp->op == TOKvar) { + if (((VarExp*)ex->exp)->var->isStaticStructInitDeclaration()) + goto LdefaultInit; + } + } + else if (StructInitializer* si = init->isStructInitializer()) + { + if (!si->ltype) + si->ltype = LLStructType::create(gIR->context(), std::string(type->toChars()) + "_init"); + return si->ltype; + } + } + + return DtoTypeNotVoid(type); +} + LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) { LLConstant* _init = 0; // may return zero @@ -1266,7 +1320,7 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) else if (ExpInitializer* ex = init->isExpInitializer()) { Logger::println("const expression initializer"); - _init = DtoConstExpInit(loc, type, ex->exp);; + _init = DtoConstExpInit(loc, type, ex->exp); } else if (StructInitializer* si = init->isStructInitializer()) { @@ -1282,7 +1336,7 @@ LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init) else if (init->isVoidInitializer()) { Logger::println("const void initializer"); - LLType* ty = DtoType(type); + LLType* ty = DtoTypeNotVoid(type); _init = LLConstant::getNullValue(ty); } else { @@ -1797,4 +1851,3 @@ void callPostblit(Loc &loc, Expression *exp, LLValue *val) } } #endif - diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index 08b4723e..9ca73ce3 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -102,6 +102,7 @@ DValue* DtoDeclarationExp(Dsymbol* declaration); LLValue* DtoRawVarDeclaration(VarDeclaration* var, LLValue* addr = 0); // initializer helpers +LLType* DtoConstInitializerType(Type* type, Initializer* init); LLConstant* DtoConstInitializer(Loc loc, Type* type, Initializer* init); LLConstant* DtoConstExpInit(Loc loc, Type* t, Expression* exp); DValue* DtoInitializer(LLValue* target, Initializer* init); diff --git a/gen/structs.cpp b/gen/structs.cpp index c0aa374d..661e4d0e 100644 --- a/gen/structs.cpp +++ b/gen/structs.cpp @@ -184,7 +184,9 @@ size_t add_zeros(std::vector& values, size_t diff) return values.size() - n; } -std::vector DtoStructLiteralValues(const StructDeclaration* sd, const std::vector& inits) +std::vector DtoStructLiteralValues(const StructDeclaration* sd, + const std::vector& inits, + bool isConst) { // get arrays size_t nvars = sd->fields.dim; @@ -268,7 +270,7 @@ std::vector DtoStructLiteralValues(const StructDeclaration* sd, co assert(nextVar == var); // add any 0 padding needed before this field - if (os > lastoffset + lastsize) + if (!isConst && os > lastoffset + lastsize) { //printf("added %lu zeros\n", os - lastoffset - lastsize); add_zeros(values, os - lastoffset - lastsize); diff --git a/gen/structs.h b/gen/structs.h index f655e614..4056e958 100644 --- a/gen/structs.h +++ b/gen/structs.h @@ -10,7 +10,9 @@ void DtoResolveStruct(StructDeclaration* sd); LLConstant* DtoConstStructInitializer(StructInitializer* si); /// Build values for a struct literal. -std::vector DtoStructLiteralValues(const StructDeclaration* sd, const std::vector& inits); +std::vector DtoStructLiteralValues(const StructDeclaration* sd, + const std::vector& inits, + bool isConst = false); /// Returns a boolean=true if the two structs are equal. LLValue* DtoStructEquals(TOK op, DValue* lhs, DValue* rhs); diff --git a/gen/toir.cpp b/gen/toir.cpp index 3fa9e341..823db485 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1168,7 +1168,7 @@ LLConstant* AddrExp::toConstElem(IRState* p) vd->codegen(Type::sir); LLConstant* llc = llvm::dyn_cast(vd->ir.getIrValue()); assert(llc); - return llc; + return DtoBitCast(llc, DtoType(type)); } // static function else if (FuncDeclaration* fd = vexp->var->isFuncDeclaration()) @@ -2883,15 +2883,22 @@ LLConstant* StructLiteralExp::toConstElem(IRState* p) inits[i] = exprs[i]->toConstElem(p); // vector of values to build aggregate from - std::vector values = DtoStructLiteralValues(sd, inits); + std::vector values = DtoStructLiteralValues(sd, inits, true); // we know those values are constants.. cast them std::vector constvals(values.size(), NULL); - for (size_t i = 0; i < values.size(); ++i) + std::vector types(values.size(), NULL); + for (size_t i = 0; i < values.size(); ++i) { constvals[i] = llvm::cast(values[i]); + types[i] = values[i]->getType(); + } // return constant struct - return LLConstantStruct::getAnon(gIR->context(), llvm::makeArrayRef(constvals), sd->ir.irStruct->packed); + if (!constType) + constType = LLStructType::get(gIR->context(), types); + else + constType->setBody(types); + return LLConstantStruct::get(constType, llvm::makeArrayRef(constvals)); } ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/ir/irclass.cpp b/ir/irclass.cpp index f71f265d..94d41e40 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -308,13 +308,6 @@ void IrStruct::addBaseClassInits( inter_idx++; } } - - // tail padding? - if (offset < base->structsize) - { - add_zeros(constants, base->structsize - offset); - offset = base->structsize; - } } ////////////////////////////////////////////////////////////////////////////// @@ -346,6 +339,10 @@ std::vector IrStruct::createClassDefaultInitializer() // add data members recursively addBaseClassInits(constants, cd, offset, field_index); + // tail padding? + if (offset < cd->structsize) + add_zeros(constants, cd->structsize - offset); + return constants; } diff --git a/ir/irstruct.cpp b/ir/irstruct.cpp index 36924a64..5befa67c 100644 --- a/ir/irstruct.cpp +++ b/ir/irstruct.cpp @@ -20,7 +20,7 @@ IrStruct::IrStruct(AggregateDeclaration* aggr) : diCompositeType(NULL), - init_type(LLStructType::create(gIR->context(), std::string(aggr->toChars()) + "_init")) + init_type(LLStructType::create(gIR->context(), std::string(aggr->toPrettyChars()) + "_init")) { aggrdecl = aggr; @@ -380,9 +380,22 @@ LLConstant * IrStruct::createStructInitializer(StructInitializer * si) add_zeros(constants, diff); } + // get initializer type + LLStructType* <ype = si->ltype; + if (!ltype || ltype->isOpaque()) { + std::vector::iterator itr, end = constants.end(); + std::vector types; + for (itr = constants.begin(); itr != end; ++itr) + types.push_back((*itr)->getType()); + if (!ltype) + ltype = LLStructType::get(gIR->context(), types); + else + ltype->setBody(types); + } + // build constant assert(!constants.empty()); - llvm::Constant* c = LLConstantStruct::getAnon(gIR->context(), constants, packed); + llvm::Constant* c = LLConstantStruct::get(ltype, constants); IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl; return c; }