diff options
author | Eli Bendersky <eliben@chromium.org> | 2013-07-09 15:29:37 -0700 |
---|---|---|
committer | Eli Bendersky <eliben@chromium.org> | 2013-07-09 15:29:37 -0700 |
commit | 299c82a21a9fd010534ea59c46ae0b88c21f25b7 (patch) | |
tree | ef0249a8e74e2d1719330fd58bf0df16a3bf5c09 | |
parent | af49991972c1ca2364cd7377f4781893ffb3ffc5 (diff) |
Make GlobalOpt's GV-by-alloca replacement work for PNaCl.
GlobalOpt currently assumes only an external "main" is the "real main".
This is no longer the case for PNaCl, where we internalize "main". Make
the test more strict and PNaCl specific by checking that "main" is just
used once - in a call from "_start", but does not have to be external.
Note that this also addresses a possible bug in the optimization for C
code, since C does not guarantee that main is not recursive.
This CL's purpose is to address a SPEC performance regression - 10% in
183.equake. The regression appeared after our ABI change that made 'main'
internal, which disabled this particular optimization. The CL addresses
this by re-enabling the optimization and also being more C-standard
conforming.
BUG=None
Review URL: https://codereview.chromium.org/18615015
-rw-r--r-- | lib/Transforms/IPO/GlobalOpt.cpp | 25 | ||||
-rw-r--r-- | test/NaCl/Localmods/lit.local.cfg | 1 | ||||
-rw-r--r-- | test/NaCl/Localmods/test-globalopt-main.ll | 37 | ||||
-rw-r--r-- | test/Transforms/GlobalOpt/metadata.ll | 4 |
4 files changed, 65 insertions, 2 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 2b9d6670ca..700d0dfb5c 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -83,6 +83,9 @@ namespace { const GlobalStatus &GS); bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn); + // @LOCALMOD: see usage below + bool IsUserEntryPointMain(const Function *Func); + DataLayout *TD; TargetLibraryInfo *TLI; }; @@ -1933,6 +1936,17 @@ bool GlobalOpt::ProcessGlobal(GlobalVariable *GV, return ProcessInternalGlobal(GV, GVI, PHIUsers, GS); } +bool GlobalOpt::IsUserEntryPointMain(const Function *Func) { // @LOCALMOD + if (Func->hasOneUse() && Func->getName() == "main") { + const User *FuncUser = Func->use_back(); + if (const CallInst *CallUser = dyn_cast<CallInst>(FuncUser)) { + const Function *Caller = CallUser->getParent()->getParent(); + return Caller->getName() == "_start"; + } + } + return false; +} + /// ProcessInternalGlobal - Analyze the specified global variable and optimize /// it if possible. If we make a change, return true. bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, @@ -1951,9 +1965,16 @@ bool GlobalOpt::ProcessInternalGlobal(GlobalVariable *GV, if (!GS.HasMultipleAccessingFunctions && GS.AccessingFunction && !GS.HasNonInstructionUser && GV->getType()->getElementType()->isSingleValueType() && - GS.AccessingFunction->getName() == "main" && - GS.AccessingFunction->hasExternalLinkage() && + // @LOCALMOD-BEGIN + // The upstream LLVM is looking for an external "main" here. Since in + // stable PNaCl bitcode, "main" is internal, we're using a different + // heuristic. We're looking for a "main" that is only used in a single + // place -- a call from "_start". + // TODO: figure out a more proper solution upstream and merge that in. + IsUserEntryPointMain(GS.AccessingFunction) && + // @LOCALMOD-END GV->getType()->getAddressSpace() == 0) { + DEBUG(dbgs() << "LOCALIZING GLOBAL: " << *GV); Instruction &FirstI = const_cast<Instruction&>(*GS.AccessingFunction ->getEntryBlock().begin()); diff --git a/test/NaCl/Localmods/lit.local.cfg b/test/NaCl/Localmods/lit.local.cfg new file mode 100644 index 0000000000..c6106e4746 --- /dev/null +++ b/test/NaCl/Localmods/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.ll'] diff --git a/test/NaCl/Localmods/test-globalopt-main.ll b/test/NaCl/Localmods/test-globalopt-main.ll new file mode 100644 index 0000000000..90d0e3193c --- /dev/null +++ b/test/NaCl/Localmods/test-globalopt-main.ll @@ -0,0 +1,37 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s + +; Check that our LOCALMOD for the GlobalOpt optimization is working properly. +; The user code entry point is a function named main that has a single user: +; a call from _start. +; @globchar can be folded into an alloca inside @main, and the global can be +; deleted. + +@globchar = internal global i8* null, align 8 +; CHECK-NOT: @globchar = internal global + +define internal i32 @main(i32 %argc, i8** %argv) { + ; CHECK: @main(i32 +entry: + ; CHECK: %globchar = alloca i8* + %argc.addr = alloca i32, align 4 + %argv.addr = alloca i8**, align 8 + store i32 %argc, i32* %argc.addr, align 4 + store i8** %argv, i8*** %argv.addr, align 8 + %0 = load i8*** %argv.addr, align 8 + %arrayidx = getelementptr inbounds i8** %0, i64 0 + %1 = load i8** %arrayidx, align 8 + store i8* %1, i8** @globchar, align 8 + %2 = load i8** @globchar, align 8 + %arrayidx1 = getelementptr inbounds i8* %2, i64 1 + %3 = load i8* %arrayidx1, align 1 + call void @somefunc(i8 signext %3) + ret i32 0 +} + +define i32 @_start(i32 %argc, i8** %argv) { + %rv = call i32 @main(i32 %argc, i8** %argv) + ret i32 %rv +} + +declare void @somefunc(i8 signext) + diff --git a/test/Transforms/GlobalOpt/metadata.ll b/test/Transforms/GlobalOpt/metadata.ll index 730e2b0802..366f61f083 100644 --- a/test/Transforms/GlobalOpt/metadata.ll +++ b/test/Transforms/GlobalOpt/metadata.ll @@ -1,4 +1,8 @@ ; RUN: opt -S -globalopt < %s | FileCheck %s +; LOCALMOD: We've changed the heuristic used to detect "main" for the GlobalOpt +; optimization of replacing globals with allocas. Revert this when fixed +; properly upstream (http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-July/063580.html) +; XFAIL: * ; PR6112 - When globalopt does RAUW(@G, %G), the metadata reference should drop ; to null. Function local metadata that references @G from a different function |