# HG changeset patch # User Tomas Lindquist Olsen # Date 1239902490 -7200 # Node ID 212ec2d9d1769672129bb71937739666f93f1163 # Parent e67c85d6e680800e7c3177ef96ca5b64ad61db98 Fixed some minitest regressions. diff -r e67c85d6e680 -r 212ec2d9d176 gen/classes.cpp --- a/gen/classes.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/gen/classes.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -486,8 +486,7 @@ LLValue* funcval = vthis; // get the vtbl for objects - if (!fdecl->isMember()->isInterfaceDeclaration()) - funcval = DtoGEPi(funcval, 0, 0, "tmp"); + funcval = DtoGEPi(funcval, 0, 0, "tmp"); // load vtbl ptr funcval = DtoLoad(funcval); // index vtbl diff -r e67c85d6e680 -r 212ec2d9d176 gen/structs.cpp --- a/gen/structs.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/gen/structs.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -22,46 +22,6 @@ ////////////////////////////////////////////////////////////////////////////////////////// -LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) -{ - Logger::println("indexing struct field %s:", vd->toPrettyChars()); - LOG_SCOPE; - - DtoResolveStruct(sd); - - // vd must be a field - IrField* field = vd->ir.irField; - assert(field); - - // get the start pointer - const LLType* st = getPtrToType(DtoType(sd->type)); - - // cast to the formal struct type - src = DtoBitCast(src, st); - - // gep to the index - LLValue* val = DtoGEPi(src, 0, field->index); - - // do we need to offset further? (union area) - if (field->unionOffset) - { - // cast to void* - val = DtoBitCast(val, getVoidPtrType()); - // offset - val = DtoGEPi1(val, field->unionOffset); - } - - // cast it to the right type - val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); - - if (Logger::enabled()) - Logger::cout() << "value: " << *val << '\n'; - - return val; -} - -////////////////////////////////////////////////////////////////////////////////////////// - void DtoResolveStruct(StructDeclaration* sd) { // don't do anything if already been here @@ -128,3 +88,226 @@ LLValue* val = DtoMemCmp(lhs->getRVal(), rhs->getRVal(), DtoConstSize_t(sz)); return gIR->ir->CreateICmp(cmpop, val, LLConstantInt::get(val->getType(), 0, false), "tmp"); } + +////////////////////////////////////////////////////////////////////////////////////////// + +LLValue* DtoIndexStruct(LLValue* src, StructDeclaration* sd, VarDeclaration* vd) +{ + Logger::println("indexing struct field %s:", vd->toPrettyChars()); + LOG_SCOPE; + + DtoResolveStruct(sd); + + // vd must be a field + IrField* field = vd->ir.irField; + assert(field); + + // get the start pointer + const LLType* st = getPtrToType(DtoType(sd->type)); + + // cast to the formal struct type + src = DtoBitCast(src, st); + + // gep to the index + LLValue* val = DtoGEPi(src, 0, field->index); + + // do we need to offset further? (union area) + if (field->unionOffset) + { + // cast to void* + val = DtoBitCast(val, getVoidPtrType()); + // offset + val = DtoGEPi1(val, field->unionOffset); + } + + // cast it to the right type + val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); + + if (Logger::enabled()) + Logger::cout() << "value: " << *val << '\n'; + + return val; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +// helper function that adds zero bytes to a vector of constants +size_t add_zeros(std::vector& values, size_t diff) +{ + size_t n = values.size(); + bool is64 = global.params.is64bit; + while (diff) + { + if (is64 && diff % 8 == 0) + { + values.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty)); + diff -= 8; + } + else if (diff % 4 == 0) + { + values.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty)); + diff -= 4; + } + else if (diff % 2 == 0) + { + values.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty)); + diff -= 2; + } + else + { + values.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty)); + diff -= 1; + } + } + return values.size() - n; +} + +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); + add_zeros(values, os - lastoffset - lastsize); + } + + // get field default init + IrField* f = var->ir.irField; + assert(f); + values.push_back(f->getDefaultInit()); + + 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); + add_zeros(values, os - lastoffset - lastsize); + } + + // 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 = getTypePaddedSize(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); + add_zeros(values, os - lastoffset - lastsize); + } + + // get field default init + IrField* f = var->ir.irField; + assert(f); + values.push_back(f->getDefaultInit()); + + 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); + add_zeros(values, structsize - lastoffset - lastsize); + } + + return values; +} \ No newline at end of file diff -r e67c85d6e680 -r 212ec2d9d176 gen/toir.cpp --- a/gen/toir.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/gen/toir.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -982,6 +982,7 @@ } else if (e1->op == TOKstructliteral) { + // FIXME: is this right? StructLiteralExp* slexp = (StructLiteralExp*)e1; LLConstant* lit = slexp->toConstElem(p); return lit; @@ -2409,8 +2410,7 @@ } // vector of values to build aggregate from - std::vector values;// = DtoStructLiteralValues(sd, inits); - assert(0 && "struct literal exp todo"); + std::vector values = DtoStructLiteralValues(sd, inits); // get the struct type from the values size_t n = values.size(); @@ -2459,8 +2459,7 @@ inits[i] = exprs[i]->toConstElem(p); // vector of values to build aggregate from - std::vector values;// = DtoStructLiteralValues(sd, inits); - assert(0 && "struct literal const exp todo"); + std::vector values = DtoStructLiteralValues(sd, inits); // we know those values are constants.. cast them std::vector constvals(values.size(), NULL); diff -r e67c85d6e680 -r 212ec2d9d176 ir/irclass.cpp --- a/ir/irclass.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irclass.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -81,6 +81,8 @@ ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + // FIXME: + // also happens for mini/s.d :( assert(cd->vtblInterfaces && cd->vtblInterfaces->dim > 0 && "should not create interface info array for class with no explicit " "interface implementations"); @@ -324,7 +326,14 @@ for (size_t i = 1; i < n; i++) { Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i]; - assert(dsym && "null vtbl member"); + if (dsym == NULL) + { + // FIXME + // why is this null? + // happens for mini/s.d + constants.push_back(getNullValue(getVoidPtrType())); + continue; + } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); diff -r e67c85d6e680 -r 212ec2d9d176 ir/irstruct.cpp --- a/ir/irstruct.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irstruct.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -23,7 +23,9 @@ type = aggr->type; - packed = false; + packed = (type->ty == Tstruct) + ? type->alignsize() == 1 + : false; // above still need to be looked at @@ -190,8 +192,10 @@ IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl; // sanity check - assert(definit->getType() == type->irtype->get() && - "default initializer type does not match the default struct type"); + if (definit->getType() != type->irtype->get()) + { + assert(0 && "default initializer type does not match the default struct type"); + } return definit; } diff -r e67c85d6e680 -r 212ec2d9d176 ir/irtypeclass.cpp --- a/ir/irtypeclass.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irtypeclass.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -212,7 +212,17 @@ for (; !it.done(); it.next()) { - FuncDeclaration* fd = it.get()->isFuncDeclaration(); + Dsymbol* dsym = it.get(); + if (dsym == NULL) + { + // FIXME + // why is this null? + // happens for mini/s.d + types.push_back(getVoidPtrType()); + continue; + } + + FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "invalid vtbl entry"); IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); diff -r e67c85d6e680 -r 212ec2d9d176 ir/irtypestruct.cpp --- a/ir/irtypestruct.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irtypestruct.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -138,8 +138,8 @@ // name types Type::sir->getState()->module->addTypeName(sd->toPrettyChars(), pa.get()); -#if 0 - IF_LOG Logger::cout() << "struct type: " << *pa.get() << std::endl; +#if 1 + IF_LOG Logger::cout() << "final struct type: " << *pa.get() << std::endl; #endif return pa.get(); diff -r e67c85d6e680 -r 212ec2d9d176 ir/irvar.cpp --- a/ir/irvar.cpp Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irvar.cpp Thu Apr 16 19:21:30 2009 +0200 @@ -46,6 +46,18 @@ V->ir.irField = this; } +extern LLConstant* get_default_initializer( + VarDeclaration* vd, + Initializer* init); + +llvm::Constant * IrField::getDefaultInit() +{ + if (constInit) + return constInit; + constInit = get_default_initializer(V, V->init); + return constInit; +} + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff -r e67c85d6e680 -r 212ec2d9d176 ir/irvar.h --- a/ir/irvar.h Thu Apr 16 13:18:56 2009 +0200 +++ b/ir/irvar.h Thu Apr 16 19:21:30 2009 +0200 @@ -39,7 +39,10 @@ unsigned index; unsigned unionOffset; + llvm::Constant* getDefaultInit(); + protected: + /// FIXME: only used for StructLiteralsExps llvm::Constant* constInit; };