aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorAlkis Evlogimenos <alkis@evlogimenos.com>2005-02-10 18:36:30 +0000
committerAlkis Evlogimenos <alkis@evlogimenos.com>2005-02-10 18:36:30 +0000
commitf64ea9d1221f52c47fed2ea86a74946c05f224ad (patch)
treefe2f49ec0132d1556844987307f8ed98c6a432a8 /lib/Transforms
parentdb40cf1b5806812b5f9a79a0ce4fb154b3e10752 (diff)
Localize globals if they are only used in main(). This replaces the
global with an alloca, which eventually gets promoted into a register. This enables a lot of other optimizations later on. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@20109 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp40
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index f2c9647e13..59ea4a6f6f 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -38,6 +38,7 @@ namespace {
Statistic<> NumDeleted ("globalopt", "Number of globals deleted");
Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized");
+ Statistic<> NumLocalized("globalopt", "Number of globals localized");
Statistic<> NumShrunkToBool("globalopt",
"Number of global vars shrunk to booleans");
@@ -92,12 +93,20 @@ struct GlobalStatus {
/// 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.
+ Function *AccessingFunction;
+ bool HasMultipleAccessingFunctions;
+
/// isNotSuitableForSRA - Keep track of whether any SRA preventing users of
/// the global exist. Such users include GEP instruction with variable
/// indexes, and non-gep/load/store users like constant expr casts.
bool isNotSuitableForSRA;
GlobalStatus() : isLoaded(false), StoredType(NotStored), StoredOnceValue(0),
+ AccessingFunction(0), HasMultipleAccessingFunctions(false),
isNotSuitableForSRA(false) {}
};
@@ -146,6 +155,13 @@ static bool AnalyzeGlobal(Value *V, GlobalStatus &GS,
}
} else if (Instruction *I = dyn_cast<Instruction>(*UI)) {
+ if (!GS.HasMultipleAccessingFunctions) {
+ Function *F = I->getParent()->getParent();
+ if (GS.AccessingFunction == 0)
+ GS.AccessingFunction = F;
+ else if (GS.AccessingFunction != F)
+ GS.HasMultipleAccessingFunctions = true;
+ }
if (isa<LoadInst>(I)) {
GS.isLoaded = true;
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
@@ -898,6 +914,30 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
}
if (!AnalyzeGlobal(GV, GS, PHIUsers)) {
+ // If this is a first class global and has only one accessing function
+ // and this function is main (which we know is not recursive we can make
+ // this global a local variable) we replace the global with a local alloca
+ // in this function.
+ //
+ // NOTE: It doesn't make sense to promote non first class types since we
+ // are just replacing static memory to stack memory.
+ if (!GS.HasMultipleAccessingFunctions &&
+ GS.AccessingFunction &&
+ GV->getType()->getElementType()->isFirstClassType() &&
+ GS.AccessingFunction->getName() == "main" &&
+ GS.AccessingFunction->hasExternalLinkage()) {
+ DEBUG(std::cerr << "LOCALIZING GLOBAL: " << *GV);
+ Instruction* FirstI = GS.AccessingFunction->getEntryBlock().begin();
+ const Type* ElemTy = GV->getType()->getElementType();
+ AllocaInst* Alloca = new AllocaInst(ElemTy, NULL, GV->getName(), FirstI);
+ if (!isa<UndefValue>(GV->getInitializer()))
+ new StoreInst(GV->getInitializer(), Alloca, FirstI);
+
+ GV->replaceAllUsesWith(Alloca);
+ GV->eraseFromParent();
+ ++NumLocalized;
+ return true;
+ }
// If the global is never loaded (but may be stored to), it is dead.
// Delete it now.
if (!GS.isLoaded) {