diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index a4b8408b1bf..46a209f2320 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -1804,7 +1804,7 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, GVI = FirstNewGV; // Don't skip the newly produced globals! return true; } - } else if (GS.StoredType == GlobalStatus::StoredOnce) { + } else if (GS.StoredType == GlobalStatus::StoredOnce && GS.StoredOnceValue) { // If the initial value for the global was an undef value, and if only // one other value was stored into it, we can just change the // initializer to be the stored value, then delete all stores to the diff --git a/lib/Transforms/Utils/GlobalStatus.cpp b/lib/Transforms/Utils/GlobalStatus.cpp index 44b7d25d519..3893a752503 100644 --- a/lib/Transforms/Utils/GlobalStatus.cpp +++ b/lib/Transforms/Utils/GlobalStatus.cpp @@ -49,6 +49,10 @@ bool llvm::isSafeToDestroyConstant(const Constant *C) { static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS, SmallPtrSetImpl &PhiUsers) { + if (const GlobalVariable *GV = dyn_cast(V)) + if (GV->isExternallyInitialized()) + GS.StoredType = GlobalStatus::StoredOnce; + for (const Use &U : V->uses()) { const User *UR = U.getUser(); if (const ConstantExpr *CE = dyn_cast(UR)) { diff --git a/test/Transforms/GlobalOpt/externally-initialized.ll b/test/Transforms/GlobalOpt/externally-initialized.ll new file mode 100644 index 00000000000..c01ba10f49c --- /dev/null +++ b/test/Transforms/GlobalOpt/externally-initialized.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +; This global is externally_initialized, which may modify the value between +; it's static initializer and any code in this module being run, so the only +; write to it cannot be merged into the static initialiser. +; CHECK: @a = internal unnamed_addr externally_initialized global i32 undef +@a = internal externally_initialized global i32 undef + +; This global is stored to by the external initialization, so cannot be +; constant-propagated and removed, despite the fact that there are no writes +; to it. +; CHECK: @b = internal unnamed_addr externally_initialized global i32 undef +@b = internal externally_initialized global i32 undef + + +define void @foo() { +; CHECK-LABEL: foo +entry: +; CHECK: store i32 42, i32* @a + store i32 42, i32* @a + ret void +} +define i32 @bar() { +; CHECK-LABEL: bar +entry: +; CHECK: %val = load i32, i32* @a + %val = load i32, i32* @a + ret i32 %val +} + +define i32 @baz() { +; CHECK-LABEL: baz +entry: +; CHECK: %val = load i32, i32* @b + %val = load i32, i32* @b + ret i32 %val +}