Allow multiple declarations to share the same mangled name/LLVM global.

This is necessary to enable aliasing compiler-generated
symbols with pragma(mangle, …).

Note that globals for internal use are still directly
created.
This commit is contained in:
David Nadlinger 2013-06-16 00:12:02 +02:00
parent 0305d3bce2
commit acd508945a
9 changed files with 63 additions and 34 deletions

View file

@ -605,7 +605,8 @@ static LLConstant* build_offti_array(ClassDeclaration* cd, LLType* arrayT)
name.append("__OffsetTypeInfos");
// create symbol
llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,DtoInternalLinkage(cd),arrInit,name,gIR->module);
llvm::GlobalVariable* gvar = getOrCreateGlobal(cd->loc, *gIR->module, arrTy,
true,DtoInternalLinkage(cd),arrInit,name);
ptr = DtoBitCast(gvar, getPtrToType(arrTy->getElementType()));
return DtoConstSlice(size, ptr);

View file

@ -98,23 +98,6 @@ void TupleDeclaration::codegen(Ir* p)
/* ================================================================== */
static llvm::GlobalVariable* createGlobal(llvm::Type* type, bool isConst,
llvm::GlobalValue::LinkageTypes linkage, llvm::StringRef name,
bool isThreadLocal)
{
#if LDC_LLVM_VER >= 302
// FIXME: clang uses a command line option for the thread model
const llvm::GlobalVariable::ThreadLocalMode tlsModel =
isThreadLocal ? llvm::GlobalVariable::GeneralDynamicTLSModel
: llvm::GlobalVariable::NotThreadLocal;
return new llvm::GlobalVariable(*gIR->module, type, isConst, linkage,
NULL, name, 0, tlsModel);
#else
return new llvm::GlobalVariable(*gIR->module, type, isConst, linkage,
NULL, name, 0, isThreadLocal);
#endif
}
void VarDeclaration::codegen(Ir* p)
{
Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars());
@ -171,8 +154,9 @@ void VarDeclaration::codegen(Ir* p)
// this->ir.irGlobal->value!), and in case we also do an initializer
// with a different type later, swap it out and replace any existing
// uses with bitcasts to the previous type.
llvm::GlobalVariable* gvar = createGlobal(i1ToI8(DtoType(type)), isLLConst,
llLinkage, llName, isThreadlocal());
llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module,
i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName,
isThreadlocal());
this->ir.irGlobal->value = gvar;
// Check if we are defining or just declaring the global in this module.
@ -184,8 +168,8 @@ void VarDeclaration::codegen(Ir* p)
// In case of type mismatch, swap out the variable.
if (initVal->getType() != gvar->getType()->getElementType())
{
llvm::GlobalVariable* newGvar = createGlobal(
initVal->getType(), isLLConst, llLinkage,
llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc,
*gIR->module, initVal->getType(), isLLConst, llLinkage, 0,
"", // We take on the name of the old global below.
isThreadlocal());

View file

@ -2024,3 +2024,32 @@ llvm::Constant* DtoConstSymbolAddress(const Loc& loc, Declaration* decl)
llvm_unreachable("Taking constant address not implemented.");
}
llvm::GlobalVariable* getOrCreateGlobal(Loc loc, llvm::Module& module,
llvm::Type* type, bool isConstant, llvm::GlobalValue::LinkageTypes linkage,
llvm::Constant* init, llvm::StringRef name, bool isThreadLocal)
{
llvm::GlobalVariable* existing = module.getGlobalVariable(name, true);
if (existing)
{
if (existing->getType()->getElementType() != type)
{
error(loc, "Global variable type does not match previous "
"declaration with same mangled name: %s", name.str().c_str());
fatal();
}
return existing;
}
#if LDC_LLVM_VER >= 302
// FIXME: clang uses a command line option for the thread model
const llvm::GlobalVariable::ThreadLocalMode tlsModel =
isThreadLocal ? llvm::GlobalVariable::GeneralDynamicTLSModel
: llvm::GlobalVariable::NotThreadLocal;
return new llvm::GlobalVariable(module, type, isConstant, linkage,
init, name, 0, tlsModel);
#else
return new llvm::GlobalVariable(module, type, isConstant, linkage,
init, name, 0, isThreadLocal);
#endif
}

View file

@ -226,4 +226,16 @@ LLConstant* toConstantArray(LLType* ct, LLArrayType* at, T* str, size_t len, boo
return LLConstantArray::get(at, vals);
}
/// Tries to create an LLVM global with the given properties. If a variable with
/// the same mangled name already exists, checks if the types match and returns
/// it instead.
///
/// Necessary to support multiple declarations with the same mangled name, as
/// can be the case due to pragma(mangle).
llvm::GlobalVariable* getOrCreateGlobal(Loc loc, llvm::Module& module,
llvm::Type* type, bool isConstant, llvm::GlobalValue::LinkageTypes linkage,
llvm::Constant* init, llvm::StringRef name, bool isThreadLocal = false);
#endif

View file

@ -178,8 +178,9 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
std::string thismrefname = "_D";
thismrefname += gIR->dmodule->mangle();
thismrefname += "11__moduleRefZ";
LLGlobalVariable* thismref = new LLGlobalVariable(*gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname);
LLGlobalVariable* thismref = getOrCreateGlobal(Loc(), *gIR->module,
modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit,
thismrefname);
// make sure _Dmodule_ref is declared
LLConstant* mref = gIR->module->getNamedGlobal("_Dmodule_ref");
LLType *modulerefPtrTy = getPtrToType(modulerefTy);
@ -341,7 +342,8 @@ llvm::GlobalVariable* Module::moduleInfoSymbol()
// declare global
// flags will be modified at runtime so can't make it constant
moduleInfoVar = new llvm::GlobalVariable(*gIR->module, moduleInfoType, false, llvm::GlobalValue::ExternalLinkage, NULL, MIname);
moduleInfoVar = getOrCreateGlobal(loc, *gIR->module, moduleInfoType,
false, llvm::GlobalValue::ExternalLinkage, NULL, MIname);
return moduleInfoVar;
}

View file

@ -86,7 +86,7 @@ void RTTIBuilder::push_void_array(llvm::Constant* CI, Type* valtype, Dsymbol* ma
std::string initname(mangle_sym->mangle());
initname.append(".rtti.voidarr.data");
LLGlobalVariable* G = new llvm::GlobalVariable(
LLGlobalVariable* G = new LLGlobalVariable(
*gIR->module, CI->getType(), true, TYPEINFO_LINKAGE_TYPE, CI, initname);
G->setAlignment(valtype->alignsize());
@ -105,7 +105,7 @@ void RTTIBuilder::push_array(llvm::Constant * CI, uint64_t dim, Type* valtype, D
initname.append(tmpStr);
initname.append(".data");
LLGlobalVariable* G = new llvm::GlobalVariable(
LLGlobalVariable* G = new LLGlobalVariable(
*gIR->module, CI->getType(), true, TYPEINFO_LINKAGE_TYPE, CI, initname);
G->setAlignment(valtype->alignsize());

View file

@ -17,6 +17,7 @@
#include "root.h"
#include "gen/irstate.h"
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/irtype.h"
@ -121,7 +122,7 @@ llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char*
}
LLPointerType* t = g->getType();
return new LLGlobalVariable(*target, t->getElementType(), g->isConstant(),
return getOrCreateGlobal(Loc(), *target, t->getElementType(), g->isConstant(),
g->getLinkage(), NULL, g->getName());
}

View file

@ -64,7 +64,7 @@ LLGlobalVariable * IrAggr::getInitSymbol()
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
init = new llvm::GlobalVariable(
init = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, init_type, true, _linkage, NULL, initname);
// set alignment

View file

@ -56,7 +56,7 @@ LLGlobalVariable * IrAggr::getVtblSymbol()
LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl();
vtbl = new llvm::GlobalVariable(
vtbl = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, vtblTy, true, _linkage, NULL, initname);
return vtbl;
@ -86,7 +86,7 @@ LLGlobalVariable * IrAggr::getClassInfoSymbol()
assert(tc && "invalid ClassInfo type");
// classinfos cannot be constants since they're used as locks for synchronized
classInfo = new llvm::GlobalVariable(
classInfo = getOrCreateGlobal(aggrdecl->loc,
*gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname);
// Generate some metadata on this ClassInfo if it's for a class.
@ -138,7 +138,7 @@ LLGlobalVariable * IrAggr::getInterfaceArraySymbol()
name.append("16__interfaceInfosZ");
llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl);
classInterfacesArray = new llvm::GlobalVariable(*gIR->module,
classInterfacesArray = getOrCreateGlobal(cd->loc, *gIR->module,
array_type, true, _linkage, NULL, name);
return classInterfacesArray;
@ -335,7 +335,7 @@ llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance
mangle.append(b->base->mangle());
mangle.append("6__vtblZ");
llvm::GlobalVariable* GV = new llvm::GlobalVariable(
llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc,
*gIR->module,
vtbl_constant->getType(),
true,