ldc/ir/irtypeclass.cpp
2009-04-26 11:29:30 +02:00

277 lines
7.8 KiB
C++

#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;
num_interface_vtbls = 0;
}
//////////////////////////////////////////////////////////////////////////////
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);
VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
Type* first = interfaces_idx->type->next->pointerTo();
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(first, &arr);
defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0));
offset += PTRSIZE;
// add to the interface map
addInterfaceToMap(b->base, field_index);
field_index++;
// inc count
num_interface_vtbls++;
}
}
// 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));
// interfaces are just a vtable
if (cd->isInterfaceDeclaration())
{
num_interface_vtbls = cd->vtblInterfaces ? cd->vtblInterfaces->dim : 0;
}
// classes have monitor and fields
else
{
// 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())
{
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());
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;
}
//////////////////////////////////////////////////////////////////////////////
void IrTypeClass::addInterfaceToMap(ClassDeclaration * inter, size_t index)
{
// don't duplicate work or overwrite indices
if (interfaceMap.find(inter) != interfaceMap.end())
return;
// add this interface
interfaceMap.insert(std::make_pair(inter, index));
// add the direct base interfaces recursively - they
// are accessed through the same index
if (inter->interfaces_dim > 0)
{
BaseClass* b = inter->interfaces[0];
addInterfaceToMap(b->base, index);
}
}
//////////////////////////////////////////////////////////////////////////////