Permalink
Fetching contributors…
Cannot retrieve contributors at this time
186 lines (150 sloc) 5.45 KB
//===-- rttibuilder.cpp ---------------------------------------------------===//
//
// LDC – the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "gen/rttibuilder.h"
#include "aggregate.h"
#include "mtype.h"
#include "gen/arrays.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/linkage.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/tollvm.h"
#include "ir/iraggr.h"
#include "ir/irfunction.h"
RTTIBuilder::RTTIBuilder(AggregateDeclaration *base_class) {
DtoResolveDsymbol(base_class);
base = base_class;
basetype = static_cast<TypeClass *>(base->type);
baseir = getIrAggr(base);
assert(baseir && "no IrStruct for TypeInfo base class");
prevFieldEnd = 0;
if (base->isClassDeclaration()) {
// just start with adding the vtbl
push(baseir->getVtblSymbol());
// and monitor
push_null_vp();
}
}
void RTTIBuilder::push(llvm::Constant *C) {
// We need to explicitly zero any padding bytes as per TDPL §7.1.1 (and
// also match the struct type lowering code here).
const uint64_t fieldStart =
#if LDC_LLVM_VER >= 309
llvm::alignTo
#else
llvm::RoundUpToAlignment
#endif
(prevFieldEnd, gDataLayout->getABITypeAlignment(C->getType()));
const uint64_t paddingBytes = fieldStart - prevFieldEnd;
if (paddingBytes) {
llvm::Type *const padding = llvm::ArrayType::get(
llvm::Type::getInt8Ty(gIR->context()), paddingBytes);
inits.push_back(llvm::Constant::getNullValue(padding));
}
inits.push_back(C);
prevFieldEnd = fieldStart + gDataLayout->getTypeAllocSize(C->getType());
}
void RTTIBuilder::push_null(Type *T) { push(getNullValue(DtoType(T))); }
void RTTIBuilder::push_null_vp() { push(getNullValue(getVoidPtrType())); }
void RTTIBuilder::push_typeinfo(Type *t) { push(DtoTypeInfoOf(t)); }
void RTTIBuilder::push_classinfo(ClassDeclaration *cd) {
push(getIrAggr(cd)->getClassInfoSymbol());
}
void RTTIBuilder::push_string(const char *str) { push(DtoConstString(str)); }
void RTTIBuilder::push_null_void_array() {
LLType *T = DtoType(Type::tvoid->arrayOf());
push(getNullValue(T));
}
void RTTIBuilder::push_void_array(uint64_t dim, llvm::Constant *ptr) {
push(DtoConstSlice(DtoConstSize_t(dim), DtoBitCast(ptr, getVoidPtrType())));
}
void RTTIBuilder::push_void_array(llvm::Constant *CI, Type *valtype,
Dsymbol *mangle_sym) {
OutBuffer initname;
mangleToBuffer(mangle_sym, &initname);
initname.writestring(".rtti.voidarr.data");
const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT());
auto G = new LLGlobalVariable(gIR->module, CI->getType(), true,
lwc.first, CI, initname.peekString());
setLinkage(lwc, G);
G->setAlignment(DtoAlignment(valtype));
push_void_array(getTypeAllocSize(CI->getType()), G);
}
void RTTIBuilder::push_array(llvm::Constant *CI, uint64_t dim, Type *valtype,
Dsymbol *mangle_sym) {
std::string tmpStr(valtype->arrayOf()->toChars());
tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), '['), tmpStr.end());
tmpStr.erase(remove(tmpStr.begin(), tmpStr.end(), ']'), tmpStr.end());
tmpStr.append("arr");
OutBuffer initname;
if (mangle_sym)
mangleToBuffer(mangle_sym, &initname);
else
initname.writestring(".ldc");
initname.writestring(".rtti.");
initname.writestring(tmpStr.c_str());
initname.writestring(".data");
const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT());
auto G = new LLGlobalVariable(gIR->module, CI->getType(), true,
lwc.first, CI, initname.peekString());
setLinkage(lwc, G);
G->setAlignment(DtoAlignment(valtype));
push_array(dim, DtoBitCast(G, DtoType(valtype->pointerTo())));
}
void RTTIBuilder::push_array(uint64_t dim, llvm::Constant *ptr) {
push(DtoConstSlice(DtoConstSize_t(dim), ptr));
}
void RTTIBuilder::push_uint(unsigned u) { push(DtoConstUint(u)); }
void RTTIBuilder::push_size(uint64_t s) { push(DtoConstSize_t(s)); }
void RTTIBuilder::push_size_as_vp(uint64_t s) {
push(llvm::ConstantExpr::getIntToPtr(DtoConstSize_t(s), getVoidPtrType()));
}
void RTTIBuilder::push_funcptr(FuncDeclaration *fd, Type *castto) {
if (fd) {
DtoResolveFunction(fd);
LLConstant *F = DtoCallee(fd);
if (castto) {
F = DtoBitCast(F, DtoType(castto));
}
push(F);
} else if (castto) {
push_null(castto);
} else {
push_null_vp();
}
}
void RTTIBuilder::finalize(IrGlobal *tid) {
finalize(tid->getType(), tid->value);
}
void RTTIBuilder::finalize(LLType *type, LLValue *value) {
llvm::ArrayRef<LLConstant *> inits = llvm::makeArrayRef(this->inits);
LLStructType *st = isaStruct(type);
assert(st);
// set struct body
if (st->isOpaque()) {
const int n = inits.size();
std::vector<LLType *> types;
types.reserve(n);
for (int i = 0; i < n; ++i) {
types.push_back(inits[i]->getType());
}
st->setBody(types);
}
// create the inititalizer
LLConstant *tiInit = LLConstantStruct::get(st, inits);
// set the initializer
llvm::GlobalVariable *gvar = llvm::cast<llvm::GlobalVariable>(value);
gvar->setInitializer(tiInit);
setLinkage({TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()}, gvar);
}
LLConstant *RTTIBuilder::get_constant(LLStructType *initType) {
// just return the inititalizer
return LLConstantStruct::get(initType, inits);
}