ldc/ir/irstruct.cpp
2024-07-18 23:21:10 +02:00

196 lines
5.7 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.

//===-- irstruct.cpp ------------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#include "dmd/errors.h"
#include "dmd/mangle.h"
#include "dmd/mtype.h"
#include "dmd/template.h"
#include "gen/irstate.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/mangling.h"
#include "gen/rttibuilder.h"
#include "gen/runtime.h"
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "gen/typinf.h"
#include "ir/iraggr.h"
#include "ir/irtypeclass.h"
using namespace dmd;
namespace {
LLStructType* getTypeInfoStructMemType() {
Type *t = getStructTypeInfoType();
IrTypeClass *tc = getIrType(t, true)->isClass();
assert(tc && "invalid TypeInfo_Struct type");
return llvm::cast<LLStructType>(tc->getMemoryLLType());
}
}
LLGlobalVariable* IrStruct::getTypeInfoSymbol(bool define) {
if (!typeInfo) {
OutBuffer mangledName;
mangledName.writestring("TypeInfo_S");
mangleToBuffer(aggrdecl, mangledName);
const auto length = mangledName.length();
mangledName.prependstring(("_D" + std::to_string(length)).c_str());
mangledName.writestring("6__initZ");
const auto irMangle = getIRMangledVarName(mangledName.peekChars(), LINK::d);
// We need to keep the symbol mutable as the type is not declared as
// immutable on the D side, and e.g. synchronized() can be used on the
// implicit monitor.
const bool isConstant = false;
// Struct TypeInfos are emitted into each referencing CU.
const bool useDLLImport = false;
typeInfo =
declareGlobal(aggrdecl->loc, gIR->module, getTypeInfoStructMemType(),
irMangle, isConstant, false, useDLLImport);
emitTypeInfoMetadata(typeInfo, aggrdecl->type);
if (!define)
define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
}
if (define) {
auto init = getTypeInfoInit();
if (!typeInfo->hasInitializer())
defineGlobal(typeInfo, init, aggrdecl);
}
return typeInfo;
}
LLConstant *IrStruct::getTypeInfoInit() {
// The upstream implementation is in dmd/todt.d,
// TypeInfoDtVisitor.visit(TypeInfoStructDeclaration).
if (constTypeInfo) {
return constTypeInfo;
}
auto sd = aggrdecl->isStructDeclaration();
IF_LOG Logger::println("Defining TypeInfo for struct: %s", sd->toChars());
LOG_SCOPE;
// we need (dummy) TypeInfos for opaque structs too
const bool isOpaque = !sd->members;
// make sure xtoHash/xopEquals/xopCmp etc. are semantically analyzed
if (!isOpaque && sd->semanticRun < PASS::semantic3done) {
Logger::println(
"Struct hasn't had semantic3 yet, calling semanticTypeInfoMembers()");
semanticTypeInfoMembers(sd);
}
TypeStruct *ts = sd->type->isTypeStruct();
// check declaration in object.d
const auto structTypeInfoType = getStructTypeInfoType();
const auto structTypeInfoDecl = Type::typeinfostruct;
// For x86_64 (except Win64) and AAPCS64 targets, class TypeInfo_Struct
// contains 2 additional fields (m_arg1/m_arg2) which are used for the
// TypeInfo-based core.stdc.stdarg.va_arg implementations in druntime.
const auto &triple = *global.params.targetTriple;
const auto arch = triple.getArch();
const bool withArgTypes =
(arch == llvm::Triple::x86_64 && !triple.isOSWindows()) ||
(!triple.isOSDarwin() && // Apple uses a simpler scheme
(arch == llvm::Triple::aarch64 || arch == llvm::Triple::aarch64_be));
const unsigned expectedFields = 11 + (withArgTypes ? 2 : 0);
const unsigned actualFields =
structTypeInfoDecl->fields.length -
1; // union of xdtor/xdtorti counts as 2 overlapping fields
if (actualFields != expectedFields) {
error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; "
"druntime version does not match compiler");
fatal();
}
RTTIBuilder b(structTypeInfoType);
// string mangledName
if (isOpaque) {
b.push_null_void_array();
} else {
b.push_string(ts->deco);
}
// void[] m_init
// The protocol is to write a null pointer for zero-initialized structs.
// The length field is always needed for tsize().
if (isOpaque) {
b.push_null_void_array();
} else {
llvm::Constant *initPtr;
if (ts->isZeroInit(Loc())) {
initPtr = getNullPtr();
} else {
initPtr = getInitSymbol();
}
b.push_void_array(sd->size(Loc()), initPtr);
}
// function xtoHash
b.push_funcptr(isOpaque ? nullptr : sd->xhash);
// function xopEquals
b.push_funcptr(isOpaque ? nullptr : sd->xeq);
// function xopCmp
b.push_funcptr(isOpaque ? nullptr : sd->xcmp);
// function xtoString
b.push_funcptr(isOpaque ? nullptr : search_toString(sd));
// StructFlags m_flags
b.push_uint(!isOpaque && hasPointers(ts) ? 1 : 0);
// function xdtor/xdtorti
b.push_funcptr(isOpaque ? nullptr : sd->tidtor);
// function xpostblit
FuncDeclaration *xpostblit = isOpaque ? nullptr : sd->postblit;
if (xpostblit && (xpostblit->storage_class & STCdisable)) {
xpostblit = nullptr;
}
b.push_funcptr(xpostblit);
// uint m_align
b.push_uint(isOpaque ? 0 : DtoAlignment(ts));
if (withArgTypes) {
// TypeInfo m_arg1
// TypeInfo m_arg2
for (unsigned i = 0; i < 2; i++) {
if (auto t = isOpaque ? nullptr : sd->argType(i)) {
t = merge(t);
b.push_typeinfo(t);
} else {
b.push_null(getTypeInfoType());
}
}
}
// immutable(void)* m_RTInfo
if (!isOpaque && sd->getRTInfo) {
b.push(toConstElem(sd->getRTInfo, gIR));
} else {
b.push_size_as_vp(!isOpaque && hasPointers(ts) ? 1 : 0);
}
constTypeInfo = b.get_constant(getTypeInfoStructMemType());
return constTypeInfo;
}