This commit is contained in:
Tomas Lindquist Olsen
2009-04-16 20:31:21 +02:00
33 changed files with 3350 additions and 2132 deletions

472
ir/irclass.cpp Normal file
View File

@@ -0,0 +1,472 @@
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "aggregate.h"
#include "declaration.h"
#include "mtype.h"
#include "gen/irstate.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/llvmhelpers.h"
#include "gen/utils.h"
#include "gen/arrays.h"
#include "ir/irstruct.h"
#include "ir/irtypeclass.h"
//////////////////////////////////////////////////////////////////////////////
extern LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init);
extern size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff);
extern LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
//////////////////////////////////////////////////////////////////////////////
LLGlobalVariable * IrStruct::getVtblSymbol()
{
if (vtbl)
return vtbl;
// create the initZ symbol
std::string initname("_D");
initname.append(aggrdecl->mangle());
initname.append("6__vtblZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
const LLType* vtblTy = type->irtype->isClass()->getVtbl();
vtbl = new llvm::GlobalVariable(
vtblTy, true, _linkage, NULL, initname, gIR->module);
return vtbl;
}
//////////////////////////////////////////////////////////////////////////////
LLGlobalVariable * IrStruct::getClassInfoSymbol()
{
if (classInfo)
return classInfo;
// create the initZ symbol
std::string initname("_D");
initname.append(aggrdecl->mangle());
if (aggrdecl->isInterfaceDeclaration())
initname.append("11__InterfaceZ");
else
initname.append("7__ClassZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
ClassDeclaration* cinfo = ClassDeclaration::classinfo;
DtoType(cinfo->type);
IrTypeClass* tc = cinfo->type->irtype->isClass();
assert(tc && "invalid ClassInfo type");
classInfo = new llvm::GlobalVariable(
tc->getPA().get(), true, _linkage, NULL, initname, gIR->module);
return classInfo;
}
//////////////////////////////////////////////////////////////////////////////
LLGlobalVariable * IrStruct::getInterfaceArraySymbol()
{
if (classInterfacesArray)
return classInterfacesArray;
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");
VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
const llvm::Type* InterfaceTy = DtoType(idx->type->next);
// create Interface[N]
const llvm::ArrayType* array_type = llvm::ArrayType::get(
InterfaceTy,
type->irtype->isClass()->getNumInterfaceVtbls());
// put it in a global
std::string name("_D");
name.append(cd->mangle());
name.append("16__interfaceInfosZ");
classInterfacesArray = new llvm::GlobalVariable(array_type, true, DtoLinkage(cd), NULL, name, classInfo);
return classInterfacesArray;
}
//////////////////////////////////////////////////////////////////////////////
LLConstant * IrStruct::getVtblInit()
{
if (constVtbl)
return constVtbl;
IF_LOG Logger::println("Building vtbl initializer");
LOG_SCOPE;
ClassDeclaration* cd = aggrdecl->isClassDeclaration();
assert(cd && "not class");
std::vector<llvm::Constant*> constants;
constants.reserve(cd->vtbl.dim);
// start with the classinfo
llvm::Constant* c = getClassInfoSymbol();
c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type));
constants.push_back(c);
// add virtual function pointers
size_t n = cd->vtbl.dim;
for (size_t i = 1; i < n; i++)
{
Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[i];
assert(dsym && "null vtbl member");
FuncDeclaration* fd = dsym->isFuncDeclaration();
assert(fd && "vtbl entry not a function");
if (fd->isAbstract() && !fd->fbody)
{
c = getNullValue(DtoType(fd->type->pointerTo()));
}
else
{
fd->codegen(Type::sir);
assert(fd->ir.irFunc && "invalid vtbl function");
c = fd->ir.irFunc->func;
}
constants.push_back(c);
}
// build the constant struct
constVtbl = llvm::ConstantStruct::get(constants, false);
// sanity check
#if 0
IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl;
IF_LOG Logger::cout() << "vtbl type: " << *type->irtype->isClass()->getVtbl() << std::endl;
#endif
assert(constVtbl->getType() == type->irtype->isClass()->getVtbl() &&
"vtbl initializer type mismatch");
return constVtbl;
}
//////////////////////////////////////////////////////////////////////////////
LLConstant * IrStruct::getClassInfoInit()
{
if (constClassInfo)
return constClassInfo;
constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration());
return constClassInfo;
}
//////////////////////////////////////////////////////////////////////////////
void IrStruct::addBaseClassInits(
std::vector<llvm::Constant*>& constants,
ClassDeclaration* base,
size_t& offset,
size_t& field_index)
{
if (base->baseClass)
{
addBaseClassInits(constants, 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);
continue;
}
IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
LOG_SCOPE;
// get next aligned offset for this type
size_t alignsize = vd->type->alignsize();
size_t alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
// insert explicit padding?
if (alignedoffset < vd->offset)
{
add_zeros(constants, vd->offset - alignedoffset);
}
// add default type
constants.push_back(get_default_initializer(vd, vd->init));
// advance offset to right past this field
offset = vd->offset + vd->type->size();
}
// has interface vtbls?
if (base->vtblInterfaces)
{
// false when it's not okay to use functions from super classes
bool newinsts = (base == aggrdecl->isClassDeclaration());
size_t inter_idx = interfacesWithVtbls.size();
ArrayIter<BaseClass> it2(*base->vtblInterfaces);
for (; !it2.done(); it2.next())
{
BaseClass* b = it2.get();
constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx));
offset += PTRSIZE;
// add to the interface list
interfacesWithVtbls.push_back(b);
inter_idx++;
}
}
// tail padding?
if (offset < base->structsize)
{
add_zeros(constants, base->structsize - offset);
offset = base->structsize;
}
}
//////////////////////////////////////////////////////////////////////////////
LLConstant * IrStruct::createClassDefaultInitializer()
{
ClassDeclaration* cd = aggrdecl->isClassDeclaration();
assert(cd && "invalid class aggregate");
IF_LOG Logger::println("Building class default initializer %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<llvm::Constant*> constants;
constants.reserve(32);
// add vtbl
constants.push_back(getVtblSymbol());
// add monitor
constants.push_back(getNullValue(DtoType(Type::tvoid->pointerTo())));
// we start right after the vtbl and monitor
size_t offset = PTRSIZE * 2;
size_t field_index = 2;
// add data members recursively
addBaseClassInits(constants, cd, offset, field_index);
// build the constant
llvm::Constant* definit = llvm::ConstantStruct::get(constants, false);
// sanity check
assert(definit->getType() == type->irtype->getPA().get() && "class initializer type mismatch");
return definit;
}
//////////////////////////////////////////////////////////////////////////////
llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index)
{
ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base);
if (it != interfaceVtblMap.end())
return it->second;
IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s",
b->base->toPrettyChars(), aggrdecl->toPrettyChars());
LOG_SCOPE;
ClassDeclaration* cd = aggrdecl->isClassDeclaration();
assert(cd && "not a class aggregate");
Array vtbl_array;
b->fillVtbl(cd, &vtbl_array, new_instance);
std::vector<llvm::Constant*> constants;
constants.reserve(vtbl_array.dim);
// start with the interface info
VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3);
Type* first = interfaces_idx->type->next->pointerTo();
// index into the interfaces array
llvm::Constant* idxs[2] = {
DtoConstSize_t(0),
DtoConstSize_t(interfaces_index)
};
llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr(
getInterfaceArraySymbol(), idxs, 2);
constants.push_back(c);
// add virtual function pointers
size_t n = vtbl_array.dim;
for (size_t i = 1; i < n; i++)
{
Dsymbol* dsym = (Dsymbol*)vtbl_array.data[i];
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");
assert(!(fd->isAbstract() && !fd->fbody) &&
"null symbol in interface implementation vtable");
fd->codegen(Type::sir);
assert(fd->ir.irFunc && "invalid vtbl function");
constants.push_back(fd->ir.irFunc->func);
}
// build the vtbl constant
llvm::Constant* vtbl_constant = llvm::ConstantStruct::get(constants, false);
// create the global variable to hold it
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
std::string mangle("_D");
mangle.append(cd->mangle());
mangle.append("11__interface");
mangle.append(b->base->mangle());
mangle.append("6__vtblZ");
llvm::GlobalVariable* GV = new llvm::GlobalVariable(
vtbl_constant->getType(),
true,
_linkage,
vtbl_constant,
mangle,
gIR->module
);
// insert into the vtbl map
interfaceVtblMap.insert(std::make_pair(b->base, GV));
return GV;
}
//////////////////////////////////////////////////////////////////////////////
LLConstant * IrStruct::getClassInfoInterfaces()
{
IF_LOG Logger::println("Building ClassInfo.interfaces");
LOG_SCOPE;
ClassDeclaration* cd = aggrdecl->isClassDeclaration();
assert(cd);
size_t n = interfacesWithVtbls.size();
assert(type->irtype->isClass()->getNumInterfaceVtbls() == n &&
"inconsistent number of interface vtables in this class");
if (n == 0)
{
VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3);
return getNullValue(DtoType(idx->type));
}
// Build array of:
//
// struct Interface
// {
// ClassInfo classinfo;
// void*[] vtbl;
// ptrdiff_t offset;
// }
LLSmallVector<LLConstant*, 6> constants;
constants.reserve(cd->vtblInterfaces->dim);
const LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type);
const LLType* voidptrptr_type = DtoType(
Type::tvoid->pointerTo()->pointerTo());
const LLType* our_type = type->irtype->isClass()->getPA().get();
for (size_t i = 0; i < n; ++i)
{
BaseClass* it = interfacesWithVtbls[i];
IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars());
IrStruct* irinter = it->base->ir.irStruct;
assert(irinter && "interface has null IrStruct");
IrTypeClass* itc = irinter->type->irtype->isClass();
assert(itc && "null interface IrTypeClass");
// classinfo
LLConstant* ci = irinter->getClassInfoSymbol();
ci = DtoBitCast(ci, classinfo_type);
// vtbl
ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base);
assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
LLConstant* vtb = itv->second;
vtb = DtoBitCast(vtb, voidptrptr_type);
vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
// offset
LLConstant* off = DtoConstSize_t(it->offset);
// create Interface struct
LLConstant* inits[3] = { ci, vtb, off };
LLConstant* entry = llvm::ConstantStruct::get(inits, 3);
constants.push_back(entry);
}
// create Interface[N]
const llvm::ArrayType* array_type = llvm::ArrayType::get(
constants[0]->getType(),
n);
LLConstant* arr = llvm::ConstantArray::get(
array_type,
&constants[0],
constants.size());
// apply the initializer
classInterfacesArray->setInitializer(arr);
LLConstant* idxs[2] = {
DtoConstSize_t(0),
// only the interface explicitly implemented by this class
// (not super classes) should show in ClassInfo
DtoConstSize_t(n - cd->vtblInterfaces->dim)
};
// return as a slice
return DtoConstSlice(
DtoConstSize_t(n),
llvm::ConstantExpr::getGetElementPtr(classInterfacesArray, idxs, 2));
}
//////////////////////////////////////////////////////////////////////////////

View File

@@ -128,7 +128,7 @@ void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB)
}
assert(it->catchType);
assert(it->catchType->ir.irStruct);
selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->classInfo);
selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->getClassInfoSymbol());
}
}
// if there's a finally, the eh table has to have a 0 action

View File

@@ -5,353 +5,334 @@
#include "declaration.h"
#include "init.h"
#include "ir/irstruct.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "gen/logger.h"
#include "gen/llvmhelpers.h"
#include "gen/utils.h"
IrInterface::IrInterface(BaseClass* b)
: vtblInitTy(llvm::OpaqueType::get())
{
base = b;
decl = b->base;
vtblInit = NULL;
vtbl = NULL;
infoTy = NULL;
infoInit = NULL;
info = NULL;
#include "ir/irstruct.h"
#include "ir/irtypeclass.h"
index = 0;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrStruct::IrStruct(AggregateDeclaration* aggr)
: initOpaque(llvm::OpaqueType::get()),
classInfoOpaque(llvm::OpaqueType::get()),
vtblTy(llvm::OpaqueType::get()),
vtblInitTy(llvm::OpaqueType::get()),
diCompositeType(NULL)
: diCompositeType(NULL)
{
aggrdecl = aggr;
defaultFound = false;
anon = NULL;
index = 0;
type = aggr->type;
defined = false;
constinited = false;
interfaceInfos = NULL;
vtbl = NULL;
constVtbl = NULL;
packed = (type->ty == Tstruct)
? type->alignsize() == 1
: false;
// above still need to be looked at
init = NULL;
constInit = NULL;
vtbl = NULL;
constVtbl = NULL;
classInfo = NULL;
constClassInfo = NULL;
classInfoDeclared = false;
classInfoDefined = false;
packed = false;
classInterfacesArray = NULL;
}
IrStruct::~IrStruct()
//////////////////////////////////////////////////////////////////////////////
LLGlobalVariable * IrStruct::getInitSymbol()
{
if (init)
return init;
// create the initZ symbol
std::string initname("_D");
initname.append(aggrdecl->mangle());
initname.append("6__initZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
init = new llvm::GlobalVariable(
type->irtype->getPA().get(), true, _linkage, NULL, initname, gIR->module);
return init;
}
//////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void IrStruct::pushAnon(bool isunion)
llvm::Constant * IrStruct::getDefaultInit()
{
anon = new Anon(isunion, anon);
}
if (constInit)
return constInit;
//////////////////////////////////////////
void IrStruct::popAnon()
{
assert(anon);
const LLType* BT;
// get the anon type
if (anon->isunion)
if (type->ty == Tstruct)
{
// get biggest type in block
const LLType* biggest = getBiggestType(&anon->types[0], anon->types.size());
std::vector<const LLType*> vec(1, biggest);
BT = LLStructType::get(vec, aggrdecl->ir.irStruct->packed);
constInit = createStructDefaultInitializer();
}
else
{
// build a struct from the types
BT = LLStructType::get(anon->types, aggrdecl->ir.irStruct->packed);
constInit = createClassDefaultInitializer();
}
// pop anon
Anon* tmp = anon;
anon = anon->parent;
delete tmp;
return constInit;
}
// is there a parent anon?
if (anon)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// helper function that returns the static default initializer of a variable
LLConstant* get_default_initializer(VarDeclaration* vd, Initializer* init)
{
if (init)
{
// make sure type gets pushed in the anon, not the main
anon->types.push_back(BT);
// index is only manipulated at the top level, anons use raw offsets
return DtoConstInitializer(init->loc, vd->type, init);
}
else if (vd->init)
{
return DtoConstInitializer(vd->init->loc, vd->type, vd->init);
}
// no parent anon, finally add to aggrdecl
else
{
types.push_back(BT);
// only advance to next position if main is not a union
if (!aggrdecl->isUnionDeclaration())
return DtoConstExpInit(vd->loc, vd->type, vd->type->defaultInit(vd->loc));
}
}
// helper function that adds zero bytes to a vector of constants
size_t add_zeros(std::vector<llvm::Constant*>& constants, size_t diff)
{
size_t n = constants.size();
while (diff)
{
if (global.params.is64bit && diff % 8 == 0)
{
index++;
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int64Ty));
diff -= 8;
}
else if (diff % 4 == 0)
{
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int32Ty));
diff -= 4;
}
else if (diff % 2 == 0)
{
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int16Ty));
diff -= 2;
}
else
{
constants.push_back(llvm::Constant::getNullValue(llvm::Type::Int8Ty));
diff -= 1;
}
}
return constants.size() - n;
}
//////////////////////////////////////////
// Matches the way the type is built in IrTypeStruct
// maybe look at unifying the interface.
void IrStruct::addVar(VarDeclaration * var)
LLConstant * IrStruct::createStructDefaultInitializer()
{
TypeVector* tvec = &types;
if (anon)
IF_LOG Logger::println("Building default initializer for %s", aggrdecl->toPrettyChars());
LOG_SCOPE;
assert(type->ty == Tstruct && "cannot build struct default initializer for non struct type");
// start at offset zero
size_t offset = 0;
// vector of constants
std::vector<llvm::Constant*> constants;
// go through fields
ArrayIter<VarDeclaration> it(aggrdecl->fields);
for (; !it.done(); it.next())
{
// make sure type gets pushed in the anon, not the main
tvec = &anon->types;
VarDeclaration* vd = it.get();
// set but don't advance index
var->ir.irField->index = index;
// set offset in bytes from start of anon block
var->ir.irField->unionOffset = var->offset - var->offset2;
}
else if (aggrdecl->isUnionDeclaration())
{
// set but don't advance index
var->ir.irField->index = index;
}
else
{
// set and advance index
var->ir.irField->index = index++;
}
// add type
tvec->push_back(DtoType(var->type));
// add var
varDecls.push_back(var);
}
//////////////////////////////////////////
const LLType* IrStruct::build()
{
// if types is empty, add a byte
if (types.empty())
{
types.push_back(LLType::Int8Ty);
}
// union type
if (aggrdecl->isUnionDeclaration())
{
const LLType* biggest = getBiggestType(&types[0], types.size());
std::vector<const LLType*> vec(1, biggest);
return LLStructType::get(vec, aggrdecl->ir.irStruct->packed);
}
// struct/class type
else
{
return LLStructType::get(types, aggrdecl->ir.irStruct->packed);
}
}
void addZeros(std::vector<const llvm::Type*>& inits, size_t pos, size_t offset)
{
assert(offset > pos);
size_t diff = offset - pos;
size_t sz;
do
{
if (pos%8 == 0 && diff >= 8)
sz = 8;
else if (pos%4 == 0 && diff >= 4)
sz = 4;
else if (pos%2 == 0 && diff >= 2)
sz = 2;
else // if (pos % 1 == 0)
sz = 1;
inits.push_back(LLIntegerType::get(sz*8));
pos += sz;
diff -= sz;
} while (pos < offset);
assert(pos == offset);
}
void addZeros(std::vector<llvm::Constant*>& inits, size_t pos, size_t offset)
{
assert(offset > pos);
size_t diff = offset - pos;
size_t sz;
do
{
if (pos%8 == 0 && diff >= 8)
sz = 8;
else if (pos%4 == 0 && diff >= 4)
sz = 4;
else if (pos%2 == 0 && diff >= 2)
sz = 2;
else // if (pos % 1 == 0)
sz = 1;
inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8)));
pos += sz;
diff -= sz;
} while (pos < offset);
assert(pos == offset);
}
// FIXME: body is exact copy of above
void addZeros(std::vector<llvm::Value*>& inits, size_t pos, size_t offset)
{
assert(offset > pos);
size_t diff = offset - pos;
size_t sz;
do
{
if (pos%8 == 0 && diff >= 8)
sz = 8;
else if (pos%4 == 0 && diff >= 4)
sz = 4;
else if (pos%2 == 0 && diff >= 2)
sz = 2;
else // if (pos % 1 == 0)
sz = 1;
inits.push_back(LLConstant::getNullValue(LLIntegerType::get(sz*8)));
pos += sz;
diff -= sz;
} while (pos < offset);
assert(pos == offset);
}
void IrStruct::buildDefaultConstInit(std::vector<llvm::Constant*>& inits)
{
assert(!defaultFound);
defaultFound = true;
const llvm::StructType* structtype = isaStruct(aggrdecl->type->ir.type->get());
Logger::cout() << "struct type: " << *structtype << '\n';
size_t lastoffset = 0;
size_t lastsize = 0;
{
Logger::println("Find the default fields");
LOG_SCOPE;
// go through all vars and find the ones that contribute to the default
size_t nvars = varDecls.size();
for (size_t i=0; i<nvars; i++)
if (vd->offset < offset)
{
VarDeclaration* var = varDecls[i];
IF_LOG Logger::println("skipping field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
continue;
}
Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset);
IF_LOG Logger::println("using field: %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
// only add vars that don't overlap
size_t offset = var->offset;
size_t size = var->type->size();
if (offset >= lastoffset+lastsize)
// get next aligned offset for this field
size_t alignedoffset = offset;
if (!packed)
{
size_t alignsize = vd->type->alignsize();
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
}
// insert explicit padding?
if (alignedoffset < vd->offset)
{
add_zeros(constants, vd->offset - alignedoffset);
}
// add initializer
constants.push_back(get_default_initializer(vd, NULL));
// advance offset to right past this field
offset = vd->offset + vd->type->size();
}
// tail padding?
if (offset < aggrdecl->structsize)
{
add_zeros(constants, aggrdecl->structsize - offset);
}
// build constant struct
llvm::Constant* definit = llvm::ConstantStruct::get(constants, packed);
IF_LOG Logger::cout() << "final default initializer: " << *definit << std::endl;
// sanity check
if (definit->getType() != type->irtype->get())
{
assert(0 && "default initializer type does not match the default struct type");
}
return definit;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// yet another rewrite of the notorious StructInitializer.
// this time a bit more inspired by the DMD code.
LLConstant * IrStruct::createStructInitializer(StructInitializer * si)
{
IF_LOG Logger::println("Building StructInitializer of type %s", si->ad->toPrettyChars());
LOG_SCOPE;
// sanity check
assert(si->ad == aggrdecl && "struct type mismatch");
assert(si->vars.dim == si->value.dim && "inconsistent StructInitializer");
// array of things to build
typedef std::pair<VarDeclaration*, llvm::Constant*> VCPair;
llvm::SmallVector<VCPair, 16> data(aggrdecl->fields.dim);
// start by creating a map from initializer indices to field indices.
// I have no fucking clue why dmd represents it like this :/
size_t n = si->vars.dim;
LLSmallVector<int, 16> datamap(n, 0);
for (size_t i = 0; i < n; i++)
{
for (size_t j = 0; 1; j++)
{
assert(j < aggrdecl->fields.dim);
if (aggrdecl->fields.data[j] == si->vars.data[i])
{
Logger::println(" added");
lastoffset = offset;
lastsize = size;
defVars.push_back(var);
datamap[i] = j;
break;
}
}
}
// fill in explicit initializers
n = si->vars.dim;
for (size_t i = 0; i < n; i++)
{
Logger::println("Build the default initializer");
LOG_SCOPE;
VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
Initializer* ini = (Initializer*)si->value.data[i];
lastoffset = 0;
lastsize = 0;
size_t idx = datamap[i];
// go through the default vars and build the default constant initializer
// adding zeros along the way to live up to alignment expectations
size_t nvars = defVars.size();
for (size_t i=0; i<nvars; i++)
if (data[idx].first != NULL)
{
VarDeclaration* var = defVars[i];
Loc l = ini ? ini->loc : si->loc;
error(l, "duplicate initialization of %s", vd->toChars());
continue;
}
Logger::println("field %s %s = %s : +%u", var->type->toChars(), var->toChars(), var->init ? var->init->toChars() : var->type->defaultInit(var->loc)->toChars(), var->offset);
data[idx].first = vd;
data[idx].second = get_default_initializer(vd, ini);
}
// get offset and size
size_t offset = var->offset;
size_t size = var->type->size();
// build array of constants and try to fill in default initializers
// where there is room.
size_t offset = 0;
std::vector<llvm::Constant*> constants;
constants.reserve(16);
// is there space in between last last offset and this one?
// if so, fill it with zeros
if (offset > lastoffset+lastsize)
n = data.size();
for (size_t i = 0; i < n; i++)
{
VarDeclaration* vd = data[i].first;
// explicitly initialized?
if (vd != NULL)
{
// get next aligned offset for this field
size_t alignedoffset = offset;
if (!packed)
{
size_t pos = lastoffset + lastsize;
addZeros(inits, pos, offset);
size_t alignsize = vd->type->alignsize();
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
}
// add the field
// lazily default initialize
if (!var->ir.irField->constInit)
var->ir.irField->constInit = DtoConstInitializer(var->loc, var->type, var->init);
inits.push_back(var->ir.irField->constInit);
// insert explicit padding?
if (alignedoffset < vd->offset)
{
add_zeros(constants, vd->offset - alignedoffset);
}
lastoffset = offset;
lastsize = var->type->size();
IF_LOG Logger::println("using field: %s", vd->toChars());
constants.push_back(data[i].second);
offset = vd->offset + vd->type->size();
}
// there might still be padding after the last one, make sure that is zeroed as well
// is there space in between last last offset and this one?
size_t structsize = getTypePaddedSize(structtype);
if (structsize > lastoffset+lastsize)
// not explicit! try and fit in the default initialization instead
// make sure we don't overlap with any following explicity initialized fields
else
{
size_t pos = lastoffset + lastsize;
addZeros(inits, pos, structsize);
vd = (VarDeclaration*)aggrdecl->fields.data[i];
// check all the way that we don't overlap, slow but it works!
for (size_t j = i+1; j <= n; j++)
{
if (j == n) // no overlap
{
IF_LOG Logger::println("using field default: %s", vd->toChars());
constants.push_back(get_default_initializer(vd, NULL));
offset = vd->offset + vd->type->size();
break;
}
VarDeclaration* vd2 = (VarDeclaration*)aggrdecl->fields.data[j];
size_t o2 = vd->offset + vd->type->size();
if (vd2->offset < o2 && data[i].first)
break; // overlaps
}
}
}
}
LLConstant* IrStruct::buildDefaultConstInit()
{
// doesn't work for classes, they add stuff before and maybe after data fields
assert(!aggrdecl->isClassDeclaration());
// tail padding?
if (offset < aggrdecl->structsize)
{
add_zeros(constants, aggrdecl->structsize - offset);
}
// initializer llvm constant list
std::vector<LLConstant*> inits;
// stop if there were errors
if (global.errors)
{
fatal();
}
// just start with an empty list
buildDefaultConstInit(inits);
// build the constant
// note that the type matches the initializer, not the aggregate in cases with unions
LLConstant* c = LLConstantStruct::get(inits, aggrdecl->ir.irStruct->packed);
Logger::cout() << "llvm constant: " << *c << '\n';
// assert(0);
// build constant
assert(!constants.empty());
llvm::Constant* c = llvm::ConstantStruct::get(&constants[0], constants.size(), packed);
IF_LOG Logger::cout() << "final struct initializer: " << *c << std::endl;
return c;
}

View File

@@ -6,178 +6,121 @@
#include <vector>
#include <map>
struct IrInterface;
// DMD forward declarations
struct StructInitializer;
void addZeros(std::vector<const llvm::Type*>& inits, size_t pos, size_t offset);
void addZeros(std::vector<llvm::Constant*>& inits, size_t pos, size_t offset);
void addZeros(std::vector<llvm::Value*>& inits, size_t pos, size_t offset);
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// represents a struct or class
// it is used during codegen to hold all the vital info we need
struct IrStruct : IrBase
{
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
typedef std::vector<VarDeclaration*> VarDeclVector;
typedef std::map<ClassDeclaration*, IrInterface*> InterfaceMap;
typedef InterfaceMap::iterator InterfaceMapIter;
typedef std::vector<IrInterface*> InterfaceVector;
typedef InterfaceVector::iterator InterfaceVectorIter;
// vector of LLVM types
typedef std::vector<const llvm::Type*> TypeVector;
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Anon represents an anonymous struct union block inside an aggregate
// during LLVM type construction.
struct Anon
{
bool isunion;
Anon* parent;
TypeVector types;
Anon(bool IsUnion, Anon* par) : isunion(IsUnion), parent(par) {}
};
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/// ctor
/// Constructor.
IrStruct(AggregateDeclaration* agg);
/// dtor
virtual ~IrStruct();
//////////////////////////////////////////////////////////////////////////
// public fields,
// FIXME this is basically stuff I just haven't gotten around to yet.
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/// push an anonymous struct/union
void pushAnon(bool isunion);
/// pops an anonymous struct/union
void popAnon();
/// adds field
void addVar(VarDeclaration* var);
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/// build the aggr type
const LLType* build();
/// put the aggr initializers in a vector
void buildDefaultConstInit(std::vector<llvm::Constant*>& inits);
/// ditto - but also builds the constant struct, for convenience
LLConstant* buildDefaultConstInit();
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// the D aggregate
/// The D aggregate.
AggregateDeclaration* aggrdecl;
// vector of VarDeclarations in this aggregate
VarDeclVector varDecls;
// vector of VarDeclarations that contribute to the default initializer
VarDeclVector defVars;
// true if the default initializer has been built
bool defaultFound;
// top element
Anon* anon;
// toplevel types in this aggr
TypeVector types;
// current index
// always the same as types.size()
size_t index;
// aggregate D type
/// Aggregate D type.
Type* type;
// class vtable type
llvm::PATypeHolder vtblTy;
llvm::PATypeHolder vtblInitTy;
// initializer type opaque (type of global matches initializer, not formal type)
llvm::PATypeHolder initOpaque;
llvm::PATypeHolder classInfoOpaque;
// map/vector of interfaces implemented
InterfaceMap interfaceMap;
InterfaceVector interfaceVec;
// interface info array global
LLGlobalVariable* interfaceInfos;
// ...
bool defined;
bool constinited;
// vtbl global and initializer
LLGlobalVariable* vtbl;
LLConstant* constVtbl;
// static initializers global and constant
LLGlobalVariable* init;
LLConstant* constInit;
// classinfo global and initializer constant
LLGlobalVariable* classInfo;
LLConstant* constClassInfo;
bool classInfoDeclared;
bool classInfoDefined;
// vector of interfaces that should be put in ClassInfo.interfaces
InterfaceVector classInfoInterfaces;
// align(1) struct S { ... }
/// true only for: align(1) struct S { ... }
bool packed;
// composite type debug description
/// Composite type debug description.
llvm::DICompositeType diCompositeType;
std::vector<VarDeclaration*> staticVars;
std::vector<FuncDeclaration*> structFuncs;
//////////////////////////////////////////////////////////////////////////
/// Create the __initZ symbol lazily.
LLGlobalVariable* getInitSymbol();
/// Builds the __initZ initializer constant lazily.
LLConstant* getDefaultInit();
/// Create the __vtblZ symbol lazily.
LLGlobalVariable* getVtblSymbol();
/// Builds the __vtblZ initializer constant lazily.
LLConstant* getVtblInit();
/// Create the __ClassZ symbol lazily.
LLGlobalVariable* getClassInfoSymbol();
/// Builds the __ClassZ initializer constant lazily.
LLConstant* getClassInfoInit();
/// Create the __interfaceInfos symbol lazily.
LLGlobalVariable* getInterfaceArraySymbol();
/// Creates a StructInitializer constant.
LLConstant* createStructInitializer(StructInitializer* si);
//////////////////////////////////////////////////////////////////////////
protected:
/// Static default initializer global.
llvm::GlobalVariable* init;
/// Static default initializer constant.
LLConstant* constInit;
/// Vtbl global.
llvm::GlobalVariable* vtbl;
/// Vtbl initializer constant.
LLConstant* constVtbl;
/// ClassInfo global.
llvm::GlobalVariable* classInfo;
/// ClassInfo initializer constant.
LLConstant* constClassInfo;
/// Map for mapping ClassDeclaration* to LLVM GlobalVariable.
typedef std::map<ClassDeclaration*, llvm::GlobalVariable*> ClassGlobalMap;
/// Map from of interface vtbls implemented by this class.
ClassGlobalMap interfaceVtblMap;
/// Interface info array global.
/// Basically: static object.Interface[num_interfaces]
llvm::GlobalVariable* classInterfacesArray;
/// std::vector of BaseClass*
typedef std::vector<BaseClass*> BaseClassVector;
/// Array of all interface vtbl implementations - in order - implemented
/// by this class.
/// Corresponds to the Interface instances needed to be output.
BaseClassVector interfacesWithVtbls;
//////////////////////////////////////////////////////////////////////////
/// Create static default initializer for struct.
LLConstant* createStructDefaultInitializer();
/// Create static default initializer for class.
LLConstant* createClassDefaultInitializer();
/// Returns vtbl for interface implementation, creates it if not already built.
llvm::GlobalVariable* getInterfaceVtbl(
BaseClass* b,
bool new_inst,
size_t interfaces_index);
/// Add base class data to initializer list.
/// Also creates the IrField instance for each data field.
void addBaseClassInits(
std::vector<llvm::Constant*>& constants,
ClassDeclaration* base,
size_t& offset,
size_t& field_index);
// FIXME make this a member instead
friend LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
/// Create the Interface[] interfaces ClassInfo field initializer.
LLConstant* getClassInfoInterfaces();
};
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// represents interface implemented by a class
struct IrInterface : IrBase
{
BaseClass* base;
ClassDeclaration* decl;
llvm::PATypeHolder vtblInitTy;
LLConstant* vtblInit;
LLGlobalVariable* vtbl;
Array vtblDecls; // array of FuncDecls that make up the vtbl
const LLStructType* infoTy;
LLConstant* infoInit;
LLConstant* info;
size_t index;
IrInterface(BaseClass* b);
};
#endif

View File

@@ -1,8 +1,16 @@
#include "llvm/DerivedTypes.h"
#include "ir/irtype.h"
#include "mars.h"
#include "mtype.h"
#include "gen/irstate.h"
#include "gen/logger.h"
#include "ir/irtype.h"
//////////////////////////////////////////////////////////////////////////////
extern const llvm::Type* DtoType(Type* dt);
extern const llvm::Type* DtoSize_t();
//////////////////////////////////////////////////////////////////////////////
IrType::IrType(Type* dt, const llvm::Type* lt)
: dtype(dt),
@@ -10,6 +18,8 @@ IrType::IrType(Type* dt, const llvm::Type* lt)
{
assert(dt && "null D Type");
assert(lt && "null LLVM Type");
assert(dt->ir.type == NULL && "llvm type (old one) already set");
dt->ir.type = &pa;
}
//////////////////////////////////////////////////////////////////////////////
@@ -23,6 +33,13 @@ IrTypeBasic::IrTypeBasic(Type * dt)
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypeBasic::buildType()
{
return pa.get();
}
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
{
const llvm::Type* t2;
@@ -101,19 +118,26 @@ const llvm::Type * IrTypeBasic::basic2llvm(Type* t)
//////////////////////////////////////////////////////////////////////////////
IrTypePointer::IrTypePointer(Type * dt)
: IrType(dt, pointer2llvm(dt))
: IrType(dt, llvm::OpaqueType::get())
{
}
//////////////////////////////////////////////////////////////////////////////
extern const llvm::Type* DtoType(Type* dt);
const llvm::Type * IrTypePointer::pointer2llvm(Type * t)
const llvm::Type * IrTypePointer::buildType()
{
assert(t->ty == Tpointer && "not pointer type");
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
pointer2llvm(dtype));
return pa.get();
}
const llvm::Type* elemType = DtoType(t->nextOf());
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypePointer::pointer2llvm(Type * dt)
{
assert(dt->ty == Tpointer && "not pointer type");
const llvm::Type* elemType = DtoType(dt->nextOf());
if (elemType == llvm::Type::VoidTy)
elemType = llvm::Type::Int8Ty;
return llvm::PointerType::get(elemType, 0);
@@ -124,21 +148,26 @@ const llvm::Type * IrTypePointer::pointer2llvm(Type * t)
//////////////////////////////////////////////////////////////////////////////
IrTypeSArray::IrTypeSArray(Type * dt)
: IrType(dt, sarray2llvm(dt))
: IrType(dt, llvm::OpaqueType::get())
{
assert(dt->ty == Tsarray && "not static array type");
TypeSArray* tsa = (TypeSArray*)dt;
uint64_t d = (uint64_t)tsa->dim->toUInteger();
assert(d == dim);
dim = (uint64_t)tsa->dim->toUInteger();
}
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypeSArray::buildType()
{
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
sarray2llvm(dtype));
return pa.get();
}
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypeSArray::sarray2llvm(Type * t)
{
assert(t->ty == Tsarray && "not static array type");
TypeSArray* tsa = (TypeSArray*)t;
dim = (uint64_t)tsa->dim->toUInteger();
const llvm::Type* elemType = DtoType(t->nextOf());
if (elemType == llvm::Type::VoidTy)
elemType = llvm::Type::Int8Ty;
@@ -150,23 +179,38 @@ const llvm::Type * IrTypeSArray::sarray2llvm(Type * t)
//////////////////////////////////////////////////////////////////////////////
IrTypeArray::IrTypeArray(Type * dt)
: IrType(dt, array2llvm(dt))
: IrType(dt, llvm::OpaqueType::get())
{
}
//////////////////////////////////////////////////////////////////////////////
extern const llvm::Type* DtoSize_t();
const llvm::Type * IrTypeArray::buildType()
{
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(
array2llvm(dtype));
return pa.get();
}
//////////////////////////////////////////////////////////////////////////////
const llvm::Type * IrTypeArray::array2llvm(Type * t)
{
assert(t->ty == Tarray && "not dynamic array type");
// get .ptr type
const llvm::Type* elemType = DtoType(t->nextOf());
if (elemType == llvm::Type::VoidTy)
elemType = llvm::Type::Int8Ty;
elemType = llvm::PointerType::get(elemType, 0);
return llvm::StructType::get(DtoSize_t(), elemType, NULL);
// create struct type
const llvm::Type* at = llvm::StructType::get(DtoSize_t(), elemType, NULL);
// name dynamic array types
Type::sir->getState()->module->addTypeName(t->toChars(), at);
return at;
}
//////////////////////////////////////////////////////////////////////////////

View File

@@ -9,10 +9,13 @@
struct Type;
class IrTypeAggr;
class IrTypeArray;
class IrTypeBasic;
class IrTypeClass;
class IrTypePointer;
class IrTypeSArray;
class IrTypeStruct;
//////////////////////////////////////////////////////////////////////////////
@@ -24,19 +27,29 @@ public:
IrType(Type* dt, const llvm::Type* lt);
///
Type* getD() { return dtype; }
///
const llvm::Type* get() { return pa.get(); }
virtual IrTypeAggr* isAggr() { return NULL; }
///
virtual IrTypeArray* isArray() { return NULL; }
///
virtual IrTypeBasic* isBasic() { return NULL; }
///
virtual IrTypeClass* isClass() { return NULL; }
///
virtual IrTypePointer* isPointer() { return NULL; }
///
virtual IrTypeSArray* isSArray() { return NULL; }
///
virtual IrTypeStruct* isStruct() { return NULL; }
///
Type* getD() { return dtype; }
///
virtual const llvm::Type* get() { return pa.get(); }
///
llvm::PATypeHolder& getPA() { return pa; }
///
virtual const llvm::Type* buildType() = 0;
protected:
///
@@ -58,6 +71,9 @@ public:
///
IrTypeBasic* isBasic() { return this; }
///
const llvm::Type* buildType();
protected:
///
const llvm::Type* basic2llvm(Type* t);
@@ -75,6 +91,9 @@ public:
///
IrTypePointer* isPointer() { return this; }
///
const llvm::Type* buildType();
protected:
///
const llvm::Type* pointer2llvm(Type* t);
@@ -92,6 +111,9 @@ public:
///
IrTypeSArray* isSArray() { return this; }
///
const llvm::Type* buildType();
protected:
///
const llvm::Type* sarray2llvm(Type* t);
@@ -112,6 +134,9 @@ public:
///
IrTypeArray* isArray() { return this; }
///
const llvm::Type* buildType();
protected:
///
const llvm::Type* array2llvm(Type* t);

254
ir/irtypeclass.cpp Normal file
View File

@@ -0,0 +1,254 @@
#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
// FIXME: and all it's baseinterfaces
if (interfaceMap.find(b->base) == interfaceMap.end())
interfaceMap.insert(std::make_pair(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));
// 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())
{
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;
}
//////////////////////////////////////////////////////////////////////////////

73
ir/irtypeclass.h Normal file
View File

@@ -0,0 +1,73 @@
#ifndef __LDC_IR_IRTYPECLASS_H__
#define __LDC_IR_IRTYPECLASS_H__
#include "ir/irtypestruct.h"
///
class IrTypeClass : public IrTypeAggr
{
public:
///
IrTypeClass(ClassDeclaration* cd);
///
virtual IrTypeClass* isClass() { return this; }
///
const llvm::Type* buildType();
///
const llvm::Type* get();
/// Returns the vtable type for this class.
const llvm::Type* getVtbl() { return vtbl_pa.get(); }
/// Get index to interface implementation.
/// Returns the index of a specific interface implementation in this
/// class or ~0 if not found.
size_t getInterfaceIndex(ClassDeclaration* inter);
/// Returns the total number of pointers in the vtable.
unsigned getVtblSize() { return vtbl_size; }
/// Returns the number of interface implementations (vtables) in this
/// class.
unsigned getNumInterfaceVtbls() { return num_interface_vtbls; }
protected:
///
ClassDeclaration* cd;
///
TypeClass* tc;
/// Type holder for the vtable type.
llvm::PATypeHolder vtbl_pa;
/// Number of pointers in vtable.
unsigned vtbl_size;
/// Number of interface implementations (vtables) in this class.
unsigned num_interface_vtbls;
/// std::map type mapping ClassDeclaration* to size_t.
typedef std::map<ClassDeclaration*, size_t> ClassIndexMap;
/// Map for mapping the index of a specific interface implementation
/// in this class to its ClassDeclaration.
ClassIndexMap interfaceMap;
//////////////////////////////////////////////////////////////////////////
/// Builds a vtable type given the type of the first entry and an array
/// of all entries.
const llvm::Type* buildVtblType(Type* first, Array* vtbl_array);
///
void addBaseClassData(
std::vector<const llvm::Type*>& defaultTypes,
ClassDeclaration* base,
size_t& offset,
size_t& field_index);
};
#endif

148
ir/irtypestruct.cpp Normal file
View File

@@ -0,0 +1,148 @@
#include "llvm/DerivedTypes.h"
#include "aggregate.h"
#include "declaration.h"
#include "mtype.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "gen/logger.h"
#include "gen/utils.h"
#include "ir/irtypestruct.h"
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeAggr::IrTypeAggr(AggregateDeclaration * ad)
: IrType(ad->type, llvm::OpaqueType::get()),
aggr(ad)
{
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrTypeStruct::IrTypeStruct(StructDeclaration * sd)
: IrTypeAggr(sd),
sd(sd),
ts((TypeStruct*)sd->type)
{
}
//////////////////////////////////////////////////////////////////////////////
size_t add_zeros(std::vector<const llvm::Type*>& defaultTypes, size_t diff)
{
size_t n = defaultTypes.size();
while (diff)
{
if (global.params.is64bit && diff % 8 == 0)
{
defaultTypes.push_back(llvm::Type::Int64Ty);
diff -= 8;
}
else if (diff % 4 == 0)
{
defaultTypes.push_back(llvm::Type::Int32Ty);
diff -= 4;
}
else if (diff % 2 == 0)
{
defaultTypes.push_back(llvm::Type::Int16Ty);
diff -= 2;
}
else
{
defaultTypes.push_back(llvm::Type::Int8Ty);
diff -= 1;
}
}
return defaultTypes.size() - n;
}
const llvm::Type* IrTypeStruct::buildType()
{
IF_LOG Logger::println("Building struct type %s @ %s", sd->toPrettyChars(), sd->locToChars());
LOG_SCOPE;
// find the fields that contribute to the default initializer.
// these will define the default type.
std::vector<const llvm::Type*> defaultTypes;
defaultTypes.reserve(16);
size_t offset = 0;
size_t field_index = 0;
bool packed = (sd->type->alignsize() == 1);
ArrayIter<VarDeclaration> it(sd->fields);
for (; !it.done(); it.next())
{
VarDeclaration* vd = it.get();
assert(vd->ir.irField == NULL && "struct inheritance is not allowed, how can this happen?");
// 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);
new IrField(vd, 0, vd->offset);
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 alignedoffset = offset;
if (!packed)
{
size_t alignsize = vd->type->alignsize();
alignedoffset = (offset + alignsize - 1) & ~(alignsize - 1);
}
// insert explicit padding?
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);
new IrField(vd, field_index);
field_index++;
}
// tail padding?
if (offset < sd->structsize)
{
add_zeros(defaultTypes, sd->structsize - offset);
}
// build the llvm type
const llvm::Type* st = llvm::StructType::get(defaultTypes, packed);
// refine type
llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(st);
// name types
Type::sir->getState()->module->addTypeName(sd->toPrettyChars(), pa.get());
#if 1
IF_LOG Logger::cout() << "final struct type: " << *pa.get() << std::endl;
#endif
return pa.get();
}
//////////////////////////////////////////////////////////////////////////////

52
ir/irtypestruct.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef __LDC_IR_IRTYPESTRUCT_H__
#define __LDC_IR_IRTYPESTRUCT_H__
#include "ir/irtype.h"
//////////////////////////////////////////////////////////////////////////////
struct AggregateDeclaration;
struct StructDeclaration;
struct TypeStruct;
//////////////////////////////////////////////////////////////////////////////
class IrTypeAggr : public IrType
{
public:
///
IrTypeAggr(AggregateDeclaration* ad);
///
IrTypeAggr* isAggr() { return this; }
protected:
/// AggregateDeclaration this type represents.
AggregateDeclaration* aggr;
};
//////////////////////////////////////////////////////////////////////////////
class IrTypeStruct : public IrTypeAggr
{
public:
///
IrTypeStruct(StructDeclaration* sd);
///
IrTypeStruct* isStruct() { return this; }
///
const llvm::Type* buildType();
protected:
/// StructDeclaration this type represents.
StructDeclaration* sd;
/// DMD TypeStruct of this type.
TypeStruct* ts;
};
//////////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -36,11 +36,26 @@ IrLocal::IrLocal(VarDeclaration* v) : IrVar(v)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
IrField::IrField(VarDeclaration* v) : IrVar(v)
IrField::IrField(VarDeclaration* v, size_t idx, size_t offset) : IrVar(v)
{
index = 0;
unionOffset = 0;
index = idx;
unionOffset = offset;
constInit = NULL;
assert(V->ir.irField == NULL && "field for this variable already exists");
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;
}
//////////////////////////////////////////////////////////////////////////////

View File

@@ -34,11 +34,15 @@ struct IrLocal : IrVar
// represents an aggregate field variable
struct IrField : IrVar
{
IrField(VarDeclaration* v);
IrField(VarDeclaration* v, size_t idx, size_t offset = 0);
unsigned index;
unsigned unionOffset;
llvm::Constant* getDefaultInit();
protected:
/// FIXME: only used for StructLiteralsExps
llvm::Constant* constInit;
};