aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Transforms/IPO/GlobalOpt.cpp
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2013-10-21 17:14:55 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2013-10-21 17:14:55 +0000
commit713cab059ebb67c2f51d8da9d8e57be2b1dcd9c2 (patch)
treec92ff5eac147f406e87b6e2cb43543d6e5b37f11 /lib/Transforms/IPO/GlobalOpt.cpp
parentda39dd30ad3c969be3ac843307d4630807699538 (diff)
downloadexternal_llvm-713cab059ebb67c2f51d8da9d8e57be2b1dcd9c2.zip
external_llvm-713cab059ebb67c2f51d8da9d8e57be2b1dcd9c2.tar.gz
external_llvm-713cab059ebb67c2f51d8da9d8e57be2b1dcd9c2.tar.bz2
Optimize more linkonce_odr values during LTO.
When a linkonce_odr value that is on the dso list is not unnamed_addr we can still look to see if anything is actually using its address. If not, it is safe to hide it. This patch implements that by moving GlobalStatus to Transforms/Utils and using it in Internalize. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193090 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/IPO/GlobalOpt.cpp')
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp210
1 files changed, 2 insertions, 208 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 7b2110f..74ed4e2 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -38,6 +38,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/Utils/GlobalStatus.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
#include <algorithm>
using namespace llvm;
@@ -60,7 +61,6 @@ STATISTIC(NumAliasesRemoved, "Number of global aliases eliminated");
STATISTIC(NumCXXDtorsRemoved, "Number of global C++ destructors removed");
namespace {
- struct GlobalStatus;
struct GlobalOpt : public ModulePass {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetLibraryInfo>();
@@ -99,214 +99,8 @@ ModulePass *llvm::createGlobalOptimizerPass() { return new GlobalOpt(); }
namespace {
-/// As we analyze each global, keep track of some information about it. If we
-/// find out that the address of the global is taken, none of this info will be
-/// accurate.
-struct GlobalStatus {
- /// True if the global's address is used in a comparison.
- bool IsCompared;
- /// True if the global is ever loaded. If the global isn't ever loaded it can
- /// be deleted.
- bool IsLoaded;
- /// Keep track of what stores to the global look like.
- ///
- enum StoredType {
- /// There is no store to this global. It can thus be marked constant.
- NotStored,
-
- /// This global is stored to, but the only thing stored is the constant it
- /// was initialized with. This is only tracked for scalar globals.
- InitializerStored,
-
- /// This global is stored to, but only its initializer and one other value
- /// is ever stored to it. If this global StoredOnce, we track the value
- /// stored to it in StoredOnceValue below. This is only tracked for scalar
- /// globals.
- StoredOnce,
-
- /// This global is stored to by multiple values or something else that we
- /// cannot track.
- Stored
- } StoredType;
-
- /// StoredOnceValue - If only one value (besides the initializer constant) is
- /// ever stored to this global, keep track of what value it is.
- Value *StoredOnceValue;
-
- /// AccessingFunction/HasMultipleAccessingFunctions - These start out
- /// null/false. When the first accessing function is noticed, it is recorded.
- /// When a second different accessing function is noticed,
- /// HasMultipleAccessingFunctions is set to true.
- const Function *AccessingFunction;
- bool HasMultipleAccessingFunctions;
-
- /// HasNonInstructionUser - Set to true if this global has a user that is not
- /// an instruction (e.g. a constant expr or GV initializer).
- bool HasNonInstructionUser;
-
- /// AtomicOrdering - Set to the strongest atomic ordering requirement.
- AtomicOrdering Ordering;
-
- GlobalStatus() : IsCompared(false), IsLoaded(false), StoredType(NotStored),
- StoredOnceValue(0), AccessingFunction(0),
- HasMultipleAccessingFunctions(false),
- HasNonInstructionUser(false), Ordering(NotAtomic) {}
-};
-
-}
-
-/// StrongerOrdering - Return the stronger of the two ordering. If the two
-/// orderings are acquire and release, then return AcquireRelease.
-///
-static AtomicOrdering StrongerOrdering(AtomicOrdering X, AtomicOrdering Y) {
- if (X == Acquire && Y == Release) return AcquireRelease;
- if (Y == Acquire && X == Release) return AcquireRelease;
- return (AtomicOrdering)std::max(X, Y);
-}
-
-/// It is safe to destroy a constant iff it is only used by constants itself.
-/// Note that constants cannot be cyclic, so this test is pretty easy to
-/// implement recursively.
-///
-static bool isSafeToDestroyConstant(const Constant *C) {
- if (isa<GlobalValue>(C))
- return false;
-
- for (Value::const_use_iterator UI = C->use_begin(), E = C->use_end(); UI != E;
- ++UI)
- if (const Constant *CU = dyn_cast<Constant>(*UI)) {
- if (!isSafeToDestroyConstant(CU))
- return false;
- } else
- return false;
- return true;
-}
-
-static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS,
- SmallPtrSet<const PHINode *, 16> &PHIUsers) {
- for (Value::const_use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;
- ++UI) {
- const User *U = *UI;
- if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
- GS.HasNonInstructionUser = true;
-
- // If the result of the constantexpr isn't pointer type, then we won't
- // know to expect it in various places. Just reject early.
- if (!isa<PointerType>(CE->getType())) return true;
-
- if (analyzeGlobalAux(CE, GS, PHIUsers))
- return true;
- } else if (const Instruction *I = dyn_cast<Instruction>(U)) {
- if (!GS.HasMultipleAccessingFunctions) {
- const Function *F = I->getParent()->getParent();
- if (GS.AccessingFunction == 0)
- GS.AccessingFunction = F;
- else if (GS.AccessingFunction != F)
- GS.HasMultipleAccessingFunctions = true;
- }
- if (const LoadInst *LI = dyn_cast<LoadInst>(I)) {
- GS.IsLoaded = true;
- // Don't hack on volatile loads.
- if (LI->isVolatile()) return true;
- GS.Ordering = StrongerOrdering(GS.Ordering, LI->getOrdering());
- } else if (const StoreInst *SI = dyn_cast<StoreInst>(I)) {
- // Don't allow a store OF the address, only stores TO the address.
- if (SI->getOperand(0) == V) return true;
-
- // Don't hack on volatile stores.
- if (SI->isVolatile()) return true;
-
- GS.Ordering = StrongerOrdering(GS.Ordering, SI->getOrdering());
-
- // If this is a direct store to the global (i.e., the global is a scalar
- // value, not an aggregate), keep more specific information about
- // stores.
- if (GS.StoredType != GlobalStatus::Stored) {
- if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(
- SI->getOperand(1))) {
- Value *StoredVal = SI->getOperand(0);
-
- if (Constant *C = dyn_cast<Constant>(StoredVal)) {
- if (C->isThreadDependent()) {
- // The stored value changes between threads; don't track it.
- return true;
- }
- }
-
- if (StoredVal == GV->getInitializer()) {
- if (GS.StoredType < GlobalStatus::InitializerStored)
- GS.StoredType = GlobalStatus::InitializerStored;
- } else if (isa<LoadInst>(StoredVal) &&
- cast<LoadInst>(StoredVal)->getOperand(0) == GV) {
- if (GS.StoredType < GlobalStatus::InitializerStored)
- GS.StoredType = GlobalStatus::InitializerStored;
- } else if (GS.StoredType < GlobalStatus::StoredOnce) {
- GS.StoredType = GlobalStatus::StoredOnce;
- GS.StoredOnceValue = StoredVal;
- } else if (GS.StoredType == GlobalStatus::StoredOnce &&
- GS.StoredOnceValue == StoredVal) {
- // noop.
- } else {
- GS.StoredType = GlobalStatus::Stored;
- }
- } else {
- GS.StoredType = GlobalStatus::Stored;
- }
- }
- } else if (isa<BitCastInst>(I)) {
- if (analyzeGlobalAux(I, GS, PHIUsers))
- return true;
- } else if (isa<GetElementPtrInst>(I)) {
- if (analyzeGlobalAux(I, GS, PHIUsers))
- return true;
- } else if (isa<SelectInst>(I)) {
- if (analyzeGlobalAux(I, GS, PHIUsers))
- return true;
- } else if (const PHINode *PN = dyn_cast<PHINode>(I)) {
- // PHI nodes we can check just like select or GEP instructions, but we
- // have to be careful about infinite recursion.
- if (PHIUsers.insert(PN)) // Not already visited.
- if (analyzeGlobalAux(I, GS, PHIUsers))
- return true;
- } else if (isa<CmpInst>(I)) {
- GS.IsCompared = true;
- } else if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(I)) {
- if (MTI->isVolatile()) return true;
- if (MTI->getArgOperand(0) == V)
- GS.StoredType = GlobalStatus::Stored;
- if (MTI->getArgOperand(1) == V)
- GS.IsLoaded = true;
- } else if (const MemSetInst *MSI = dyn_cast<MemSetInst>(I)) {
- assert(MSI->getArgOperand(0) == V && "Memset only takes one pointer!");
- if (MSI->isVolatile()) return true;
- GS.StoredType = GlobalStatus::Stored;
- } else {
- return true; // Any other non-load instruction might take address!
- }
- } else if (const Constant *C = dyn_cast<Constant>(U)) {
- GS.HasNonInstructionUser = true;
- // We might have a dead and dangling constant hanging off of here.
- if (!isSafeToDestroyConstant(C))
- return true;
- } else {
- GS.HasNonInstructionUser = true;
- // Otherwise must be some other user.
- return true;
- }
- }
-
- return false;
-}
-
-/// Look at all uses of the global and fill in the GlobalStatus
-/// structure. If the global has its address taken, return true to indicate we
-/// can't do anything with it.
-///
-static bool analyzeGlobal(const Value *V, GlobalStatus &GS) {
- SmallPtrSet<const PHINode *, 16> PHIUsers;
- return analyzeGlobalAux(V, GS, PHIUsers);
}
/// isLeakCheckerRoot - Is this global variable possibly used by a leak checker
@@ -1927,7 +1721,7 @@ bool GlobalOpt::ProcessGlobal(GlobalVariable *GV,
GlobalStatus GS;
- if (analyzeGlobal(GV, GS))
+ if (GlobalStatus::analyzeGlobal(GV, GS))
return false;
if (!GS.IsCompared && !GV->hasUnnamedAddr()) {