GlobalOpt does not treat externally_initialized globals correctly
authorOliver Stannard <oliver.stannard@arm.com>
Mon, 12 Oct 2015 13:20:52 +0000 (13:20 +0000)
committerOliver Stannard <oliver.stannard@arm.com>
Mon, 12 Oct 2015 13:20:52 +0000 (13:20 +0000)
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
lib/Transforms/Utils/GlobalStatus.cpp
test/Transforms/GlobalOpt/externally-initialized.ll [new file with mode: 0644]

index a4b8408b1bf7883c9be60c0bb878b33625f378f9..46a209f232077e61ae83213162a9d97e87cece8d 100644 (file)
@@ -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
index 44b7d25d519a166349ccb5494fa9a0afc3218e06..3893a752503b6b63600edd6ddd6b7b56461054b5 100644 (file)
@@ -49,6 +49,10 @@ bool llvm::isSafeToDestroyConstant(const Constant *C) {
 
 static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
                              SmallPtrSetImpl<const PHINode *> &PhiUsers) {
+  if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(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<ConstantExpr>(UR)) {
diff --git a/test/Transforms/GlobalOpt/externally-initialized.ll b/test/Transforms/GlobalOpt/externally-initialized.ll
new file mode 100644 (file)
index 0000000..c01ba10
--- /dev/null
@@ -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
+}