llvm/lib/Transforms/IPO/PruneEH.cpp
Sanjoy Das c9e3e3cbfd Don't IPO over functions that can be de-refined
Summary:
Fixes PR26774.

If you're aware of the issue, feel free to skip the "Motivation"
section and jump directly to "This patch".

Motivation:

I define "refinement" as discarding behaviors from a program that the
optimizer has license to discard.  So transforming:

```
void f(unsigned x) {
  unsigned t = 5 / x;
  (void)t;
}
```

to

```
void f(unsigned x) { }
```

is refinement, since the behavior went from "if x == 0 then undefined
else nothing" to "nothing" (the optimizer has license to discard
undefined behavior).

Refinement is a fundamental aspect of many mid-level optimizations done
by LLVM.  For instance, transforming `x == (x + 1)` to `false` also
involves refinement since the expression's value went from "if x is
`undef` then { `true` or `false` } else { `false` }" to "`false`" (by
definition, the optimizer has license to fold `undef` to any non-`undef`
value).

Unfortunately, refinement implies that the optimizer cannot assume
that the implementation of a function it can see has all of the
behavior an unoptimized or a differently optimized version of the same
function can have.  This is a problem for functions with comdat
linkage, where a function can be replaced by an unoptimized or a
differently optimized version of the same source level function.

For instance, FunctionAttrs cannot assume a comdat function is
actually `readnone` even if it does not have any loads or stores in
it; since there may have been loads and stores in the "original
function" that were refined out in the currently visible variant, and
at the link step the linker may in fact choose an implementation with
a load or a store.  As an example, consider a function that does two
atomic loads from the same memory location, and writes to memory only
if the two values are not equal.  The optimizer is allowed to refine
this function by first CSE'ing the two loads, and the folding the
comparision to always report that the two values are equal.  Such a
refined variant will look like it is `readonly`.  However, the
unoptimized version of the function can still write to memory (since
the two loads //can// result in different values), and selecting the
unoptimized version at link time will retroactively invalidate
transforms we may have done under the assumption that the function
does not write to memory.

Note: this is not just a problem with atomics or with linking
differently optimized object files.  See PR26774 for more realistic
examples that involved neither.

This patch:

This change introduces a new set of linkage types, predicated as
`GlobalValue::mayBeDerefined` that returns true if the linkage type
allows a function to be replaced by a differently optimized variant at
link time.  It then changes a set of IPO passes to bail out if they see
such a function.

Reviewers: chandlerc, hfinkel, dexonsmith, joker.eph, rnk

Subscribers: mcrosier, llvm-commits

Differential Revision: http://reviews.llvm.org/D18634

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265762 91177308-0d34-0410-b5e6-96231b3b80d8
2016-04-08 00:48:30 +00:00

270 lines
9.8 KiB
C++

//===- PruneEH.cpp - Pass which deletes unused exception handlers ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, turning invoke instructions into calls, iff the callee cannot
// throw an exception, and marking functions 'nounwind' if they cannot throw.
// It implements this as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Transforms/Utils/Local.h"
#include <algorithm>
using namespace llvm;
#define DEBUG_TYPE "prune-eh"
STATISTIC(NumRemoved, "Number of invokes removed");
STATISTIC(NumUnreach, "Number of noreturn calls optimized");
namespace {
struct PruneEH : public CallGraphSCCPass {
static char ID; // Pass identification, replacement for typeid
PruneEH() : CallGraphSCCPass(ID) {
initializePruneEHPass(*PassRegistry::getPassRegistry());
}
// runOnSCC - Analyze the SCC, performing the transformation if possible.
bool runOnSCC(CallGraphSCC &SCC) override;
bool SimplifyFunction(Function *F);
void DeleteBasicBlock(BasicBlock *BB);
};
}
char PruneEH::ID = 0;
INITIALIZE_PASS_BEGIN(PruneEH, "prune-eh",
"Remove unused exception handling info", false, false)
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
INITIALIZE_PASS_END(PruneEH, "prune-eh",
"Remove unused exception handling info", false, false)
Pass *llvm::createPruneEHPass() { return new PruneEH(); }
bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
SmallPtrSet<CallGraphNode *, 8> SCCNodes;
CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
bool MadeChange = false;
// Fill SCCNodes with the elements of the SCC. Used for quickly
// looking up whether a given CallGraphNode is in this SCC.
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
SCCNodes.insert(*I);
// First pass, scan all of the functions in the SCC, simplifying them
// according to what we know.
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
if (Function *F = (*I)->getFunction())
MadeChange |= SimplifyFunction(F);
// Next, check to see if any callees might throw or if there are any external
// functions in this SCC: if so, we cannot prune any functions in this SCC.
// Definitions that are weak and not declared non-throwing might be
// overridden at linktime with something that throws, so assume that.
// If this SCC includes the unwind instruction, we KNOW it throws, so
// obviously the SCC might throw.
//
bool SCCMightUnwind = false, SCCMightReturn = false;
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end();
(!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) {
Function *F = (*I)->getFunction();
if (!F) {
SCCMightUnwind = true;
SCCMightReturn = true;
} else if (F->isDeclaration() || F->isInterposable()) {
// Note: isInterposable (as opposed to hasExactDefinition) is fine above,
// since we're not inferring new attributes here, but only using existing,
// assumed to be correct, function attributes.
SCCMightUnwind |= !F->doesNotThrow();
SCCMightReturn |= !F->doesNotReturn();
} else {
bool CheckUnwind = !SCCMightUnwind && !F->doesNotThrow();
bool CheckReturn = !SCCMightReturn && !F->doesNotReturn();
// Determine if we should scan for InlineAsm in a naked function as it
// is the only way to return without a ReturnInst. Only do this for
// no-inline functions as functions which may be inlined cannot
// meaningfully return via assembly.
bool CheckReturnViaAsm = CheckReturn &&
F->hasFnAttribute(Attribute::Naked) &&
F->hasFnAttribute(Attribute::NoInline);
if (!CheckUnwind && !CheckReturn)
continue;
for (const BasicBlock &BB : *F) {
const TerminatorInst *TI = BB.getTerminator();
if (CheckUnwind && TI->mayThrow()) {
SCCMightUnwind = true;
} else if (CheckReturn && isa<ReturnInst>(TI)) {
SCCMightReturn = true;
}
for (const Instruction &I : BB) {
if ((!CheckUnwind || SCCMightUnwind) &&
(!CheckReturnViaAsm || SCCMightReturn))
break;
// Check to see if this function performs an unwind or calls an
// unwinding function.
if (CheckUnwind && !SCCMightUnwind && I.mayThrow()) {
bool InstMightUnwind = true;
if (const auto *CI = dyn_cast<CallInst>(&I)) {
if (Function *Callee = CI->getCalledFunction()) {
CallGraphNode *CalleeNode = CG[Callee];
// If the callee is outside our current SCC then we may throw
// because it might. If it is inside, do nothing.
if (SCCNodes.count(CalleeNode) > 0)
InstMightUnwind = false;
}
}
SCCMightUnwind |= InstMightUnwind;
}
if (CheckReturnViaAsm && !SCCMightReturn)
if (auto ICS = ImmutableCallSite(&I))
if (const auto *IA = dyn_cast<InlineAsm>(ICS.getCalledValue()))
if (IA->hasSideEffects())
SCCMightReturn = true;
}
if (SCCMightUnwind && SCCMightReturn)
break;
}
}
}
// If the SCC doesn't unwind or doesn't throw, note this fact.
if (!SCCMightUnwind || !SCCMightReturn)
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
Function *F = (*I)->getFunction();
if (!SCCMightUnwind && !F->hasFnAttribute(Attribute::NoUnwind)) {
F->addFnAttr(Attribute::NoUnwind);
MadeChange = true;
}
if (!SCCMightReturn && !F->hasFnAttribute(Attribute::NoReturn)) {
F->addFnAttr(Attribute::NoReturn);
MadeChange = true;
}
}
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
// Convert any invoke instructions to non-throwing functions in this node
// into call instructions with a branch. This makes the exception blocks
// dead.
if (Function *F = (*I)->getFunction())
MadeChange |= SimplifyFunction(F);
}
return MadeChange;
}
// SimplifyFunction - Given information about callees, simplify the specified
// function if we have invokes to non-unwinding functions or code after calls to
// no-return functions.
bool PruneEH::SimplifyFunction(Function *F) {
bool MadeChange = false;
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) {
if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator()))
if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(F)) {
BasicBlock *UnwindBlock = II->getUnwindDest();
removeUnwindEdge(&*BB);
// If the unwind block is now dead, nuke it.
if (pred_empty(UnwindBlock))
DeleteBasicBlock(UnwindBlock); // Delete the new BB.
++NumRemoved;
MadeChange = true;
}
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; )
if (CallInst *CI = dyn_cast<CallInst>(I++))
if (CI->doesNotReturn() && !isa<UnreachableInst>(I)) {
// This call calls a function that cannot return. Insert an
// unreachable instruction after it and simplify the code. Do this
// by splitting the BB, adding the unreachable, then deleting the
// new BB.
BasicBlock *New = BB->splitBasicBlock(I);
// Remove the uncond branch and add an unreachable.
BB->getInstList().pop_back();
new UnreachableInst(BB->getContext(), &*BB);
DeleteBasicBlock(New); // Delete the new BB.
MadeChange = true;
++NumUnreach;
break;
}
}
return MadeChange;
}
/// DeleteBasicBlock - remove the specified basic block from the program,
/// updating the callgraph to reflect any now-obsolete edges due to calls that
/// exist in the BB.
void PruneEH::DeleteBasicBlock(BasicBlock *BB) {
assert(pred_empty(BB) && "BB is not dead!");
CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
Instruction *TokenInst = nullptr;
CallGraphNode *CGN = CG[BB->getParent()];
for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) {
--I;
if (I->getType()->isTokenTy()) {
TokenInst = &*I;
break;
}
if (auto CS = CallSite (&*I)) {
const Function *Callee = CS.getCalledFunction();
if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID()))
CGN->removeCallEdgeFor(CS);
else if (!Callee->isIntrinsic())
CGN->removeCallEdgeFor(CS);
}
if (!I->use_empty())
I->replaceAllUsesWith(UndefValue::get(I->getType()));
}
if (TokenInst) {
if (!isa<TerminatorInst>(TokenInst))
changeToUnreachable(TokenInst->getNextNode(), /*UseLLVMTrap=*/false);
} else {
// Get the list of successors of this block.
std::vector<BasicBlock *> Succs(succ_begin(BB), succ_end(BB));
for (unsigned i = 0, e = Succs.size(); i != e; ++i)
Succs[i]->removePredecessor(BB);
BB->eraseFromParent();
}
}