forked from OSchip/llvm-project
[GlobalOpt] Simplify __cxa_atexit elimination
cxxDtorIsEmpty checks callers recursively to determine if the __cxa_atexit-registered function is empty, and eliminates the __cxa_atexit call accordingly. This recursive check is unnecessary as redundant instructions and function calls can be removed by early-cse and inliner. In addition, cxxDtorIsEmpty does not mark visited function and it may visit a function exponential times (multiplication principle). llvm-svn: 353603
This commit is contained in:
parent
c5cb2ce905
commit
6e679f8ba5
|
@ -2814,46 +2814,20 @@ static Function *FindCXAAtExit(Module &M, TargetLibraryInfo *TLI) {
|
||||||
/// Returns whether the given function is an empty C++ destructor and can
|
/// Returns whether the given function is an empty C++ destructor and can
|
||||||
/// therefore be eliminated.
|
/// therefore be eliminated.
|
||||||
/// Note that we assume that other optimization passes have already simplified
|
/// Note that we assume that other optimization passes have already simplified
|
||||||
/// the code so we only look for a function with a single basic block, where
|
/// the code so we simply check for 'ret'.
|
||||||
/// the only allowed instructions are 'ret', 'call' to an empty C++ dtor and
|
static bool cxxDtorIsEmpty(const Function &Fn) {
|
||||||
/// other side-effect free instructions.
|
|
||||||
static bool cxxDtorIsEmpty(const Function &Fn,
|
|
||||||
SmallPtrSet<const Function *, 8> &CalledFunctions) {
|
|
||||||
// FIXME: We could eliminate C++ destructors if they're readonly/readnone and
|
// FIXME: We could eliminate C++ destructors if they're readonly/readnone and
|
||||||
// nounwind, but that doesn't seem worth doing.
|
// nounwind, but that doesn't seem worth doing.
|
||||||
if (Fn.isDeclaration())
|
if (Fn.isDeclaration())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (++Fn.begin() != Fn.end())
|
for (auto &I : Fn.getEntryBlock()) {
|
||||||
return false;
|
if (isa<DbgInfoIntrinsic>(I))
|
||||||
|
continue;
|
||||||
const BasicBlock &EntryBlock = Fn.getEntryBlock();
|
if (isa<ReturnInst>(I))
|
||||||
for (BasicBlock::const_iterator I = EntryBlock.begin(), E = EntryBlock.end();
|
return true;
|
||||||
I != E; ++I) {
|
break;
|
||||||
if (const CallInst *CI = dyn_cast<CallInst>(I)) {
|
|
||||||
// Ignore debug intrinsics.
|
|
||||||
if (isa<DbgInfoIntrinsic>(CI))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const Function *CalledFn = CI->getCalledFunction();
|
|
||||||
|
|
||||||
if (!CalledFn)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SmallPtrSet<const Function *, 8> NewCalledFunctions(CalledFunctions);
|
|
||||||
|
|
||||||
// Don't treat recursive functions as empty.
|
|
||||||
if (!NewCalledFunctions.insert(CalledFn).second)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!cxxDtorIsEmpty(*CalledFn, NewCalledFunctions))
|
|
||||||
return false;
|
|
||||||
} else if (isa<ReturnInst>(*I))
|
|
||||||
return true; // We're done.
|
|
||||||
else if (I->mayHaveSideEffects())
|
|
||||||
return false; // Destructor with side effects, bail.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2885,11 +2859,7 @@ static bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn) {
|
||||||
|
|
||||||
Function *DtorFn =
|
Function *DtorFn =
|
||||||
dyn_cast<Function>(CI->getArgOperand(0)->stripPointerCasts());
|
dyn_cast<Function>(CI->getArgOperand(0)->stripPointerCasts());
|
||||||
if (!DtorFn)
|
if (!DtorFn || !cxxDtorIsEmpty(*DtorFn))
|
||||||
continue;
|
|
||||||
|
|
||||||
SmallPtrSet<const Function *, 8> CalledFunctions;
|
|
||||||
if (!cxxDtorIsEmpty(*DtorFn, CalledFunctions))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Just remove the call.
|
// Just remove the call.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
; RUN: opt < %s -globalopt -S | FileCheck %s
|
; RUN: opt < %s -S -passes='cgscc(inline),function(early-cse),globalopt' | FileCheck %s
|
||||||
|
|
||||||
%0 = type { i32, void ()* }
|
%0 = type { i32, void ()* }
|
||||||
%struct.A = type { i8 }
|
%struct.A = type { i8 }
|
||||||
|
|
Loading…
Reference in New Issue