Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle IR collisions wrt. built-in TypeInfos and make them mutable #3599

Merged
merged 3 commits into from
Oct 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions gen/linkage.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,5 @@
// Make it easier to test new linkage types

#define TYPEINFO_LINKAGE_TYPE LLGlobalValue::LinkOnceODRLinkage
// The One-Definition-Rule shouldn't matter for debug info, right?
#define DEBUGINFO_LINKONCE_LINKAGE_TYPE LLGlobalValue::LinkOnceAnyLinkage

extern LLGlobalValue::LinkageTypes templateLinkage;
22 changes: 3 additions & 19 deletions gen/passes/GarbageCollect2Stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -569,28 +569,12 @@ llvm::Type *Analysis::getTypeFor(Value *typeinfo) const {
const auto metaname = getMetadataName(TD_PREFIX, ti_global);

NamedMDNode *meta = M.getNamedMetadata(metaname);
if (!meta) {
if (!meta || meta->getNumOperands() != 1) {
return nullptr;
}

MDNode *node = static_cast<MDNode *>(meta->getOperand(0));
if (!node) {
return nullptr;
}

if (node->getNumOperands() != TD_NumFields) {
return nullptr;
}

auto md = llvm::dyn_cast<llvm::ValueAsMetadata>(
node->getOperand(TD_TypeInfo).get());
if (md == nullptr || md->getValue()->stripPointerCasts() != ti_global) {
return nullptr;
}


return llvm::cast<llvm::ValueAsMetadata>(node->getOperand(TD_Type))
->getType();
MDNode *node = meta->getOperand(0);
return llvm::cast<llvm::ConstantAsMetadata>(node->getOperand(0))->getType();
}

/// Returns whether Def is used by any instruction that is reachable from Alloc
Expand Down
18 changes: 3 additions & 15 deletions gen/passes/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,14 @@

#pragma once

// MDNode was moved into its own header, and contains Value*s
#include "llvm/IR/Metadata.h"
typedef llvm::Value MDNodeField;

#define METADATA_LINKAGE_TYPE llvm::GlobalValue::WeakODRLinkage

// *** Metadata for TypeInfo instances ***
// A metadata node for a TypeInfo instance will be named TD_PREFIX ~ <Name of
// TypeInfo global>. The node contains a single operand, an arbitrary constant
// value of the LLVM type corresponding to the D type the TypeInfo is for.
#define TD_PREFIX "llvm.ldc.typeinfo."

/// The fields in the metadata node for a TypeInfo instance.
/// (Its name will be TD_PREFIX ~ <Name of TypeInfo global>)
enum TypeDataFields {
TD_TypeInfo, /// A reference toe the TypeInfo global this node is for.

TD_Type, /// A value of the LLVM type corresponding to this D type

// Must be kept last:
TD_NumFields /// The number of fields in TypeInfo metadata
};

// *** Metadata for ClassInfo instances ***
#define CD_PREFIX "llvm.ldc.classinfo."

Expand Down
39 changes: 17 additions & 22 deletions gen/typinf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@
#include <cassert>
#include <cstdio>

// defined in dmd/typinf.d:
void genTypeInfo(Loc loc, Type *torig, Scope *sc);
bool builtinTypeInfo(Type *t);
void genTypeInfo(Loc loc, Type *torig, Scope *sc); // in dmd/typinf.d

TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc, Type *forType) {
IF_LOG Logger::println("getOrCreateTypeInfoDeclaration(): %s",
Expand Down Expand Up @@ -88,19 +86,12 @@ void emitTypeInfoMetadata(LLGlobalVariable *typeinfoGlobal, Type *forType) {
t->ty != Tident) {
const auto metaname = getMetadataName(TD_PREFIX, typeinfoGlobal);

llvm::NamedMDNode *meta = gIR->module.getNamedMetadata(metaname);

if (!meta) {
// Construct the fields
llvm::Metadata *mdVals[TD_NumFields];
mdVals[TD_TypeInfo] = llvm::ValueAsMetadata::get(typeinfoGlobal);
mdVals[TD_Type] = llvm::ConstantAsMetadata::get(
llvm::UndefValue::get(DtoType(forType)));

if (!gIR->module.getNamedMetadata(metaname)) {
// Construct the metadata and insert it into the module.
llvm::NamedMDNode *node = gIR->module.getOrInsertNamedMetadata(metaname);
node->addOperand(llvm::MDNode::get(
gIR->context(), llvm::makeArrayRef(mdVals, TD_NumFields)));
auto meta = gIR->module.getOrInsertNamedMetadata(metaname);
auto val = llvm::UndefValue::get(DtoType(forType));
meta->addOperand(llvm::MDNode::get(gIR->context(),
llvm::ConstantAsMetadata::get(val)));
}
}
}
Expand Down Expand Up @@ -434,21 +425,25 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
Logger::println("typeinfo mangle: %s", mangled);
}

// Only declare the symbol if it isn't yet, otherwise the subtype of
// built-in TypeInfos (rt.typeinfo.*) may clash with the base type when
// compiling the rt.typeinfo.* modules.
// Only declare the symbol if it isn't yet, otherwise it may clash with an
// existing init symbol of a built-in TypeInfo class (in rt.util.typeinfo)
// when compiling the rt.util.typeinfo unittests.
const auto irMangle = getIRMangledVarName(mangled, LINKd);
LLGlobalVariable *gvar = gIR->module.getGlobalVariable(irMangle);
if (!gvar) {
if (gvar) {
assert(builtinTypeInfo(forType) && "existing global expected to be the "
"init symbol of a built-in TypeInfo");
} else {
LLType *type = DtoType(decl->type)->getPointerElementType();
// 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.
gvar = declareGlobal(decl->loc, gIR->module, type, irMangle, false);

emitTypeInfoMetadata(gvar, forType);
gvar = declareGlobal(decl->loc, gIR->module, type, irMangle,
/*isConstant=*/false);
}

emitTypeInfoMetadata(gvar, forType);

IrGlobal *irg = getIrGlobal(decl, true);
irg->value = gvar;

Expand Down
2 changes: 2 additions & 0 deletions gen/typinf.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct Loc;
class Type;
class TypeInfoDeclaration;

bool builtinTypeInfo(Type *t); // in dmd/typinf.d

namespace llvm {
class GlobalVariable;
}
Expand Down
27 changes: 24 additions & 3 deletions ir/iraggr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "dmd/aggregate.h"
#include "dmd/declaration.h"
#include "dmd/expression.h"
#include "dmd/identifier.h"
#include "dmd/init.h"
#include "dmd/mtype.h"
#include "dmd/target.h"
Expand Down Expand Up @@ -55,9 +56,29 @@ LLConstant *IrAggr::getInitSymbol(bool define) {
if (!init) {
const auto irMangle = getIRMangledInitSymbolName(aggrdecl);

auto initGlobal =
declareGlobal(aggrdecl->loc, gIR->module, getLLStructType(), irMangle,
/*isConstant=*/true);
// Init symbols of built-in TypeInfo classes (in rt.util.typeinfo) are
// special.
auto cd = aggrdecl->isClassDeclaration();
const bool isBuiltinTypeInfo =
cd && llvm::StringRef(cd->ident->toChars()).startswith("TypeInfo_");

// Only declare the symbol if it isn't yet, otherwise the init symbol of
// built-in TypeInfos may clash with an existing base-typed forward
// declaration when compiling the rt.util.typeinfo unittests.
auto initGlobal = gIR->module.getGlobalVariable(irMangle);
if (initGlobal) {
assert(isBuiltinTypeInfo && !initGlobal->hasInitializer() &&
"existing global expected to be a built-in TypeInfo forward "
"declaration");
} else {
// Init symbols of built-in TypeInfos need to be kept mutable as the type
// is not declared as immutable on the D side, and e.g. synchronized() can
// be used on the implicit monitor.
initGlobal =
declareGlobal(aggrdecl->loc, gIR->module, getLLStructType(), irMangle,
/*isConstant=*/!isBuiltinTypeInfo);
}

initGlobal->setAlignment(LLMaybeAlign(DtoAlignment(type)));

init = initGlobal;
Expand Down
7 changes: 4 additions & 3 deletions ir/irclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,11 @@ LLGlobalVariable *IrClass::getClassInfoSymbol(bool define) {
IrTypeClass *tc = stripModifiers(cinfoType)->ctype->isClass();
assert(tc && "invalid ClassInfo type");

// classinfos cannot be constants since they're used as locks for
// synchronized
// 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.
typeInfo = declareGlobal(aggrdecl->loc, gIR->module, tc->getMemoryLLType(),
irMangle, false);
irMangle, /*isConstant=*/false);

// Generate some metadata on this ClassInfo if it's for a class.
if (!aggrdecl->isInterfaceDeclaration()) {
Expand Down
5 changes: 3 additions & 2 deletions ir/irstruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ LLGlobalVariable* IrStruct::getTypeInfoSymbol(bool define) {
// 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.
typeInfo = declareGlobal(aggrdecl->loc, gIR->module,
getTypeInfoStructMemType(), irMangle, false);
typeInfo =
declareGlobal(aggrdecl->loc, gIR->module, getTypeInfoStructMemType(),
irMangle, /*isConstant=*/false);

emitTypeInfoMetadata(typeInfo, aggrdecl->type);
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/druntime