Index: lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- lib/Transforms/IPO/GlobalOpt.cpp +++ lib/Transforms/IPO/GlobalOpt.cpp @@ -1800,6 +1800,63 @@ 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!"); + } + + for (auto *U : Users) { + SmallVector UUsers; + for (auto *UU : U->users()) + UUsers.push_back(UU); + for (auto *UU : UUsers) { + assert(!isa(UU)); + + 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 +1872,11 @@ // // 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 +1889,8 @@ if (!isa(GV->getInitializer())) new StoreInst(GV->getInitializer(), Alloca, &FirstI); + makeAllConstantUsesInstructions(GV); + GV->replaceAllUsesWith(Alloca); GV->eraseFromParent(); ++NumLocalized; Index: test/Transforms/GlobalOpt/localize-constexpr.ll =================================================================== --- /dev/null +++ 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 +} +