Mercurial > projects > ldc
diff gen/structs.cpp @ 1231:212ec2d9d176
Fixed some minitest regressions.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Thu, 16 Apr 2009 19:21:30 +0200 |
parents | 79758fd2f48a |
children | 9201e0d41ee5 |
line wrap: on
line diff
--- 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<llvm::Value*>& 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<llvm::Value*> DtoStructLiteralValues(const StructDeclaration* sd, const std::vector<llvm::Value*>& 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<VarDeclaration*> 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<llvm::Value*> 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<nvars; i++) + { + 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 (!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