mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 17:43:35 +03:00
Emit struct TypeInfos & special member functions in owning module only
Analogous to ClassInfos, incl. normal linkage (external for non- templates, weak_odr for templates). This enables to get rid of frontend logic wrt. whether to add TypeInfoStructDeclarations to a module's members tree - previously, it was defined as linkonce_odr in the owning module and each referencing module (unless speculative) - and related extra semantic and codegen for the special member functions. I've gone a bit further and moved the entire TypeInfo emission for LDC to the codegen layer; no TypeInfoDeclarations are added to the module members anymore. Whenever we need a TypeInfo symbol during codegen, it is declared or defined, and we don't need to rely on brittle frontend logic with speculative-ness complications. This might slightly increase compilation speed due to less emitted TypeInfos and functions (possibly less work for the linker too). A slight drawback is that the job of stripping unused struct TypeInfos is fully delegated to the linker, as the TypeInfo is guaranteed to end up in the owning object file due to no linkonce_odr. Another theoretical drawback is that the optimizer can definitely not inline xtoHash/xopEquals/xopCmp/xtoString/xdtor[ti]/xpostblit function pointer indirections in non-owning CUs without LTO (neither the pointers nor the special member functions are defined anymore). These (public) members are probably hardly used directly though, and instead used by the virtual TypeInfo_Struct methods equals/compare/ getHash/destroy/postblit, which are exclusively defined in druntime's object.o (incl. the TypeInfo_Struct vtable) and aren't cross-module- inlined anyway (without LTO). Re-emitting the struct TypeInfos (and optionally the special member functions too) into each referencing CU could be handled in our codegen layer, which should be much simpler and more robust than the upstream scheme.
This commit is contained in:
parent
555f3ba233
commit
64aa4fe1e3
11 changed files with 124 additions and 160 deletions
|
@ -167,10 +167,12 @@ public:
|
||||||
bool hasIdentityEquals; // true if has identity opEquals
|
bool hasIdentityEquals; // true if has identity opEquals
|
||||||
bool hasNoFields; // has no fields
|
bool hasNoFields; // has no fields
|
||||||
bool hasCopyCtor; // copy constructor
|
bool hasCopyCtor; // copy constructor
|
||||||
|
#if !IN_LLVM
|
||||||
// Even if struct is defined as non-root symbol, some built-in operations
|
// Even if struct is defined as non-root symbol, some built-in operations
|
||||||
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
||||||
// For those, today TypeInfo_Struct is generated in COMDAT.
|
// For those, today TypeInfo_Struct is generated in COMDAT.
|
||||||
bool requestTypeInfo;
|
bool requestTypeInfo;
|
||||||
|
#endif
|
||||||
|
|
||||||
FuncDeclarations postblits; // Array of postblit functions
|
FuncDeclarations postblits; // Array of postblit functions
|
||||||
FuncDeclaration *postblit; // aggregate postblit
|
FuncDeclaration *postblit; // aggregate postblit
|
||||||
|
|
|
@ -104,7 +104,10 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
|
||||||
Scope scx;
|
Scope scx;
|
||||||
scx._module = sd.getModule();
|
scx._module = sd.getModule();
|
||||||
getTypeInfoType(sd.loc, t, &scx);
|
getTypeInfoType(sd.loc, t, &scx);
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
sd.requestTypeInfo = true;
|
sd.requestTypeInfo = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!sc.minst)
|
else if (!sc.minst)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +117,10 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getTypeInfoType(sd.loc, t, sc);
|
getTypeInfoType(sd.loc, t, sc);
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
sd.requestTypeInfo = true;
|
sd.requestTypeInfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
// https://issues.dlang.org/show_bug.cgi?id=15149
|
// https://issues.dlang.org/show_bug.cgi?id=15149
|
||||||
// if the typeid operand type comes from a
|
// if the typeid operand type comes from a
|
||||||
|
@ -122,6 +128,13 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
|
||||||
// unSpeculative(sc, sd);
|
// unSpeculative(sc, sd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
// LDC defines a struct's TypeInfo (only) once in its owning module,
|
||||||
|
// including the special members, as part of StructDeclaration codegen.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
|
/* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
|
||||||
* This should be done even if typeid(T) exists in speculative scope.
|
* This should be done even if typeid(T) exists in speculative scope.
|
||||||
* Because it may appear later in non-speculative scope.
|
* Because it may appear later in non-speculative scope.
|
||||||
|
@ -150,6 +163,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
|
||||||
Module.addDeferredSemantic3(sd);
|
Module.addDeferredSemantic3(sd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} // !IN_LLVM
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitTuple(TypeTuple t)
|
void visitTuple(TypeTuple t)
|
||||||
|
@ -205,10 +219,13 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
||||||
bool hasIdentityEquals; // true if has identity opEquals
|
bool hasIdentityEquals; // true if has identity opEquals
|
||||||
bool hasNoFields; // has no fields
|
bool hasNoFields; // has no fields
|
||||||
bool hasCopyCtor; // copy constructor
|
bool hasCopyCtor; // copy constructor
|
||||||
|
version (IN_LLVM) {} else
|
||||||
|
{
|
||||||
// Even if struct is defined as non-root symbol, some built-in operations
|
// Even if struct is defined as non-root symbol, some built-in operations
|
||||||
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
|
||||||
// For those, today TypeInfo_Struct is generated in COMDAT.
|
// For those, today TypeInfo_Struct is generated in COMDAT.
|
||||||
bool requestTypeInfo;
|
bool requestTypeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
FuncDeclarations postblits; // Array of postblit functions
|
FuncDeclarations postblits; // Array of postblit functions
|
||||||
FuncDeclaration postblit; // aggregate postblit
|
FuncDeclaration postblit; // aggregate postblit
|
||||||
|
|
29
dmd/typinf.d
29
dmd/typinf.d
|
@ -75,6 +75,12 @@ void genTypeInfo(Loc loc, Type torig, Scope* sc)
|
||||||
t.vtinfo = getTypeInfoDeclaration(t);
|
t.vtinfo = getTypeInfoDeclaration(t);
|
||||||
assert(t.vtinfo);
|
assert(t.vtinfo);
|
||||||
|
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
// LDC handles emission in the codegen layer
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* If this has a custom implementation in std/typeinfo, then
|
/* If this has a custom implementation in std/typeinfo, then
|
||||||
* do not generate a COMDAT for it.
|
* do not generate a COMDAT for it.
|
||||||
*/
|
*/
|
||||||
|
@ -88,17 +94,11 @@ void genTypeInfo(Loc loc, Type torig, Scope* sc)
|
||||||
m.members.push(t.vtinfo);
|
m.members.push(t.vtinfo);
|
||||||
}
|
}
|
||||||
else // if in obj generation pass
|
else // if in obj generation pass
|
||||||
{
|
|
||||||
version (IN_LLVM)
|
|
||||||
{
|
|
||||||
Declaration_codegen(t.vtinfo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
toObjFile(t.vtinfo, global.params.multiobj);
|
toObjFile(t.vtinfo, global.params.multiobj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // !IN_LLVM
|
||||||
}
|
}
|
||||||
if (!torig.vtinfo)
|
if (!torig.vtinfo)
|
||||||
torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
|
torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
|
||||||
|
@ -157,12 +157,19 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version (IN_LLVM)
|
||||||
|
{
|
||||||
|
// LDC handles TypeInfo emission in the codegen layer
|
||||||
|
// => no need to take care of speculative types.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Returns:
|
* Returns:
|
||||||
* true if any part of type t is speculative.
|
* true if any part of type t is speculative.
|
||||||
* if t is null, returns false.
|
* if t is null, returns false.
|
||||||
*/
|
*/
|
||||||
extern (C++) // IN_LLVM
|
|
||||||
bool isSpeculativeType(Type t)
|
bool isSpeculativeType(Type t)
|
||||||
{
|
{
|
||||||
static bool visitVector(TypeVector t)
|
static bool visitVector(TypeVector t)
|
||||||
|
@ -255,6 +262,8 @@ bool isSpeculativeType(Type t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // !IN_LLVM
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
/* These decide if there's an instance for them already in std.typeinfo,
|
/* These decide if there's an instance for them already in std.typeinfo,
|
||||||
|
@ -263,8 +272,8 @@ bool isSpeculativeType(Type t)
|
||||||
// IN_LLVM: replaced `private` with `extern(C++)`
|
// IN_LLVM: replaced `private` with `extern(C++)`
|
||||||
extern(C++) bool builtinTypeInfo(Type t)
|
extern(C++) bool builtinTypeInfo(Type t)
|
||||||
{
|
{
|
||||||
// LDC_FIXME: if I enable for Tclass, the way LDC does typeinfo will cause
|
// IN_LLVM: the Tclass case seems to be a DMD hack
|
||||||
// a bunch of linker errors to missing ClassInfo init symbols.
|
// (in order not to define ClassInfos in each referencing module)
|
||||||
if (t.isTypeBasic() || (!IN_LLVM && t.ty == Tclass) || t.ty == Tnull)
|
if (t.isTypeBasic() || (!IN_LLVM && t.ty == Tclass) || t.ty == Tnull)
|
||||||
return !t.mod;
|
return !t.mod;
|
||||||
if (t.ty == Tarray)
|
if (t.ty == Tarray)
|
||||||
|
|
|
@ -92,7 +92,10 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl->members && decl->symtab) {
|
if (!(decl->members && decl->symtab)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DtoResolveClass(decl);
|
DtoResolveClass(decl);
|
||||||
decl->ir->setDefined();
|
decl->ir->setDefined();
|
||||||
|
|
||||||
|
@ -103,12 +106,11 @@ public:
|
||||||
|
|
||||||
// Emit TypeInfo.
|
// Emit TypeInfo.
|
||||||
IrClass *ir = getIrAggr(decl);
|
IrClass *ir = getIrAggr(decl);
|
||||||
if (!ir->suppressTypeInfo() && !isSpeculativeType(decl->type)) {
|
if (!ir->suppressTypeInfo()) {
|
||||||
llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol();
|
llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol();
|
||||||
defineGlobal(interfaceZ, ir->getClassInfoInit(), decl);
|
defineGlobal(interfaceZ, ir->getClassInfoInit(), decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -128,6 +130,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(decl->members && decl->symtab)) {
|
if (!(decl->members && decl->symtab)) {
|
||||||
|
// we need to emit TypeInfos for opaque structs too
|
||||||
|
IrStruct *ir = getIrAggr(decl, true);
|
||||||
|
if (!irs->dcomputetarget && !ir->suppressTypeInfo()) {
|
||||||
|
llvm::GlobalVariable *typeInfo = ir->getTypeInfoSymbol();
|
||||||
|
defineGlobal(typeInfo, ir->getTypeInfoInit(), decl);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +162,6 @@ public:
|
||||||
|
|
||||||
// emit typeinfo
|
// emit typeinfo
|
||||||
if (!ir->suppressTypeInfo()) {
|
if (!ir->suppressTypeInfo()) {
|
||||||
DtoTypeInfoOf(decl->type, /*base=*/false);
|
|
||||||
|
|
||||||
// Emit __xopEquals/__xopCmp/__xtoHash.
|
// Emit __xopEquals/__xopCmp/__xtoHash.
|
||||||
if (decl->xeq && decl->xeq != decl->xerreq) {
|
if (decl->xeq && decl->xeq != decl->xerreq) {
|
||||||
decl->xeq->accept(this);
|
decl->xeq->accept(this);
|
||||||
|
@ -165,6 +172,10 @@ public:
|
||||||
if (decl->xhash) {
|
if (decl->xhash) {
|
||||||
decl->xhash->accept(this);
|
decl->xhash->accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define the TypeInfo_Struct symbol
|
||||||
|
llvm::GlobalVariable *typeInfo = ir->getTypeInfoSymbol();
|
||||||
|
defineGlobal(typeInfo, ir->getTypeInfoInit(), decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +199,10 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl->members && decl->symtab) {
|
if (!(decl->members && decl->symtab)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DtoResolveClass(decl);
|
DtoResolveClass(decl);
|
||||||
decl->ir->setDefined();
|
decl->ir->setDefined();
|
||||||
|
|
||||||
|
@ -209,12 +223,11 @@ public:
|
||||||
ir->defineInterfaceVtbls();
|
ir->defineInterfaceVtbls();
|
||||||
|
|
||||||
// Emit TypeInfo.
|
// Emit TypeInfo.
|
||||||
if (!ir->suppressTypeInfo() && !isSpeculativeType(decl->type)) {
|
if (!ir->suppressTypeInfo()) {
|
||||||
llvm::GlobalVariable *classZ = ir->getClassInfoSymbol();
|
llvm::GlobalVariable *classZ = ir->getClassInfoSymbol();
|
||||||
defineGlobal(classZ, ir->getClassInfoInit(), decl);
|
defineGlobal(classZ, ir->getClassInfoInit(), decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -503,8 +516,7 @@ public:
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void visit(TypeInfoDeclaration *decl) override {
|
void visit(TypeInfoDeclaration *decl) override {
|
||||||
if (!irs->dcomputetarget)
|
llvm_unreachable("Should be emitted from codegen layer only");
|
||||||
TypeInfoDeclaration_codegen(decl);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -827,8 +827,9 @@ void DtoResolveDsymbol(Dsymbol *dsym) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoResolveVariable(VarDeclaration *vd) {
|
void DtoResolveVariable(VarDeclaration *vd) {
|
||||||
if (vd->isTypeInfoDeclaration()) {
|
if (auto tid = vd->isTypeInfoDeclaration()) {
|
||||||
return DtoResolveTypeInfo(static_cast<TypeInfoDeclaration *>(vd));
|
DtoResolveTypeInfo(tid);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IF_LOG Logger::println("DtoResolveVariable(%s)", vd->toPrettyChars());
|
IF_LOG Logger::println("DtoResolveVariable(%s)", vd->toPrettyChars());
|
||||||
|
@ -1263,17 +1264,12 @@ LLConstant *DtoTypeInfoOf(Type *type, bool base) {
|
||||||
type->toChars(), base);
|
type->toChars(), base);
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
||||||
TypeInfoDeclaration *tidecl =
|
auto tidecl = getOrCreateTypeInfoDeclaration(Loc(), type);
|
||||||
getOrCreateTypeInfoDeclaration(Loc(), type, nullptr);
|
auto tiglobal = DtoResolveTypeInfo(tidecl);
|
||||||
assert(tidecl);
|
|
||||||
Declaration_codegen(tidecl);
|
|
||||||
assert(getIrGlobal(tidecl)->value != NULL);
|
|
||||||
LLConstant *c = isaConstant(getIrGlobal(tidecl)->value);
|
|
||||||
assert(c != NULL);
|
|
||||||
if (base) {
|
if (base) {
|
||||||
return llvm::ConstantExpr::getBitCast(c, DtoType(getTypeInfoType()));
|
return llvm::ConstantExpr::getBitCast(tiglobal, DtoType(getTypeInfoType()));
|
||||||
}
|
}
|
||||||
return c;
|
return tiglobal;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1560,10 +1556,8 @@ DValue *DtoSymbolAddress(Loc &loc, Type *type, Declaration *decl) {
|
||||||
// typeinfo
|
// typeinfo
|
||||||
if (TypeInfoDeclaration *tid = vd->isTypeInfoDeclaration()) {
|
if (TypeInfoDeclaration *tid = vd->isTypeInfoDeclaration()) {
|
||||||
Logger::println("TypeInfoDeclaration");
|
Logger::println("TypeInfoDeclaration");
|
||||||
DtoResolveTypeInfo(tid);
|
|
||||||
assert(getIrValue(tid));
|
|
||||||
LLType *vartype = DtoType(type);
|
LLType *vartype = DtoType(type);
|
||||||
LLValue *m = getIrValue(tid);
|
LLValue *m = DtoResolveTypeInfo(tid);
|
||||||
if (m->getType() != getPtrToType(vartype)) {
|
if (m->getType() != getPtrToType(vartype)) {
|
||||||
m = gIR->ir->CreateBitCast(m, vartype);
|
m = gIR->ir->CreateBitCast(m, vartype);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2669,8 +2669,8 @@ public:
|
||||||
|
|
||||||
void visit(TypeidExp *e) override {
|
void visit(TypeidExp *e) override {
|
||||||
if (Type *t = isType(e->obj)) {
|
if (Type *t = isType(e->obj)) {
|
||||||
result = DtoSymbolAddress(
|
result = DtoSymbolAddress(e->loc, e->type,
|
||||||
e->loc, e->type, getOrCreateTypeInfoDeclaration(e->loc, t, nullptr));
|
getOrCreateTypeInfoDeclaration(e->loc, t));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Expression *ex = isExpression(e->obj)) {
|
if (Expression *ex = isExpression(e->obj)) {
|
||||||
|
|
|
@ -60,14 +60,14 @@
|
||||||
void genTypeInfo(Loc loc, Type *torig, Scope *sc);
|
void genTypeInfo(Loc loc, Type *torig, Scope *sc);
|
||||||
bool builtinTypeInfo(Type *t);
|
bool builtinTypeInfo(Type *t);
|
||||||
|
|
||||||
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc, Type *torig,
|
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc, Type *forType) {
|
||||||
Scope *sc) {
|
IF_LOG Logger::println("getOrCreateTypeInfoDeclaration(): %s",
|
||||||
IF_LOG Logger::println("Type::getTypeInfo(): %s", torig->toChars());
|
forType->toChars());
|
||||||
LOG_SCOPE
|
LOG_SCOPE
|
||||||
|
|
||||||
genTypeInfo(loc, torig, sc);
|
genTypeInfo(loc, forType, nullptr);
|
||||||
|
|
||||||
return torig->vtinfo;
|
return forType->vtinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
@ -105,23 +105,6 @@ void emitTypeInfoMetadata(LLGlobalVariable *typeinfoGlobal, Type *forType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoResolveTypeInfo(TypeInfoDeclaration *tid) {
|
|
||||||
if (tid->ir->isResolved()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tid->ir->setResolved();
|
|
||||||
|
|
||||||
// TypeInfo instances (except ClassInfo ones) are always emitted as weak
|
|
||||||
// symbols when they are used. We call semanticTypeInfo() to make sure
|
|
||||||
// that the type (e.g. for structs) is semantic3'd and codegen() does not
|
|
||||||
// skip it on grounds of being speculative, as DtoResolveTypeInfo() means
|
|
||||||
// that we actually need the value somewhere else in codegen.
|
|
||||||
// TODO: DMD does not seem to call semanticTypeInfo() from the glue layer,
|
|
||||||
// so there might be a structural issue somewhere.
|
|
||||||
semanticTypeInfo(nullptr, tid->tinfo);
|
|
||||||
Declaration_codegen(tid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -471,8 +454,7 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
|
||||||
|
|
||||||
// check if the definition can be elided
|
// check if the definition can be elided
|
||||||
if (gvar->hasInitializer() || !global.params.useTypeInfo ||
|
if (gvar->hasInitializer() || !global.params.useTypeInfo ||
|
||||||
!Type::dtypeinfo || isSpeculativeType(forType) ||
|
!Type::dtypeinfo || builtinTypeInfo(forType)) {
|
||||||
builtinTypeInfo(forType)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (auto forClassType = forType->isTypeClass()) {
|
if (auto forClassType = forType->isTypeClass()) {
|
||||||
|
@ -491,28 +473,12 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
|
||||||
class DeclareOrDefineVisitor : public Visitor {
|
class DeclareOrDefineVisitor : public Visitor {
|
||||||
using Visitor::visit;
|
using Visitor::visit;
|
||||||
|
|
||||||
// Define struct TypeInfos as linkonce_odr in each referencing CU.
|
// Only declare struct TypeInfos. They are defined once in their owning module
|
||||||
|
// as part of StructDeclaration codegen.
|
||||||
void visit(TypeInfoStructDeclaration *decl) override {
|
void visit(TypeInfoStructDeclaration *decl) override {
|
||||||
auto forType = decl->tinfo->isTypeStruct();
|
auto irstruct = getIrAggr(decl->tinfo->isTypeStruct()->sym, true);
|
||||||
|
|
||||||
auto irstruct = getIrAggr(forType->sym, true);
|
|
||||||
auto gvar = irstruct->getTypeInfoSymbol();
|
|
||||||
|
|
||||||
IrGlobal *irg = getIrGlobal(decl, true);
|
IrGlobal *irg = getIrGlobal(decl, true);
|
||||||
irg->value = gvar;
|
irg->value = irstruct->getTypeInfoSymbol();
|
||||||
|
|
||||||
// check if the definition can be elided
|
|
||||||
if (gvar->hasInitializer() || irstruct->suppressTypeInfo() ||
|
|
||||||
isSpeculativeType(forType)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLConstant *init = irstruct->getTypeInfoInit(); // might define gvar!
|
|
||||||
|
|
||||||
if (!gvar->hasInitializer()) {
|
|
||||||
defineGlobal(gvar, init, irstruct->aggrdecl);
|
|
||||||
gvar->setLinkage(TYPEINFO_LINKAGE_TYPE); // override
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only declare class TypeInfos. They are defined once in their owning module
|
// Only declare class TypeInfos. They are defined once in their owning module
|
||||||
|
@ -526,17 +492,22 @@ class DeclareOrDefineVisitor : public Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build all other TypeInfos.
|
// Build all other TypeInfos.
|
||||||
void visit(TypeInfoDeclaration *decl) override {
|
void visit(TypeInfoDeclaration *decl) override { buildTypeInfo(decl); }
|
||||||
buildTypeInfo(decl);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl) {
|
LLGlobalVariable *DtoResolveTypeInfo(TypeInfoDeclaration *tid) {
|
||||||
IF_LOG Logger::println("TypeInfoDeclaration_codegen(%s)",
|
IF_LOG Logger::println("DtoResolveTypeInfo(%s)", tid->toPrettyChars());
|
||||||
decl->toPrettyChars());
|
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
|
assert(!gIR->dcomputetarget);
|
||||||
|
|
||||||
|
if (!tid->ir->isResolved()) {
|
||||||
|
tid->ir->setResolved();
|
||||||
|
|
||||||
DeclareOrDefineVisitor v;
|
DeclareOrDefineVisitor v;
|
||||||
decl->accept(&v);
|
tid->accept(&v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return llvm::cast<LLGlobalVariable>(getIrValue(tid));
|
||||||
}
|
}
|
||||||
|
|
11
gen/typinf.h
11
gen/typinf.h
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct Scope;
|
|
||||||
struct Loc;
|
struct Loc;
|
||||||
class Type;
|
class Type;
|
||||||
class TypeInfoDeclaration;
|
class TypeInfoDeclaration;
|
||||||
|
@ -23,13 +22,9 @@ namespace llvm {
|
||||||
class GlobalVariable;
|
class GlobalVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoResolveTypeInfo(TypeInfoDeclaration *tid);
|
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc,
|
||||||
TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc, Type *t,
|
Type *forType);
|
||||||
Scope *sc);
|
llvm::GlobalVariable *DtoResolveTypeInfo(TypeInfoDeclaration *tid);
|
||||||
void TypeInfoDeclaration_codegen(TypeInfoDeclaration *decl);
|
|
||||||
|
|
||||||
// Adds some metadata for use by optimization passes.
|
// Adds some metadata for use by optimization passes.
|
||||||
void emitTypeInfoMetadata(llvm::GlobalVariable *typeinfoGlobal, Type *forType);
|
void emitTypeInfoMetadata(llvm::GlobalVariable *typeinfoGlobal, Type *forType);
|
||||||
|
|
||||||
// defined in dmd/typinf.d:
|
|
||||||
bool isSpeculativeType(Type *t);
|
|
||||||
|
|
|
@ -101,42 +101,6 @@ LLConstant *IrStruct::getTypeInfoInit() {
|
||||||
// we need (dummy) TypeInfos for opaque structs too
|
// we need (dummy) TypeInfos for opaque structs too
|
||||||
const bool isOpaque = !sd->members;
|
const bool isOpaque = !sd->members;
|
||||||
|
|
||||||
if (!isOpaque) {
|
|
||||||
DtoResolveStruct(sd);
|
|
||||||
|
|
||||||
if (TemplateInstance *ti = sd->isInstantiated()) {
|
|
||||||
if (!ti->needsCodegen()) {
|
|
||||||
assert(ti->minst || sd->requestTypeInfo);
|
|
||||||
|
|
||||||
// We won't emit ti, so emit the special member functions in here.
|
|
||||||
if (sd->xeq && sd->xeq != StructDeclaration::xerreq &&
|
|
||||||
sd->xeq->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->xeq);
|
|
||||||
}
|
|
||||||
if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp &&
|
|
||||||
sd->xcmp->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->xcmp);
|
|
||||||
}
|
|
||||||
if (FuncDeclaration *ftostr = search_toString(sd)) {
|
|
||||||
if (ftostr->semanticRun >= PASSsemantic3)
|
|
||||||
Declaration_codegen(ftostr);
|
|
||||||
}
|
|
||||||
if (sd->xhash && sd->xhash->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->xhash);
|
|
||||||
}
|
|
||||||
if (sd->postblit && sd->postblit->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->postblit);
|
|
||||||
}
|
|
||||||
if (sd->dtor && sd->dtor->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->dtor);
|
|
||||||
}
|
|
||||||
if (sd->tidtor && sd->tidtor->semanticRun >= PASSsemantic3) {
|
|
||||||
Declaration_codegen(sd->tidtor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// string name
|
// string name
|
||||||
if (isOpaque) {
|
if (isOpaque) {
|
||||||
b.push_null_void_array();
|
b.push_null_void_array();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
pragma(LDC_no_moduleinfo); // prevent ModuleInfo from referencing class TypeInfos
|
pragma(LDC_no_moduleinfo); // prevent ModuleInfo from referencing class TypeInfos
|
||||||
|
|
||||||
|
|
||||||
// CHECK: _D50TypeInfo_S18pragma_no_typeinfo18StructWithTypeInfo6__initZ = linkonce_odr global %object.TypeInfo_Struct
|
// CHECK: _D50TypeInfo_S18pragma_no_typeinfo18StructWithTypeInfo6__initZ = global %object.TypeInfo_Struct
|
||||||
struct StructWithTypeInfo {}
|
struct StructWithTypeInfo {}
|
||||||
|
|
||||||
// CHECK: _D18pragma_no_typeinfo17ClassWithTypeInfo7__ClassZ = global %object.TypeInfo_Class
|
// CHECK: _D18pragma_no_typeinfo17ClassWithTypeInfo7__ClassZ = global %object.TypeInfo_Class
|
||||||
|
|
|
@ -23,6 +23,6 @@ auto classvar = typeid(C);
|
||||||
// CHECK-DAG: _D{{.*}}interfacevarC18TypeInfo_Interface{{\"?}} = thread_local global %object.TypeInfo_Interface* {{.*}}TypeInfo_C{{.*}}1I6__initZ
|
// CHECK-DAG: _D{{.*}}interfacevarC18TypeInfo_Interface{{\"?}} = thread_local global %object.TypeInfo_Interface* {{.*}}TypeInfo_C{{.*}}1I6__initZ
|
||||||
auto interfacevar = typeid(I);
|
auto interfacevar = typeid(I);
|
||||||
|
|
||||||
// CHECK-DAG: _D{{.*}}TypeInfo_S{{.*}}1S6__initZ{{\"?}} = linkonce_odr global %object.TypeInfo_Struct
|
// CHECK-DAG: _D{{.*}}TypeInfo_S{{.*}}1S6__initZ{{\"?}} = global %object.TypeInfo_Struct
|
||||||
// CHECK-DAG: _D{{.*}}structvarC15TypeInfo_Struct{{\"?}} = thread_local global %object.TypeInfo_Struct* {{.*}}TypeInfo_S{{.*}}1S6__initZ
|
// CHECK-DAG: _D{{.*}}structvarC15TypeInfo_Struct{{\"?}} = thread_local global %object.TypeInfo_Struct* {{.*}}TypeInfo_S{{.*}}1S6__initZ
|
||||||
auto structvar = typeid(S);
|
auto structvar = typeid(S);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue