mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-27 13:40:33 +03:00
171 lines
5.1 KiB
C++
171 lines
5.1 KiB
C++
//===-- 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 "dmd/aggregate.h"
|
||
#include "dmd/mangle.h"
|
||
#include "dmd/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"
|
||
|
||
using namespace dmd;
|
||
|
||
RTTIBuilder::RTTIBuilder(Type *baseType) {
|
||
const auto ad = isAggregate(baseType);
|
||
assert(ad && "not an aggregate type");
|
||
|
||
DtoResolveDsymbol(ad);
|
||
|
||
if (auto cd = ad->isClassDeclaration()) {
|
||
const auto baseir = getIrAggr(cd);
|
||
assert(baseir && "no IrAggr for TypeInfo base class");
|
||
|
||
// 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 = llvm::alignTo(
|
||
prevFieldEnd, gDataLayout->getABITypeAlign(C->getType()).value());
|
||
|
||
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(getNullPtr()); }
|
||
|
||
void RTTIBuilder::push_typeinfo(Type *t) { push(DtoTypeInfoOf(Loc(), t)); }
|
||
|
||
void RTTIBuilder::push_string(const char *str) { push(DtoConstString(str)); }
|
||
|
||
void RTTIBuilder::push_null_void_array() {
|
||
LLType *T = DtoType(arrayOf(Type::tvoid));
|
||
push(getNullValue(T));
|
||
}
|
||
|
||
void RTTIBuilder::push_void_array(uint64_t dim, llvm::Constant *ptr) {
|
||
push(DtoConstSlice(DtoConstSize_t(dim), ptr));
|
||
}
|
||
|
||
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, needsCOMDAT());
|
||
|
||
auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI,
|
||
initname.peekChars());
|
||
setLinkage(lwc, G);
|
||
G->setAlignment(llvm::MaybeAlign(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(arrayOf(valtype)->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, needsCOMDAT());
|
||
|
||
auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI,
|
||
initname.peekChars());
|
||
setLinkage(lwc, G);
|
||
G->setAlignment(llvm::MaybeAlign(DtoAlignment(valtype)));
|
||
|
||
push_array(dim, G);
|
||
}
|
||
|
||
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), getOpaquePtrType()));
|
||
}
|
||
|
||
void RTTIBuilder::push_funcptr(FuncDeclaration *fd) {
|
||
if (fd) {
|
||
LLConstant *F = DtoCallee(fd);
|
||
push(F);
|
||
} else {
|
||
push_null_vp();
|
||
}
|
||
}
|
||
|
||
void RTTIBuilder::finalize(LLGlobalVariable *gvar) {
|
||
LLStructType *st = isaStruct(gvar->getValueType());
|
||
assert(st);
|
||
|
||
// finalize the type if opaque (e.g., for ModuleInfos)
|
||
if (st->isOpaque()) {
|
||
std::vector<LLType *> fieldTypes;
|
||
fieldTypes.reserve(inits.size());
|
||
for (auto c : inits) {
|
||
fieldTypes.push_back(c->getType());
|
||
}
|
||
st->setBody(fieldTypes);
|
||
}
|
||
|
||
// create the initializer
|
||
LLConstant *tiInit = get_constant(st);
|
||
|
||
// set the initializer
|
||
gvar->setInitializer(tiInit);
|
||
}
|
||
|
||
LLConstant *RTTIBuilder::get_constant(LLStructType *initType) {
|
||
assert(initType->getNumElements() == inits.size());
|
||
|
||
std::vector<LLConstant *> castInits;
|
||
castInits.reserve(inits.size());
|
||
for (unsigned i = 0; i < inits.size(); ++i) {
|
||
castInits.push_back(DtoBitCast(inits[i], initType->getElementType(i)));
|
||
}
|
||
|
||
return LLConstantStruct::get(initType, castInits);
|
||
}
|