diff --git a/driver/codegenerator.cpp b/driver/codegenerator.cpp index d3e3a262e5..90b22335ae 100644 --- a/driver/codegenerator.cpp +++ b/driver/codegenerator.cpp @@ -216,6 +216,10 @@ void CodeGenerator::finishLLModule(Module *m) { } void CodeGenerator::writeAndFreeLLModule(const char *filename) { + // Issue #1829: make sure all replaced global variables are replaced + // everywhere. + ir_->replaceGlobals(); + ir_->DBuilder.Finalize(); emitLLVMUsedArray(*ir_); diff --git a/gen/declarations.cpp b/gen/declarations.cpp index e0d43ad8da..515a596bfe 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -282,15 +282,15 @@ public: LLConstant *initVal = DtoConstInitializer(decl->loc, decl->type, decl->_init); - setLinkage(lwc, gvar); - - // In case of type mismatch, swap out the variable. - irGlobal->value = irs->setGlobalVarInitializer(gvar, initVal); - - // Now, set the initializer. + // Cache it. assert(!irGlobal->constInit); irGlobal->constInit = initVal; + // Set the initializer, swapping out the variable if the types do not + // match. + setLinkage(lwc, gvar); + irGlobal->value = irs->setGlobalVarInitializer(gvar, initVal); + // Also set up the debug info. irs->DBuilder.EmitGlobalVariable(gvar, decl); } diff --git a/gen/irstate.cpp b/gen/irstate.cpp index 46d544deee..c57a117720 100644 --- a/gen/irstate.cpp +++ b/gen/irstate.cpp @@ -167,7 +167,9 @@ LLConstant *IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar, // Replace all existing uses of globalVar by the bitcast pointer. auto castHelperVar = DtoBitCast(globalHelperVar, globalVar->getType()); globalVar->replaceAllUsesWith(castHelperVar); - globalVar->eraseFromParent(); + + // Register replacement for later occurrences of the original globalVar. + globalsToReplace.emplace_back(globalVar, castHelperVar); // Reset globalVar to the helper variable. globalVar = globalHelperVar; @@ -175,6 +177,15 @@ LLConstant *IRState::setGlobalVarInitializer(LLGlobalVariable *&globalVar, return castHelperVar; } +void IRState::replaceGlobals() { + for (const auto &pair : globalsToReplace) { + pair.first->replaceAllUsesWith(pair.second); + pair.first->eraseFromParent(); + } + + globalsToReplace.resize(0); +} + //////////////////////////////////////////////////////////////////////////////// IRBuilder<> *IRBuilderHelper::operator->() { diff --git a/gen/irstate.h b/gen/irstate.h index 7865f43ea6..1716d09878 100644 --- a/gen/irstate.h +++ b/gen/irstate.h @@ -107,6 +107,11 @@ struct IRAsmBlock { // represents the module struct IRState { +private: + std::vector> + globalsToReplace; + +public: IRState(const char *name, llvm::LLVMContext &context); ~IRState(); @@ -209,6 +214,11 @@ struct IRState { llvm::Constant *setGlobalVarInitializer(llvm::GlobalVariable *&globalVar, llvm::Constant *initializer); + // To be called when finalizing the IR module in order to perform a second + // replacement pass for global variables replaced (and registered) by + // setGlobalVarInitializer(). + void replaceGlobals(); + /// Vector of options passed to the linker as metadata in object file. #if LDC_LLVM_VER >= 306 llvm::SmallVector LinkerMetadataArgs;