From 1cff5e80070eb3cb1c1f24acf0ef039a2cb547c4 Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Mon, 9 Nov 2015 16:47:16 +0000 Subject: [PATCH] GlobalOpt should maintain externally_initialized when splitting aggregates When GlobalOpt splits an internal, global variable with an aggregate type, it should propagate the externally_initialized flag to the newly created globals. This makes the pass safe for our downstream use of this flag, while still allowing some useful optimisations (such as removing dead parts of the split aggregate) to be performed. Differential Revision: http://reviews.llvm.org/D13382 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252490 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/GlobalOpt.cpp | 2 + .../GlobalOpt/externally-initialized-aggregate.ll | 50 ++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/Transforms/GlobalOpt/externally-initialized-aggregate.ll diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 040fd7c8324..01ea896727a 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -497,6 +497,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { In, GV->getName()+"."+Twine(i), GV->getThreadLocalMode(), GV->getType()->getAddressSpace()); + NGV->setExternallyInitialized(GV->isExternallyInitialized()); Globals.insert(GV->getIterator(), NGV); NewGlobals.push_back(NGV); @@ -530,6 +531,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { In, GV->getName()+"."+Twine(i), GV->getThreadLocalMode(), GV->getType()->getAddressSpace()); + NGV->setExternallyInitialized(GV->isExternallyInitialized()); Globals.insert(GV->getIterator(), NGV); NewGlobals.push_back(NGV); diff --git a/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll b/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll new file mode 100644 index 00000000000..b446d24f1fd --- /dev/null +++ b/test/Transforms/GlobalOpt/externally-initialized-aggregate.ll @@ -0,0 +1,50 @@ +; RUN: opt < %s -S -globalopt | FileCheck %s + +; This global is externally_initialized, so if we split it into scalars we +; should keep that flag set on all of the new globals. This will prevent the +; store to @a[0] from being constant propagated to the load in @foo, but will not +; prevent @a[1] from being removed since it is dead. +; CHECK: @a.0 = internal unnamed_addr externally_initialized global i32 undef +; CHECK-NOT @a.1 +@a = internal externally_initialized global [2 x i32] undef, align 4 +; This is the same, but a struct rather than an array. +; CHECK: @b.0 = internal unnamed_addr externally_initialized global i32 undef +; CHECK-NOT @b.1 +@b = internal externally_initialized global {i32, i32} undef, align 4 + +define i32 @foo() { +; CHECK-LABEL: define i32 @foo +entry: +; This load uses the split global, but cannot be constant-propagated away. +; CHECK: %0 = load i32, i32* @a.0 + %0 = load i32, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 0), align 4 + ret i32 %0 +} + +define i32 @bar() { +; CHECK-LABEL: define i32 @bar +entry: +; This load uses the split global, but cannot be constant-propagated away. +; CHECK: %0 = load i32, i32* @b.0 + %0 = load i32, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 0), align 4 + ret i32 %0 +} + +define void @init() { +; CHECK-LABEL: define void @init +entry: +; This store uses the split global, but cannot be constant-propagated away. +; CHECK: store i32 1, i32* @a.0 + store i32 1, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 0), align 4 +; This store can be removed, because the second element of @a is never read. +; CHECK-NOT: store i32 2, i32* @a.1 + store i32 2, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @a, i32 0, i32 1), align 4 + +; This store uses the split global, but cannot be constant-propagated away. +; CHECK: store i32 3, i32* @b.0 + store i32 3, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 0), align 4 +; This store can be removed, because the second element of @b is never read. +; CHECK-NOT: store i32 4, i32* @b.1 + store i32 4, i32* getelementptr inbounds ({i32, i32}, {i32, i32}* @b, i32 0, i32 1), align 4 + ret void +} -- 2.11.0