mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 09:31:03 +03:00

Previously, the transitory state only needed and valid during generation of the LLVM IR for the function body was conflated with the general codegen metadata for the function declaration in IrFunction. There is further potential for cleanup regarding the use of gIR->func() and so on all over the code base, but this is out of scope of this commit, which is only concerned with those IrFunction members moved to FuncGenState. GitHub: Fixes #1661.
590 lines
19 KiB
C++
590 lines
19 KiB
C++
//===-- irclass.cpp -------------------------------------------------------===//
|
||
//
|
||
// LDC – the LLVM D compiler
|
||
//
|
||
// This file is distributed under the BSD-style LDC license. See the LICENSE
|
||
// file for details.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "llvm/IR/Constants.h"
|
||
#include "llvm/IR/DerivedTypes.h"
|
||
#include "llvm/ADT/SmallString.h"
|
||
#ifndef NDEBUG
|
||
#include "llvm/Support/raw_ostream.h"
|
||
#endif
|
||
|
||
#include "aggregate.h"
|
||
#include "declaration.h"
|
||
#include "hdrgen.h" // for parametersTypeToChars()
|
||
#include "mtype.h"
|
||
#include "target.h"
|
||
#include "gen/funcgenstate.h"
|
||
#include "gen/irstate.h"
|
||
#include "gen/logger.h"
|
||
#include "gen/tollvm.h"
|
||
#include "gen/llvmhelpers.h"
|
||
#include "gen/arrays.h"
|
||
#include "gen/metadata.h"
|
||
#include "gen/runtime.h"
|
||
#include "gen/functions.h"
|
||
#include "gen/abi.h"
|
||
#include "gen/mangling.h"
|
||
|
||
#include "ir/iraggr.h"
|
||
#include "ir/irfunction.h"
|
||
#include "ir/irtypeclass.h"
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
extern LLConstant *DtoDefineClassInfo(ClassDeclaration *cd);
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLGlobalVariable *IrAggr::getVtblSymbol() {
|
||
if (vtbl) {
|
||
return vtbl;
|
||
}
|
||
|
||
// create the vtblZ symbol
|
||
auto initname = getMangledVTableSymbolName(aggrdecl);
|
||
|
||
LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtbl();
|
||
|
||
vtbl =
|
||
getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true,
|
||
llvm::GlobalValue::ExternalLinkage, nullptr, initname);
|
||
|
||
return vtbl;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLGlobalVariable *IrAggr::getClassInfoSymbol() {
|
||
if (classInfo) {
|
||
return classInfo;
|
||
}
|
||
|
||
// create the ClassZ / InterfaceZ symbol
|
||
std::string initname = getMangledClassInfoSymbolName(aggrdecl);
|
||
|
||
// The type is also ClassInfo for interfaces – the actual TypeInfo for them
|
||
// is a TypeInfo_Interface instance that references __ClassZ in its "base"
|
||
// member.
|
||
ClassDeclaration *cinfo = Type::typeinfoclass;
|
||
DtoType(cinfo->type);
|
||
IrTypeClass *tc = stripModifiers(cinfo->type)->ctype->isClass();
|
||
assert(tc && "invalid ClassInfo type");
|
||
|
||
// classinfos cannot be constants since they're used as locks for synchronized
|
||
classInfo = getOrCreateGlobal(
|
||
aggrdecl->loc, gIR->module, tc->getMemoryLLType(), false,
|
||
llvm::GlobalValue::ExternalLinkage, nullptr, initname);
|
||
|
||
// Generate some metadata on this ClassInfo if it's for a class.
|
||
ClassDeclaration *classdecl = aggrdecl->isClassDeclaration();
|
||
if (classdecl && !aggrdecl->isInterfaceDeclaration()) {
|
||
// Gather information
|
||
LLType *type = DtoType(aggrdecl->type);
|
||
LLType *bodyType = llvm::cast<LLPointerType>(type)->getElementType();
|
||
bool hasDestructor = (classdecl->dtor != nullptr);
|
||
bool hasCustomDelete = (classdecl->aggDelete != nullptr);
|
||
// Construct the fields
|
||
#if LDC_LLVM_VER >= 306
|
||
llvm::Metadata *mdVals[CD_NumFields];
|
||
mdVals[CD_BodyType] =
|
||
llvm::ConstantAsMetadata::get(llvm::UndefValue::get(bodyType));
|
||
mdVals[CD_Finalize] = llvm::ConstantAsMetadata::get(
|
||
LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor));
|
||
mdVals[CD_CustomDelete] = llvm::ConstantAsMetadata::get(
|
||
LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete));
|
||
#else
|
||
MDNodeField *mdVals[CD_NumFields];
|
||
mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType);
|
||
mdVals[CD_Finalize] =
|
||
LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor);
|
||
mdVals[CD_CustomDelete] =
|
||
LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete);
|
||
#endif
|
||
// Construct the metadata and insert it into the module.
|
||
llvm::SmallString<64> name;
|
||
llvm::NamedMDNode *node = gIR->module.getOrInsertNamedMetadata(
|
||
llvm::Twine(CD_PREFIX, initname).toStringRef(name));
|
||
node->addOperand(llvm::MDNode::get(
|
||
gIR->context(), llvm::makeArrayRef(mdVals, CD_NumFields)));
|
||
}
|
||
|
||
return classInfo;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLGlobalVariable *IrAggr::getInterfaceArraySymbol() {
|
||
if (classInterfacesArray) {
|
||
return classInterfacesArray;
|
||
}
|
||
|
||
ClassDeclaration *cd = aggrdecl->isClassDeclaration();
|
||
|
||
size_t n = stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls();
|
||
assert(n > 0 && "getting ClassInfo.interfaces storage symbol, but we "
|
||
"don't implement any interfaces");
|
||
|
||
LLType *InterfaceTy = DtoType(Type::typeinfoclass->fields[3]->type->nextOf());
|
||
|
||
// create Interface[N]
|
||
LLArrayType *array_type = llvm::ArrayType::get(InterfaceTy, n);
|
||
|
||
// put it in a global
|
||
std::string name("_D");
|
||
name.append(mangle(cd));
|
||
name.append("16__interfaceInfosZ");
|
||
|
||
// We keep this as external for now and only consider template linkage if
|
||
// we emit the initializer later.
|
||
classInterfacesArray =
|
||
getOrCreateGlobal(cd->loc, gIR->module, array_type, true,
|
||
llvm::GlobalValue::ExternalLinkage, nullptr, name);
|
||
|
||
return classInterfacesArray;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLConstant *IrAggr::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;
|
||
if (!cd->isCPPclass()) {
|
||
c = getClassInfoSymbol();
|
||
c = DtoBitCast(c, DtoType(Type::typeinfoclass->type));
|
||
constants.push_back(c);
|
||
}
|
||
|
||
// add virtual function pointers
|
||
size_t n = cd->vtbl.dim;
|
||
for (size_t i = cd->vtblOffset(); i < n; i++) {
|
||
Dsymbol *dsym = static_cast<Dsymbol *>(cd->vtbl.data[i]);
|
||
assert(dsym && "null vtbl member");
|
||
|
||
FuncDeclaration *fd = dsym->isFuncDeclaration();
|
||
assert(fd && "vtbl entry not a function");
|
||
|
||
if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) {
|
||
c = getNullValue(getPtrToType(DtoFunctionType(fd)));
|
||
} else {
|
||
DtoResolveFunction(fd);
|
||
assert(isIrFuncCreated(fd) && "invalid vtbl function");
|
||
c = getIrFunc(fd)->func;
|
||
if (cd->isFuncHidden(fd)) {
|
||
// fd is hidden from the view of this class. If fd overlaps with any
|
||
// function in the vtbl[], issue error.
|
||
for (size_t j = 1; j < n; j++) {
|
||
if (j == i) {
|
||
continue;
|
||
}
|
||
auto fd2 =
|
||
static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration();
|
||
if (!fd2->ident->equals(fd->ident)) {
|
||
continue;
|
||
}
|
||
if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) {
|
||
TypeFunction *tf = static_cast<TypeFunction *>(fd->type);
|
||
if (tf->ty == Tfunction) {
|
||
cd->error("use of %s%s is hidden by %s; use 'alias %s = %s.%s;' "
|
||
"to introduce base class overload set",
|
||
fd->toPrettyChars(),
|
||
parametersTypeToChars(tf->parameters, tf->varargs),
|
||
cd->toChars(),
|
||
|
||
fd->toChars(), fd->parent->toChars(), fd->toChars());
|
||
} else {
|
||
cd->error("use of %s is hidden by %s", fd->toPrettyChars(),
|
||
cd->toChars());
|
||
}
|
||
fatal();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
constants.push_back(c);
|
||
}
|
||
|
||
// build the constant struct
|
||
LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtbl();
|
||
#ifndef NDEBUG
|
||
size_t nc = constants.size();
|
||
|
||
for (size_t i = 0; i < nc; ++i) {
|
||
if (constants[i]->getType() != vtblTy->getContainedType(i)) {
|
||
llvm::errs() << "type mismatch for entry # " << i
|
||
<< " in vtbl initializer\n";
|
||
|
||
constants[i]->getType()->dump();
|
||
vtblTy->getContainedType(i)->dump();
|
||
}
|
||
}
|
||
|
||
#endif
|
||
constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants);
|
||
|
||
assert(constVtbl->getType() ==
|
||
stripModifiers(type)->ctype->isClass()->getVtbl() &&
|
||
"vtbl initializer type mismatch");
|
||
|
||
return constVtbl;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLConstant *IrAggr::getClassInfoInit() {
|
||
if (constClassInfo) {
|
||
return constClassInfo;
|
||
}
|
||
constClassInfo = DtoDefineClassInfo(aggrdecl->isClassDeclaration());
|
||
return constClassInfo;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
||
size_t interfaces_index) {
|
||
auto it = interfaceVtblMap.find({b->sym, interfaces_index});
|
||
if (it != interfaceVtblMap.end()) {
|
||
return it->second;
|
||
}
|
||
|
||
IF_LOG Logger::println(
|
||
"Building vtbl for implementation of interface %s in class %s",
|
||
b->sym->toPrettyChars(), aggrdecl->toPrettyChars());
|
||
LOG_SCOPE;
|
||
|
||
ClassDeclaration *cd = aggrdecl->isClassDeclaration();
|
||
assert(cd && "not a class aggregate");
|
||
|
||
FuncDeclarations vtbl_array;
|
||
b->fillVtbl(cd, &vtbl_array, new_instance);
|
||
|
||
std::vector<llvm::Constant *> constants;
|
||
constants.reserve(vtbl_array.dim);
|
||
|
||
if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces
|
||
// index into the interfaces array
|
||
llvm::Constant *idxs[2] = {DtoConstSize_t(0),
|
||
DtoConstSize_t(interfaces_index)};
|
||
|
||
llvm::GlobalVariable *interfaceInfosZ = getInterfaceArraySymbol();
|
||
llvm::Constant *c = llvm::ConstantExpr::getGetElementPtr(
|
||
#if LDC_LLVM_VER >= 307
|
||
isaPointer(interfaceInfosZ)->getElementType(),
|
||
#endif
|
||
interfaceInfosZ, idxs, true);
|
||
|
||
constants.push_back(c);
|
||
}
|
||
|
||
// Thunk prefix
|
||
char thunkPrefix[16];
|
||
int thunkLen = sprintf(thunkPrefix, "Th%d", b->offset);
|
||
char thunkPrefixLen[16];
|
||
sprintf(thunkPrefixLen, "%d", thunkLen);
|
||
|
||
// add virtual function pointers
|
||
size_t n = vtbl_array.dim;
|
||
for (size_t i = b->sym->vtblOffset(); i < n; i++) {
|
||
Dsymbol *dsym = static_cast<Dsymbol *>(vtbl_array.data[i]);
|
||
if (dsym == nullptr) {
|
||
// 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");
|
||
|
||
DtoResolveFunction(fd);
|
||
assert(isIrFuncCreated(fd) && "invalid vtbl function");
|
||
|
||
IrFunction *irFunc = getIrFunc(fd);
|
||
|
||
assert(irFunc->irFty.arg_this);
|
||
|
||
int thunkOffset = b->offset;
|
||
if (fd->interfaceVirtual)
|
||
thunkOffset -= fd->interfaceVirtual->offset;
|
||
if (thunkOffset == 0) {
|
||
constants.push_back(irFunc->func);
|
||
continue;
|
||
}
|
||
|
||
// Create the thunk function if it does not already exist in this
|
||
// module.
|
||
OutBuffer nameBuf;
|
||
nameBuf.writestring(thunkPrefix);
|
||
nameBuf.writestring(mangleExact(fd));
|
||
const char *thunkName = nameBuf.extractString();
|
||
llvm::Function *thunk = gIR->module.getFunction(thunkName);
|
||
if (!thunk) {
|
||
const LinkageWithCOMDAT lwc(LLGlobalValue::LinkOnceODRLinkage,
|
||
supportsCOMDAT());
|
||
thunk = LLFunction::Create(
|
||
isaFunction(irFunc->func->getType()->getContainedType(0)), lwc.first,
|
||
thunkName, &gIR->module);
|
||
setLinkage(lwc, thunk);
|
||
thunk->copyAttributesFrom(irFunc->func);
|
||
|
||
// Thunks themselves don't have an identity, only the target
|
||
// function has.
|
||
#if LDC_LLVM_VER >= 309
|
||
thunk->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
|
||
#else
|
||
thunk->setUnnamedAddr(true);
|
||
#endif
|
||
|
||
#if LDC_LLVM_VER >= 307
|
||
// thunks don't need exception handling themselves
|
||
thunk->setPersonalityFn(nullptr);
|
||
#endif
|
||
|
||
// It is necessary to add debug information to the thunk in case it is
|
||
// subject to inlining. See https://llvm.org/bugs/show_bug.cgi?id=26833
|
||
IF_LOG Logger::println("Doing function body for thunk to: %s",
|
||
fd->toChars());
|
||
|
||
// Create a dummy FuncDeclaration with enough information to satisfy the
|
||
// DIBuilder
|
||
FuncDeclaration *thunkFd = reinterpret_cast<FuncDeclaration *>(
|
||
memcpy(new char[sizeof(FuncDeclaration)], (void *)fd,
|
||
sizeof(FuncDeclaration)));
|
||
thunkFd->ir = new IrDsymbol();
|
||
auto thunkFunc = getIrFunc(thunkFd, true); // create the IrFunction
|
||
thunkFunc->func = thunk;
|
||
thunkFunc->type = irFunc->type;
|
||
gIR->funcGenStates.emplace_back(new FuncGenState(*thunkFunc, *gIR));
|
||
|
||
// debug info
|
||
thunkFunc->diSubprogram = gIR->DBuilder.EmitThunk(thunk, thunkFd);
|
||
|
||
// create entry and end blocks
|
||
llvm::BasicBlock *beginbb =
|
||
llvm::BasicBlock::Create(gIR->context(), "", thunk);
|
||
gIR->scopes.push_back(IRScope(beginbb));
|
||
|
||
gIR->DBuilder.EmitFuncStart(thunkFd);
|
||
|
||
// Copy the function parameters, so later we can pass them to the
|
||
// real function and set their names from the original function (the
|
||
// latter being just for IR readablilty).
|
||
std::vector<LLValue *> args;
|
||
llvm::Function::arg_iterator thunkArg = thunk->arg_begin();
|
||
llvm::Function::arg_iterator origArg = irFunc->func->arg_begin();
|
||
for (; thunkArg != thunk->arg_end(); ++thunkArg, ++origArg) {
|
||
thunkArg->setName(origArg->getName());
|
||
args.push_back(&(*thunkArg));
|
||
}
|
||
|
||
// cast 'this' to Object
|
||
const int thisArgIndex =
|
||
(!irFunc->irFty.arg_sret || gABI->passThisBeforeSret(irFunc->type))
|
||
? 0
|
||
: 1;
|
||
LLValue *&thisArg = args[thisArgIndex];
|
||
LLType *targetThisType = thisArg->getType();
|
||
thisArg = DtoBitCast(thisArg, getVoidPtrType());
|
||
thisArg = DtoGEP1(thisArg, DtoConstInt(-thunkOffset), true);
|
||
thisArg = DtoBitCast(thisArg, targetThisType);
|
||
|
||
// all calls that might be subject to inlining into a caller with debug
|
||
// info should have debug info, too
|
||
gIR->DBuilder.EmitStopPoint(fd->loc);
|
||
|
||
// call the real vtbl function.
|
||
llvm::CallSite call = gIR->ir->CreateCall(irFunc->func, args);
|
||
call.setCallingConv(irFunc->func->getCallingConv());
|
||
|
||
// return from the thunk
|
||
if (thunk->getReturnType() == LLType::getVoidTy(gIR->context())) {
|
||
llvm::ReturnInst::Create(gIR->context(), beginbb);
|
||
} else {
|
||
llvm::ReturnInst::Create(gIR->context(), call.getInstruction(),
|
||
beginbb);
|
||
}
|
||
|
||
gIR->DBuilder.EmitFuncEnd(thunkFd);
|
||
|
||
// clean up
|
||
gIR->scopes.pop_back();
|
||
|
||
gIR->funcGenStates.pop_back();
|
||
}
|
||
|
||
constants.push_back(thunk);
|
||
}
|
||
|
||
// build the vtbl constant
|
||
llvm::Constant *vtbl_constant =
|
||
LLConstantStruct::getAnon(gIR->context(), constants, false);
|
||
|
||
std::string mangledName("_D");
|
||
mangledName.append(mangle(cd));
|
||
mangledName.append("11__interface");
|
||
mangledName.append(mangle(b->sym));
|
||
mangledName.append(thunkPrefixLen);
|
||
mangledName.append(thunkPrefix);
|
||
mangledName.append("6__vtblZ");
|
||
|
||
const auto lwc = DtoLinkage(cd);
|
||
LLGlobalVariable *GV =
|
||
getOrCreateGlobal(cd->loc, gIR->module, vtbl_constant->getType(), true,
|
||
lwc.first, vtbl_constant, mangledName);
|
||
setLinkage(lwc, GV);
|
||
|
||
// insert into the vtbl map
|
||
interfaceVtblMap.insert({{b->sym, interfaces_index}, GV});
|
||
|
||
return GV;
|
||
}
|
||
|
||
bool IrAggr::isPacked() const {
|
||
return static_cast<IrTypeAggr *>(type->ctype)->packed;
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
LLConstant *IrAggr::getClassInfoInterfaces() {
|
||
IF_LOG Logger::println("Building ClassInfo.interfaces");
|
||
LOG_SCOPE;
|
||
|
||
ClassDeclaration *cd = aggrdecl->isClassDeclaration();
|
||
assert(cd);
|
||
|
||
size_t n = interfacesWithVtbls.size();
|
||
assert(stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls() == n &&
|
||
"inconsistent number of interface vtables in this class");
|
||
|
||
VarDeclaration *interfaces_idx = Type::typeinfoclass->fields[3];
|
||
|
||
if (n == 0) {
|
||
return getNullValue(DtoType(interfaces_idx->type));
|
||
}
|
||
|
||
// Build array of:
|
||
//
|
||
// struct Interface
|
||
// {
|
||
// ClassInfo classinfo;
|
||
// void*[] vtbl;
|
||
// ptrdiff_t offset;
|
||
// }
|
||
|
||
LLSmallVector<LLConstant *, 6> constants;
|
||
constants.reserve(cd->vtblInterfaces->dim);
|
||
|
||
LLType *classinfo_type = DtoType(Type::typeinfoclass->type);
|
||
LLType *voidptrptr_type = DtoType(Type::tvoid->pointerTo()->pointerTo());
|
||
VarDeclaration *idx = Type::typeinfoclass->fields[3];
|
||
LLStructType *interface_type = isaStruct(DtoType(idx->type->nextOf()));
|
||
assert(interface_type);
|
||
|
||
for (size_t i = 0; i < n; ++i) {
|
||
BaseClass *it = interfacesWithVtbls[i];
|
||
|
||
IF_LOG Logger::println("Adding interface %s", it->sym->toPrettyChars());
|
||
|
||
IrAggr *irinter = getIrAggr(it->sym);
|
||
assert(irinter && "interface has null IrStruct");
|
||
IrTypeClass *itc = stripModifiers(irinter->type)->ctype->isClass();
|
||
assert(itc && "null interface IrTypeClass");
|
||
|
||
// classinfo
|
||
LLConstant *ci = irinter->getClassInfoSymbol();
|
||
ci = DtoBitCast(ci, classinfo_type);
|
||
|
||
// vtbl
|
||
LLConstant *vtb;
|
||
// interface get a null
|
||
if (cd->isInterfaceDeclaration()) {
|
||
vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type));
|
||
} else {
|
||
auto itv = interfaceVtblMap.find({it->sym, i});
|
||
assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
|
||
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 =
|
||
LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3));
|
||
constants.push_back(entry);
|
||
}
|
||
|
||
// create Interface[N]
|
||
LLArrayType *array_type = llvm::ArrayType::get(interface_type, n);
|
||
|
||
// create and apply initializer
|
||
LLConstant *arr = LLConstantArray::get(array_type, constants);
|
||
auto ciarr = getInterfaceArraySymbol();
|
||
ciarr->setInitializer(arr);
|
||
setLinkage(cd, ciarr);
|
||
|
||
// return null, only baseclass provide interfaces
|
||
if (cd->vtblInterfaces->dim == 0) {
|
||
return getNullValue(DtoType(interfaces_idx->type));
|
||
}
|
||
|
||
// only the interface explicitly implemented by this class
|
||
// (not super classes) should show in ClassInfo
|
||
LLConstant *idxs[2] = {DtoConstSize_t(0),
|
||
DtoConstSize_t(n - cd->vtblInterfaces->dim)};
|
||
|
||
LLConstant *ptr = llvm::ConstantExpr::getGetElementPtr(
|
||
#if LDC_LLVM_VER >= 307
|
||
isaPointer(ciarr)->getElementType(),
|
||
#endif
|
||
ciarr, idxs, true);
|
||
|
||
// return as a slice
|
||
return DtoConstSlice(DtoConstSize_t(cd->vtblInterfaces->dim), ptr);
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|
||
|
||
void IrAggr::initializeInterface() {
|
||
InterfaceDeclaration *base = aggrdecl->isInterfaceDeclaration();
|
||
assert(base && "not interface");
|
||
|
||
// has interface vtbls?
|
||
if (!base->vtblInterfaces) {
|
||
return;
|
||
}
|
||
|
||
for (auto bc : *base->vtblInterfaces) {
|
||
// add to the interface list
|
||
interfacesWithVtbls.push_back(bc);
|
||
}
|
||
}
|
||
|
||
//////////////////////////////////////////////////////////////////////////////
|