mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-07-22 15:15:22 +02:00
Merge.
This commit is contained in:
472
ir/irclass.cpp
Normal file
472
ir/irclass.cpp
Normal 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));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@@ -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
|
||||
|
||||
527
ir/irstruct.cpp
527
ir/irstruct.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
247
ir/irstruct.h
247
ir/irstruct.h
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
35
ir/irtype.h
35
ir/irtype.h
@@ -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
254
ir/irtypeclass.cpp
Normal 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
73
ir/irtypeclass.h
Normal 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
148
ir/irtypestruct.cpp
Normal 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
52
ir/irtypestruct.h
Normal 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
|
||||
21
ir/irvar.cpp
21
ir/irvar.cpp
@@ -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;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user