From 30430397eaa5d5baf1cc8126b5cd52229ccd62ac Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Mon, 12 Oct 2015 13:20:52 +0000 Subject: [PATCH] GlobalOpt does not treat externally_initialized globals correctly GlobalOpt currently merges stores into the initialisers of internal, externally_initialized globals, but should not do so as the value of the global may change between the initialiser and any code in the module being run. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@250035 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/GlobalOpt.cpp | 2 +- lib/Transforms/Utils/GlobalStatus.cpp | 4 ++ .../GlobalOpt/externally-initialized.ll | 37 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 test/Transforms/GlobalOpt/externally-initialized.ll 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 +}