aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Samsonov <samsonov@google.com>2013-10-07 19:03:24 +0000
committerAlexey Samsonov <samsonov@google.com>2013-10-07 19:03:24 +0000
commit23eb90714bb6a5a7d94a262f439b5bf872733cf1 (patch)
treefb8b8b0bac34c032f839e82a89d22d833cbde1d1
parent243702b95a471ffb7d2374dfad3d7f8b11bee7e7 (diff)
downloadexternal_llvm-23eb90714bb6a5a7d94a262f439b5bf872733cf1.zip
external_llvm-23eb90714bb6a5a7d94a262f439b5bf872733cf1.tar.gz
external_llvm-23eb90714bb6a5a7d94a262f439b5bf872733cf1.tar.bz2
Revert r191834 until we measure the effect of this benchmarks and maybe find a better way to fix it
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@192121 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp59
-rw-r--r--test/Transforms/GlobalOpt/metadata.ll26
2 files changed, 82 insertions, 3 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 3129559..cf15580 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -50,6 +50,7 @@ STATISTIC(NumSubstitute,"Number of globals with initializers stored into them");
STATISTIC(NumDeleted , "Number of globals deleted");
STATISTIC(NumFnDeleted , "Number of functions deleted");
STATISTIC(NumGlobUses , "Number of global uses devirtualized");
+STATISTIC(NumLocalized , "Number of globals localized");
STATISTIC(NumShrunkToBool , "Number of global vars shrunk to booleans");
STATISTIC(NumFastCallFns , "Number of functions converted to fastcc");
STATISTIC(NumCtorsEvaluated, "Number of static ctors evaluated");
@@ -136,12 +137,24 @@ 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.
+ 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), Ordering(NotAtomic) {}
+ GlobalStatus() : isCompared(false), isLoaded(false), StoredType(NotStored),
+ StoredOnceValue(0), AccessingFunction(0),
+ HasMultipleAccessingFunctions(false),
+ HasNonInstructionUser(false), Ordering(NotAtomic) {}
};
}
@@ -182,12 +195,21 @@ static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS,
++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 (AnalyzeGlobal(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.
@@ -264,10 +286,12 @@ static bool AnalyzeGlobal(const Value *V, GlobalStatus &GS,
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 (!SafeToDestroyConstant(C))
return true;
} else {
+ GS.HasNonInstructionUser = true;
// Otherwise must be some other user.
return true;
}
@@ -1914,6 +1938,35 @@ bool GlobalOpt::ProcessGlobal(GlobalVariable *GV,
bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV,
Module::global_iterator &GVI,
const GlobalStatus &GS) {
+ // 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 replace
+ // the global with a local alloca in this function.
+ //
+ // NOTE: It doesn't make sense to promote non single-value types since we
+ // are just replacing static memory to stack memory.
+ //
+ // If the global is in different address space, don't bring it to stack.
+ if (!GS.HasMultipleAccessingFunctions &&
+ GS.AccessingFunction && !GS.HasNonInstructionUser &&
+ GV->getType()->getElementType()->isSingleValueType() &&
+ GS.AccessingFunction->getName() == "main" &&
+ GS.AccessingFunction->hasExternalLinkage() &&
+ GV->getType()->getAddressSpace() == 0) {
+ DEBUG(dbgs() << "LOCALIZING GLOBAL: " << *GV);
+ Instruction &FirstI = const_cast<Instruction&>(*GS.AccessingFunction
+ ->getEntryBlock().begin());
+ Type *ElemTy = GV->getType()->getElementType();
+ // FIXME: Pass Global's alignment when globals have alignment
+ 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) {
diff --git a/test/Transforms/GlobalOpt/metadata.ll b/test/Transforms/GlobalOpt/metadata.ll
new file mode 100644
index 0000000..ecf3f94
--- /dev/null
+++ b/test/Transforms/GlobalOpt/metadata.ll
@@ -0,0 +1,26 @@
+; RUN: opt -S -globalopt < %s | FileCheck %s
+
+; PR6112 - When globalopt does RAUW(@G, %G), the metadata reference should drop
+; to null. Function local metadata that references @G from a different function
+; to that containing %G should likewise drop to null.
+@G = internal global i8** null
+
+define i32 @main(i32 %argc, i8** %argv) {
+; CHECK-LABEL: @main(
+; CHECK: %G = alloca
+ store i8** %argv, i8*** @G
+ ret i32 0
+}
+
+define void @foo(i32 %x) {
+ call void @llvm.foo(metadata !{i8*** @G, i32 %x})
+; CHECK: call void @llvm.foo(metadata !{null, i32 %x})
+ ret void
+}
+
+declare void @llvm.foo(metadata) nounwind readnone
+
+!named = !{!0}
+
+!0 = metadata !{i8*** @G}
+; CHECK: !0 = metadata !{null}