diff --git a/gen/classes.cpp b/gen/classes.cpp index 3f14da5a75..d50462116c 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -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); diff --git a/gen/declarations.cpp b/gen/declarations.cpp index 237bbc95e9..dcb710bbea 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -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()); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 4d71b928ce..53198c2909 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -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 +} diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index bf8e561e26..a23b2a55eb 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -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 diff --git a/gen/module.cpp b/gen/module.cpp index 693ca36bcf..f8151904bc 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -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; } diff --git a/gen/rttibuilder.cpp b/gen/rttibuilder.cpp index bc182b5f5c..79f1c9bfea 100644 --- a/gen/rttibuilder.cpp +++ b/gen/rttibuilder.cpp @@ -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()); diff --git a/gen/runtime.cpp b/gen/runtime.cpp index a0ccd41cc6..6d49356ff2 100644 --- a/gen/runtime.cpp +++ b/gen/runtime.cpp @@ -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,8 +122,8 @@ llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char* } LLPointerType* t = g->getType(); - return new LLGlobalVariable(*target, t->getElementType(), g->isConstant(), - g->getLinkage(), NULL, g->getName()); + return getOrCreateGlobal(Loc(), *target, t->getElementType(), g->isConstant(), + g->getLinkage(), NULL, g->getName()); } ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp index 5e5acf23f5..ce4bdc9d61 100644 --- a/ir/iraggr.cpp +++ b/ir/iraggr.cpp @@ -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 diff --git a/ir/irclass.cpp b/ir/irclass.cpp index b280a80d47..755d5048b7 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -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,