//===-- 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(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, true)); } 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) { std::string initname(mangle(mangle_sym)); initname.append(".rtti.voidarr.data"); const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()); auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI, initname); 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"); std::string initname(mangle_sym ? mangle(mangle_sym) : ".ldc"); initname.append(".rtti."); initname.append(tmpStr); initname.append(".data"); const LinkageWithCOMDAT lwc(TYPEINFO_LINKAGE_TYPE, supportsCOMDAT()); auto G = new LLGlobalVariable(gIR->module, CI->getType(), true, lwc.first, CI, initname); 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->type, tid->value); } void RTTIBuilder::finalize(LLType *type, LLValue *value) { llvm::ArrayRef inits = llvm::makeArrayRef(this->inits); LLStructType *st = isaStruct(type); assert(st); // set struct body if (st->isOpaque()) { const int n = inits.size(); std::vector 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(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); }