ldc/ir/irtypeclass.cpp
2024-08-18 15:30:51 +02:00

140 lines
4.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- irtypeclass.cpp ---------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "ir/irtypeclass.h"
#include "dmd/aggregate.h"
#include "dmd/declaration.h"
#include "dmd/dsymbol.h"
#include "dmd/errors.h"
#include "dmd/mtype.h"
#include "dmd/target.h"
#include "dmd/template.h"
#include "gen/functions.h"
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "llvm/IR/DerivedTypes.h"
IrTypeClass::IrTypeClass(ClassDeclaration *cd)
: IrTypeAggr(cd), cd(cd), tc(static_cast<TypeClass *>(cd->type)) {
vtbl_type = LLArrayType::get(getOpaquePtrType(), cd->vtbl.length);
}
void IrTypeClass::addClassData(AggrTypeBuilder &builder,
ClassDeclaration *currCd) {
// First, recursively add the fields for our base class and interfaces, if
// any.
if (currCd->baseClass) {
addClassData(builder, currCd->baseClass);
}
if (currCd->vtblInterfaces && currCd->vtblInterfaces->length > 0) {
// KLUDGE: The first pointer in the vtbl will be of type object.Interface;
// extract that from the "well-known" object.TypeInfo_Class definition.
// For C++ interfaces, this vtbl entry has to be omitted
builder.alignCurrentOffset(target.ptrsize);
for (auto b : *currCd->vtblInterfaces) {
IF_LOG Logger::println("Adding interface vtbl for %s",
b->sym->toPrettyChars());
// add to the interface map
addInterfaceToMap(b->sym, builder.currentFieldIndex());
auto vtblTy = LLArrayType::get(getOpaquePtrType(), b->sym->vtbl.length);
builder.addType(llvm::PointerType::get(vtblTy, 0), target.ptrsize);
++num_interface_vtbls;
}
}
// Finally, the data members for this class.
builder.addAggregate(currCd);
}
IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) {
IF_LOG Logger::println("Building class type %s @ %s", cd->toPrettyChars(),
cd->loc.toChars());
LOG_SCOPE;
const auto t = new IrTypeClass(cd);
getIrType(cd->type) = t;
const unsigned instanceSize = cd->structsize;
IF_LOG Logger::println("Instance size: %u", instanceSize);
AggrTypeBuilder builder;
// add vtbl
builder.addType(llvm::PointerType::get(t->vtbl_type, 0), target.ptrsize);
if (cd->isInterfaceDeclaration()) {
// interfaces are just a vtable
t->num_interface_vtbls =
cd->vtblInterfaces ? cd->vtblInterfaces->length : 0;
} else {
// classes have monitor and fields
if (!cd->isCPPclass() && !cd->isCPPinterface()) {
// add monitor
builder.addType(getOpaquePtrType(), target.ptrsize);
}
// add data members recursively
t->addClassData(builder, cd);
// add tail padding
if (instanceSize) // can be 0 for opaque classes
builder.addTailPadding(instanceSize);
}
// set struct body and copy GEP indices
isaStruct(t->type)->setBody(builder.defaultTypes(), builder.isPacked());
t->varGEPIndices = builder.varGEPIndices();
if (!cd->isInterfaceDeclaration() && instanceSize &&
getTypeAllocSize(t->type) != instanceSize) {
error(cd->loc, "ICE: class IR size does not match the frontend size");
fatal();
}
IF_LOG Logger::cout() << "class type: " << *t->type << std::endl;
return t;
}
llvm::Type *IrTypeClass::getLLType() { return llvm::PointerType::get(type, 0); }
llvm::Type *IrTypeClass::getMemoryLLType() { return type; }
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) {
auto it = interfaceMap.find(inter);
if (it == interfaceMap.end()) {
return ~0UL;
}
return it->second;
}
void IrTypeClass::addInterfaceToMap(ClassDeclaration *inter, size_t index) {
// don't duplicate work or overwrite indices
if (interfaceMap.find(inter) != interfaceMap.end()) {
return;
}
// add this interface
interfaceMap.insert(std::make_pair(inter, index));
// add the direct base interfaces recursively - they
// are accessed through the same index
if (inter->interfaces.length > 0) {
BaseClass *b = inter->interfaces.ptr[0];
addInterfaceToMap(b->sym, index);
}
}