mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-29 14:40:40 +03:00
196 lines
5.7 KiB
C++
196 lines
5.7 KiB
C++
//===-- 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;
|
||
}
|