Mercurial > projects > ldc
diff ir/irtypeclass.cpp @ 1228:79758fd2f48a
Added Doxygen file.
Completely seperated type and symbol generation. Should fix a lot of bugs, but is not yet 100% complete.
author | Tomas Lindquist Olsen <tomas.l.olsen gmail.com> |
---|---|
date | Wed, 15 Apr 2009 20:06:25 +0200 |
parents | |
children | e67c85d6e680 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ir/irtypeclass.cpp Wed Apr 15 20:06:25 2009 +0200 @@ -0,0 +1,236 @@ +#include "llvm/DerivedTypes.h" + +#include "aggregate.h" +#include "declaration.h" +#include "dsymbol.h" +#include "mtype.h" + +#include "gen/irstate.h" +#include "gen/logger.h" +#include "gen/tollvm.h" +#include "gen/utils.h" +#include "ir/irtypeclass.h" + +////////////////////////////////////////////////////////////////////////////// + +extern size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff); + +////////////////////////////////////////////////////////////////////////////// + +IrTypeClass::IrTypeClass(ClassDeclaration* cd) +: IrTypeAggr(cd), + cd(cd), + tc((TypeClass*)cd->type), + vtbl_pa(llvm::OpaqueType::get()) +{ + vtbl_size = cd->vtbl.dim; +} + +////////////////////////////////////////////////////////////////////////////// + +void IrTypeClass::addBaseClassData( + std::vector< const llvm::Type * > & defaultTypes, + ClassDeclaration * base, + size_t & offset, + size_t & field_index) +{ + if (base->baseClass) + { + addBaseClassData(defaultTypes, base->baseClass, offset, field_index); + } + + ArrayIter<VarDeclaration> it(base->fields); + for (; !it.done(); it.next()) + { + VarDeclaration* vd = it.get(); + + // skip if offset moved backwards + if (vd->offset < offset) + { + IF_LOG Logger::println("Skipping field %s %s (+%u) for default", vd->type->toChars(), vd->toChars(), vd->offset); + if (vd->ir.irField == NULL) + { + new IrField(vd, 2, vd->offset - PTRSIZE * 2); + } + continue; + } + + IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); + + // get next aligned offset for this type + size_t alignsize = vd->type->alignsize(); + size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1); + + // do we need to insert explicit padding before the field? + if (alignedoffset < vd->offset) + { + field_index += add_zeros(defaultTypes, vd->offset - alignedoffset); + } + + // add default type + defaultTypes.push_back(DtoType(vd->type)); + + // advance offset to right past this field + offset = vd->offset + vd->type->size(); + + // give field index + // the IrField creation doesn't really belong here, but it's a trivial operation + // and it save yet another of these loops. + IF_LOG Logger::println("Field index: %zu", field_index); + if (vd->ir.irField == NULL) + { + new IrField(vd, field_index); + } + field_index++; + } + + // any interface implementations? + if (base->vtblInterfaces) + { + bool new_instances = (base == cd); + + ArrayIter<BaseClass> it2(*base->vtblInterfaces); + + for (; !it2.done(); it2.next()) + { + BaseClass* b = it2.get(); + IF_LOG Logger::println("Adding interface vtbl for %s", b->base->toPrettyChars()); + + Array arr; + b->fillVtbl(cd, &arr, new_instances); + + const llvm::Type* ivtbl_type = buildVtblType(Type::tvoid->pointerTo(), &arr); + defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0)); + + offset += PTRSIZE; + + // add to the interface map + if (interfaceMap.find(b->base) == interfaceMap.end()) + interfaceMap.insert(std::make_pair(b->base, field_index)); + field_index++; + } + } + + // tail padding? + if (offset < base->structsize) + { + field_index += add_zeros(defaultTypes, base->structsize - offset); + offset = base->structsize; + } +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* IrTypeClass::buildType() +{ + IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(), cd->locToChars()); + LOG_SCOPE; + IF_LOG Logger::println("Instance size: %u", cd->structsize); + + // find the fields that contribute to the default initializer. + // these will define the default type. + + std::vector<const llvm::Type*> defaultTypes; + defaultTypes.reserve(32); + + // add vtbl + defaultTypes.push_back(llvm::PointerType::get(vtbl_pa.get(), 0)); + + // interface are just a vtable + if (!cd->isInterfaceDeclaration()) + { + // add monitor + defaultTypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty, 0)); + + // we start right after the vtbl and monitor + size_t offset = PTRSIZE * 2; + size_t field_index = 2; + + // add data members recursively + addBaseClassData(defaultTypes, cd, offset, field_index); + } + + // errors are fatal during codegen + if (global.errors) + fatal(); + + // build the llvm type + const llvm::Type* st = llvm::StructType::get(defaultTypes, false); + + // refine type + llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(st); + + // name type + Type::sir->getState()->module->addTypeName(cd->toPrettyChars(), pa.get()); + + // VTBL + + // build vtbl type + const llvm::Type* vtblty = buildVtblType( + ClassDeclaration::classinfo->type, + &cd->vtbl); + + // refine vtbl pa + llvm::cast<llvm::OpaqueType>(vtbl_pa.get())->refineAbstractTypeTo(vtblty); + + // name vtbl type + std::string name(cd->toPrettyChars()); + name.append(".__vtbl"); + Type::sir->getState()->module->addTypeName(name, vtbl_pa.get()); + +#if 0 + IF_LOG Logger::cout() << "class type: " << *pa.get() << std::endl; +#endif + + return get(); +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type* IrTypeClass::buildVtblType(Type* first, Array* vtbl_array) +{ + IF_LOG Logger::println("Building vtbl type for class %s", cd->toPrettyChars()); + LOG_SCOPE; + + std::vector<const llvm::Type*> types; + types.reserve(vtbl_array->dim); + + // first comes the classinfo + types.push_back(DtoType(first)); + + // then come the functions + ArrayIter<Dsymbol> it(*vtbl_array); + it.index = 1; + + for (; !it.done(); it.next()) + { + FuncDeclaration* fd = it.get()->isFuncDeclaration(); + assert(fd && "invalid vtbl entry"); + + IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars()); + + types.push_back(DtoType(fd->type->pointerTo())); + } + + // build the vtbl llvm type + return llvm::StructType::get(types, false); +} + +////////////////////////////////////////////////////////////////////////////// + +const llvm::Type * IrTypeClass::get() +{ + return llvm::PointerType::get(pa.get(), 0); +} + +////////////////////////////////////////////////////////////////////////////// + +size_t IrTypeClass::getInterfaceIndex(ClassDeclaration * inter) +{ + ClassIndexMap::iterator it = interfaceMap.find(inter); + if (it == interfaceMap.end()) + return ~0; + return it->second; +} + +//////////////////////////////////////////////////////////////////////////////