Mercurial > projects > ldc
diff gen/structs.cpp @ 100:5071469303d4 trunk
[svn r104] TONS OF FIXES.
Split up declaration, constant initializer gen and definition for globals, structs, classes and functions.
Improved ClassInfo support (not complete), not in vtable yet.
Fixed a bunch of forward reference problems.
Much more. Major commit! :)
author | lindquist |
---|---|
date | Fri, 16 Nov 2007 08:21:47 +0100 |
parents | ce7ed8f59b99 |
children | 027b8d8b71ec |
line wrap: on
line diff
--- a/gen/structs.cpp Thu Nov 15 00:24:44 2007 +0100 +++ b/gen/structs.cpp Fri Nov 16 08:21:47 2007 +0100 @@ -78,7 +78,9 @@ Logger::println("DtoConstStructInitializer: %s", si->toChars()); LOG_SCOPE; - const llvm::StructType* structtype = isaStruct(si->ad->llvmType); + TypeStruct* ts = (TypeStruct*)si->ad->type; + + const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); Logger::cout() << "llvm struct type: " << *structtype << '\n'; assert(si->value.dim == si->vars.dim); @@ -160,6 +162,231 @@ ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp"); return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb()); } + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoDeclareStruct(StructDeclaration* sd) +{ + if (sd->llvmTouched) return; + sd->llvmTouched = true; + + Logger::println("DtoDeclareStruct(%s)", sd->toChars()); + LOG_SCOPE; + + TypeStruct* ts = (TypeStruct*)DtoDType(sd->type); + + IRStruct* irstruct = new IRStruct(ts); + sd->llvmIRStruct = irstruct; + gIR->structs.push_back(irstruct); + + for (int k=0; k < sd->members->dim; k++) { + Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]); + dsym->toObjFile(); + } + + Logger::println("doing struct fields"); + + const llvm::StructType* structtype = 0; + std::vector<const llvm::Type*> fieldtypes; + + if (irstruct->offsets.empty()) + { + Logger::println("has no fields"); + fieldtypes.push_back(llvm::Type::Int8Ty); + structtype = llvm::StructType::get(fieldtypes); + } + else + { + Logger::println("has fields"); + unsigned prevsize = (unsigned)-1; + unsigned lastoffset = (unsigned)-1; + const llvm::Type* fieldtype = NULL; + VarDeclaration* fieldinit = NULL; + size_t fieldpad = 0; + int idx = 0; + for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { + // first iteration + if (lastoffset == (unsigned)-1) { + lastoffset = i->first; + assert(lastoffset == 0); + fieldtype = i->second.type; + fieldinit = i->second.var; + prevsize = gTargetData->getTypeSize(fieldtype); + i->second.var->llvmFieldIndex = idx; + } + // colliding offset? + else if (lastoffset == i->first) { + size_t s = gTargetData->getTypeSize(i->second.type); + if (s > prevsize) { + fieldpad += s - prevsize; + prevsize = s; + } + sd->llvmHasUnions = true; + i->second.var->llvmFieldIndex = idx; + } + // intersecting offset? + else if (i->first < (lastoffset + prevsize)) { + size_t s = gTargetData->getTypeSize(i->second.type); + assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size + sd->llvmHasUnions = true; + i->second.var->llvmFieldIndex = idx; + i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s; + } + // fresh offset + else { + // commit the field + fieldtypes.push_back(fieldtype); + irstruct->defaultFields.push_back(fieldinit); + if (fieldpad) { + fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad)); + irstruct->defaultFields.push_back(NULL); + idx++; + } + + idx++; + + // start new + lastoffset = i->first; + fieldtype = i->second.type; + fieldinit = i->second.var; + prevsize = gTargetData->getTypeSize(fieldtype); + i->second.var->llvmFieldIndex = idx; + fieldpad = 0; + } + } + fieldtypes.push_back(fieldtype); + irstruct->defaultFields.push_back(fieldinit); + if (fieldpad) { + fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad)); + irstruct->defaultFields.push_back(NULL); + } + + Logger::println("creating struct type"); + structtype = llvm::StructType::get(fieldtypes); + } + + // refine abstract types for stuff like: struct S{S* next;} + if (irstruct->recty != 0) + { + llvm::PATypeHolder& pa = irstruct->recty; + llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype); + structtype = isaStruct(pa.get()); + } + + assert(ts->llvmType == 0); + ts->llvmType = new llvm::PATypeHolder(structtype); + + if (sd->parent->isModule()) { + gIR->module->addTypeName(sd->mangle(),structtype); + } + + std::string initname("_D"); + initname.append(sd->mangle()); + initname.append("6__initZ"); + + llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; + llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); + ts->llvmInit = initvar; + + gIR->structs.pop_back(); + + gIR->constInitQueue.push_back(sd); + if (sd->getModule() == gIR->dmodule) + gIR->defineQueue.push_back(sd); + + // declare typeinfo + if (sd->getModule() == gIR->dmodule && sd->llvmInternal != LLVMnotypeinfo) + sd->type->getTypeInfo(NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoConstInitStruct(StructDeclaration* sd) +{ + IRStruct* irstruct = sd->llvmIRStruct; + if (irstruct->constinited) return; + irstruct->constinited = true; + + Logger::println("DtoConstInitStruct(%s)", sd->toChars()); + LOG_SCOPE; + + gIR->structs.push_back(irstruct); + + // make sure each offset knows its default initializer + for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) + { + IRStruct::Offset* so = &i->second; + llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init); + so->init = finit; + so->var->llvmConstInit = finit; + } + + const llvm::StructType* structtype = isaStruct(sd->type->llvmType->get()); + + // go through the field inits and build the default initializer + std::vector<llvm::Constant*> fieldinits_ll; + size_t nfi = irstruct->defaultFields.size(); + for (size_t i=0; i<nfi; ++i) { + llvm::Constant* c; + if (irstruct->defaultFields[i] != NULL) { + c = irstruct->defaultFields[i]->llvmConstInit; + assert(c); + } + else { + const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i)); + std::vector<llvm::Constant*> vals(arrty->getNumElements(), llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false)); + c = llvm::ConstantArray::get(arrty, vals); + } + fieldinits_ll.push_back(c); + } + + // generate the union mapper + sd->llvmUnion = new DUnion; // uses gIR->topstruct() + + // always generate the constant initalizer + if (!sd->zeroInit) { + Logger::println("Not zero initialized"); + //assert(tk == gIR->gIR->topstruct()().size()); + #ifndef LLVMD_NO_LOGGER + Logger::cout() << "struct type: " << *structtype << '\n'; + for (size_t k=0; k<fieldinits_ll.size(); ++k) { + Logger::cout() << "Type:" << '\n'; + Logger::cout() << *fieldinits_ll[k]->getType() << '\n'; + Logger::cout() << "Value:" << '\n'; + Logger::cout() << *fieldinits_ll[k] << '\n'; + } + Logger::cout() << "Initializer printed" << '\n'; + #endif + sd->llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits_ll); + } + else { + Logger::println("Zero initialized"); + sd->llvmInitZ = llvm::ConstantAggregateZero::get(structtype); + } + + gIR->structs.pop_back(); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +void DtoDefineStruct(StructDeclaration* sd) +{ + IRStruct* irstruct = sd->llvmIRStruct; + if (irstruct->defined) return; + irstruct->defined = true; + + DtoConstInitStruct(sd); + + Logger::println("DtoDefineStruct(%s)", sd->toChars()); + LOG_SCOPE; + + assert(sd->type->ty == Tstruct); + TypeStruct* ts = (TypeStruct*)sd->type; + ts->llvmInit->setInitializer(sd->llvmInitZ); + + sd->llvmDModule = gIR->dmodule; +} + ////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////// D UNION HELPER CLASS //////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// @@ -167,9 +394,9 @@ DUnion::DUnion() { DUnionField* f = NULL; - IRStruct& topstruct = gIR->topstruct(); + IRStruct* topstruct = gIR->topstruct(); bool unions = false; - for (IRStruct::OffsetMap::iterator i=topstruct.offsets.begin(); i!=topstruct.offsets.end(); ++i) + for (IRStruct::OffsetMap::iterator i=topstruct->offsets.begin(); i!=topstruct->offsets.end(); ++i) { unsigned o = i->first; IRStruct::Offset* so = &i->second;