# HG changeset patch # User Christian Kamm # Date 1230633721 -3600 # Node ID af7a6faf94068b86d2a816921c9cea05912371f4 # Parent 5dbc63f83380728288eb840d1ea2bac909557c2a Fix #153. Factor out common code in StructLiteralExp::to(Const)Elem. diff -r 5dbc63f83380 -r af7a6faf9406 gen/structs.cpp --- a/gen/structs.cpp Sat Dec 27 16:07:23 2008 +0100 +++ b/gen/structs.cpp Tue Dec 30 11:42:01 2008 +0100 @@ -298,6 +298,164 @@ ////////////////////////////////////////////////////////////////////////////////////////// +std::vector DtoStructLiteralValues(const StructDeclaration* sd, const std::vector& inits) +{ + // get arrays + size_t nvars = sd->fields.dim; + VarDeclaration** vars = (VarDeclaration**)sd->fields.data; + + assert(inits.size() == nvars); + + // first locate all explicit initializers + std::vector explicitInits; + for (size_t i=0; i < nvars; i++) + { + if (inits[i]) + { + explicitInits.push_back(vars[i]); + } + } + + // vector of values to build aggregate from + std::vector values; + + // offset trackers + size_t lastoffset = 0; + size_t lastsize = 0; + + // index of next explicit init + size_t exidx = 0; + // number of explicit inits + size_t nex = explicitInits.size(); + + // for through each field and build up the struct, padding with zeros + size_t i; + for (i=0; ioffset; + size_t sz = var->type->size(); + + // get next explicit + VarDeclaration* nextVar = NULL; + size_t nextOs = 0; + if (exidx < nex) + { + nextVar = explicitInits[exidx]; + nextOs = nextVar->offset; + } + // none, rest is defaults + else + { + break; + } + + // not explicit initializer, default initialize if there is room, otherwise skip + if (!inits[i]) + { + // default init if there is room + // (past current offset) and (small enough to fit before next explicit) + if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) + { + // add any 0 padding needed before this field + if (os > lastoffset + lastsize) + { + //printf("1added %lu zeros\n", os - lastoffset - lastsize); + addZeros(values, lastoffset + lastsize, os); + } + + // get field default init + IrField* f = var->ir.irField; + assert(f); + if (!f->constInit) + f->constInit = DtoConstInitializer(var->loc, var->type, var->init); + + values.push_back(f->constInit); + + lastoffset = os; + lastsize = sz; + //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); + } + // skip + continue; + } + + assert(nextVar == var); + + // add any 0 padding needed before this field + if (os > lastoffset + lastsize) + { + //printf("added %lu zeros\n", os - lastoffset - lastsize); + addZeros(values, lastoffset + lastsize, os); + } + + // add the expression value + values.push_back(inits[i]); + + // update offsets + lastoffset = os; + lastsize = sz; + + // go to next explicit init + exidx++; + + //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); + } + + // fill out rest with default initializers + const LLType* structtype = DtoType(sd->type); + size_t structsize = getABITypeSize(structtype); + + // FIXME: this could probably share some code with the above + if (structsize > lastoffset+lastsize) + { + for (/*continue from first loop*/; i < nvars; i++) + { + VarDeclaration* var = vars[i]; + + // get var info + size_t os = var->offset; + size_t sz = var->type->size(); + + // skip? + if (os < lastoffset + lastsize) + continue; + + // add any 0 padding needed before this field + if (os > lastoffset + lastsize) + { + //printf("2added %lu zeros\n", os - lastoffset - lastsize); + addZeros(values, lastoffset + lastsize, os); + } + + // get field default init + IrField* f = var->ir.irField; + assert(f); + if (!f->constInit) + f->constInit = DtoConstInitializer(var->loc, var->type, var->init); + + values.push_back(f->constInit); + + lastoffset = os; + lastsize = sz; + //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); + } + } + + // add any 0 padding needed at the end of the literal + if (structsize > lastoffset+lastsize) + { + //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); + addZeros(values, lastoffset + lastsize, structsize); + } + + return values; +} + +////////////////////////////////////////////////////////////////////////////////////////// + LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) { Logger::println("indexing struct field %s:", vd->toPrettyChars()); diff -r 5dbc63f83380 -r af7a6faf9406 gen/structs.h --- a/gen/structs.h Sat Dec 27 16:07:23 2008 +0100 +++ b/gen/structs.h Tue Dec 30 11:42:01 2008 +0100 @@ -4,6 +4,7 @@ struct StructInitializer; LLConstant* DtoConstStructInitializer(StructInitializer* si); +std::vector DtoStructLiteralValues(const StructDeclaration* sd, const std::vector& inits); /** * Resolves the llvm type for a struct diff -r 5dbc63f83380 -r af7a6faf9406 gen/toir.cpp --- a/gen/toir.cpp Sat Dec 27 16:07:23 2008 +0100 +++ b/gen/toir.cpp Tue Dec 30 11:42:01 2008 +0100 @@ -860,15 +860,34 @@ Logger::print("CastExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - LLConstant* c = e1->toConstElem(p); + LLConstant* res; const LLType* lltype = DtoType(type); - - if(!isaPointer(c->getType()) || !isaPointer(lltype)) { - error("can only cast pointers to pointers at code generation time, not %s to %s", type->toChars(), e1->type->toChars()); - fatal(); + Type* tb = to->toBasetype(); + + // string literal to dyn array: + // reinterpret the string data as an array, calculate the length + if (e1->op == TOKstring && tb->ty == Tarray) { +/* StringExp *strexp = (StringExp*)e1; + size_t datalen = strexp->sz * strexp->len; + Type* eltype = tb->nextOf()->toBasetype(); + if (datalen % eltype->size() != 0) { + error("the sizes don't line up"); + return e1->toConstElem(p); + } + size_t arrlen = datalen / eltype->size();*/ + error("ct cast of string to dynamic array not fully implemented"); + return e1->toConstElem(p); } - - return llvm::ConstantExpr::getBitCast(c, lltype); + // pointer to pointer + else if (tb->ty == Tpointer && e1->type->toBasetype()->ty == Tpointer) { + res = llvm::ConstantExpr::getBitCast(e1->toConstElem(p), lltype); + } + else { + error("can not cast %s to %s at compile time", e1->type->toChars(), type->toChars()); + return e1->toConstElem(p); + } + + return res; } ////////////////////////////////////////////////////////////////////////////////////////// @@ -2364,161 +2383,23 @@ Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - // get arrays + // get inits + std::vector inits(sd->fields.dim, NULL); + size_t nexprs = elements->dim;; Expression** exprs = (Expression**)elements->data; - size_t nvars = sd->fields.dim; - VarDeclaration** vars = (VarDeclaration**)sd->fields.data; - - assert(nexprs <= nvars); - - // first locate all explicit initializers - std::vector explicitInits; - for (size_t i=0; i < nexprs; i++) + for (size_t i = 0; i < nexprs; i++) { if (exprs[i]) { - explicitInits.push_back(vars[i]); + DValue* v = exprs[i]->toElem(p); + inits[i] = v->getRVal(); } } // vector of values to build aggregate from - std::vector values; - - // offset trackers - size_t lastoffset = 0; - size_t lastsize = 0; - - // index of next explicit init - size_t exidx = 0; - // number of explicit inits - size_t nex = explicitInits.size(); - - // for through each field and build up the struct, padding with zeros - size_t i; - for (i=0; i i) ? exprs[i] : NULL; - VarDeclaration* var = vars[i]; - - // get var info - size_t os = var->offset; - size_t sz = var->type->size(); - - // get next explicit - VarDeclaration* nextVar = NULL; - size_t nextOs = 0; - if (exidx < nex) - { - nextVar = explicitInits[exidx]; - nextOs = nextVar->offset; - } - // none, rest is defaults - else - { - break; - } - - // not explicit initializer, default initialize if there is room, otherwise skip - if (!e) - { - // default init if there is room - // (past current offset) and (small enough to fit before next explicit) - if ((os >= lastoffset + lastsize) && (os+sz <= nextOs)) - { - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("1added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - if (!f->constInit) - f->constInit = DtoConstInitializer(var->loc, var->type, var->init); - - values.push_back(f->constInit); - - lastoffset = os; - lastsize = sz; - //printf("added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - // skip - continue; - } - - assert(nextVar == var); - - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // add the expression value - DValue* v = e->toElem(p); - values.push_back(v->getRVal()); - - // update offsets - lastoffset = os; - lastsize = sz; - - // go to next explicit init - exidx++; - - //printf("added field: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - - // fill out rest with default initializers - const LLType* structtype = DtoType(sd->type); - size_t structsize = getABITypeSize(structtype); - - // FIXME: this could probably share some code with the above - if (structsize > lastoffset+lastsize) - { - for (/*continue from first loop*/; i < nvars; i++) - { - VarDeclaration* var = vars[i]; - - // get var info - size_t os = var->offset; - size_t sz = var->type->size(); - - // skip? - if (os < lastoffset + lastsize) - continue; - - // add any 0 padding needed before this field - if (os > lastoffset + lastsize) - { - //printf("2added %lu zeros\n", os - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, os); - } - - // get field default init - IrField* f = var->ir.irField; - assert(f); - if (!f->constInit) - f->constInit = DtoConstInitializer(var->loc, var->type, var->init); - - values.push_back(f->constInit); - - lastoffset = os; - lastsize = sz; - //printf("2added default: %s : %lu (%lu)\n", var->toChars(), os, sz); - } - } - - // add any 0 padding needed at the end of the literal - if (structsize > lastoffset+lastsize) - { - //printf("3added %lu zeros\n", structsize - lastoffset - lastsize); - addZeros(values, lastoffset + lastsize, structsize); - } + std::vector values = DtoStructLiteralValues(sd, inits); // get the struct type from the values size_t n = values.size(); @@ -2542,6 +2423,7 @@ } // cast the alloca pointer to the "formal" struct type + const LLType* structtype = DtoType(sd->type); mem = DtoBitCast(mem, getPtrToType(structtype)); // return as a var @@ -2555,55 +2437,26 @@ Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; - // get arrays - size_t n = elements->dim; + // get inits + std::vector inits(sd->fields.dim, NULL); + + size_t nexprs = elements->dim;; Expression** exprs = (Expression**)elements->data; - assert(sd->fields.dim == n); - VarDeclaration** vars = (VarDeclaration**)sd->fields.data; + for (size_t i = 0; i < nexprs; i++) + if (exprs[i]) + inits[i] = exprs[i]->toConstElem(p); // vector of values to build aggregate from - std::vector values; - - // trackers - size_t lastoffset = 0; - size_t lastsize = 0; - - // for through each field and build up the struct, padding with zeros - for (size_t i=0; ioffset > lastoffset + lastsize) - { - addZeros(values, lastoffset + lastsize, var->offset); - } - - // add the expression value - values.push_back(e->toConstElem(p)); - - // update offsets - lastoffset = var->offset; - lastsize = var->type->size(); - } - - // add any 0 padding needed at the end of the literal - const LLType* structtype = DtoType(sd->type); - size_t structsize = getABITypeSize(structtype); - - if (structsize > lastoffset+lastsize) - { - addZeros(values, lastoffset + lastsize, structsize); - } + std::vector values = DtoStructLiteralValues(sd, inits); + + // we know those values are constants.. cast them + std::vector constvals(values.size(), NULL); + for (size_t i = 0; i < values.size(); ++i) + constvals[i] = llvm::cast(values[i]); // return constant struct - return LLConstantStruct::get(values, sd->ir.irStruct->packed); + return LLConstantStruct::get(constvals, sd->ir.irStruct->packed); } //////////////////////////////////////////////////////////////////////////////////////////