From a6b4079da30ccade414444e89301021cb9485e47 Mon Sep 17 00:00:00 2001 From: James Molloy Date: Thu, 19 Nov 2015 18:04:33 +0000 Subject: [PATCH] [GlobalOpt] Localize some globals that have non-instruction users We currently bail out of global localization if the global has non-instruction users. However, often these can be simple bitcasts or constant-GEPs, which we can easily turn into instructions before localizing. Be a bit more aggressive. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@253584 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/GlobalOpt.cpp | 61 ++++++++++++++++++- .../GlobalOpt/localize-constexpr.ll | 28 +++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/Transforms/GlobalOpt/localize-constexpr.ll diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 812ee243738..083eb5de27a 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -1800,6 +1800,62 @@ bool GlobalOpt::isPointerValueDeadOnEntryToFunction(const Function *F, GlobalVal return true; } +/// C may have non-instruction users. Can all of those users be turned into +/// instructions? +static bool allNonInstructionUsersCanBeMadeInstructions(Constant *C) { + // We don't do this exhaustively. The most common pattern that we really need + // to care about is a constant GEP or constant bitcast - so just looking + // through one single ConstantExpr. + // + // The set of constants that this function returns true for must be able to be + // handled by makeAllConstantUsesInstructions. + for (auto *U : C->users()) { + if (isa(U)) + continue; + if (!isa(U)) + // Non instruction, non-constantexpr user; cannot convert this. + return false; + for (auto *UU : U->users()) + if (!isa(UU)) + // A constantexpr used by another constant. We don't try and recurse any + // further but just bail out at this point. + return false; + } + + return true; +} + +/// C may have non-instruction users, and +/// allNonInstructionUsersCanBeMadeInstructions has returned true. Convert the +/// non-instruction users to instructions. +static void makeAllConstantUsesInstructions(Constant *C) { + SmallVector Users; + for (auto *U : C->users()) { + if (isa(U)) + Users.push_back(cast(U)); + else + // We should never get here; allNonInstructionUsersCanBeMadeInstructions + // should not have returned true for C. + assert( + isa(U) && + "Can't transform non-constantexpr non-instruction to instruction!"); + } + + SmallVector UUsers; + for (auto *U : Users) { + UUsers.clear(); + for (auto *UU : U->users()) + UUsers.push_back(UU); + for (auto *UU : UUsers) { + Instruction *UI = cast(UU); + Instruction *NewU = U->getAsInstruction(); + NewU->insertBefore(UI); + UI->replaceUsesOfWith(U, NewU); + } + U->dropAllReferences(); + } +} + /// Analyze the specified global variable and optimize /// it if possible. If we make a change, return true. bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, @@ -1815,10 +1871,11 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, // // If the global is in different address space, don't bring it to stack. if (!GS.HasMultipleAccessingFunctions && - GS.AccessingFunction && !GS.HasNonInstructionUser && + GS.AccessingFunction && GV->getType()->getElementType()->isSingleValueType() && GV->getType()->getAddressSpace() == 0 && !GV->isExternallyInitialized() && + allNonInstructionUsersCanBeMadeInstructions(GV) && GS.AccessingFunction->doesNotRecurse() && isPointerValueDeadOnEntryToFunction(GS.AccessingFunction, GV) ) { DEBUG(dbgs() << "LOCALIZING GLOBAL: " << *GV << "\n"); @@ -1831,6 +1888,8 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, if (!isa(GV->getInitializer())) new StoreInst(GV->getInitializer(), Alloca, &FirstI); + makeAllConstantUsesInstructions(GV); + GV->replaceAllUsesWith(Alloca); GV->eraseFromParent(); ++NumLocalized; diff --git a/test/Transforms/GlobalOpt/localize-constexpr.ll b/test/Transforms/GlobalOpt/localize-constexpr.ll new file mode 100644 index 00000000000..6754533a50c --- /dev/null +++ b/test/Transforms/GlobalOpt/localize-constexpr.ll @@ -0,0 +1,28 @@ +; RUN: opt -S < %s -globalopt | FileCheck %s + +@G = internal global i32 42 + +define i8 @f() norecurse { +; CHECK-LABEL: @f +; CHECK: alloca +; CHECK-NOT: @G +; CHECK: } + store i32 42, i32* @G + %a = load i8, i8* bitcast (i32* @G to i8*) + ret i8 %a +} + +@H = internal global i32 42 +@Halias = internal alias i32, i32* @H + +; @H can't be localized because @Halias uses it, and @Halias can't be converted to an instruction. +define i8 @g() norecurse { +; CHECK-LABEL: @g +; CHECK-NOT: alloca +; CHECK: @H +; CHECK: } + store i32 42, i32* @H + %a = load i8, i8* bitcast (i32* @H to i8*) + ret i8 %a +} + -- 2.34.1