[llvm-commits] [llvm] r127970 - in /llvm/trunk: lib/Transforms/IPO/GlobalOpt.cpp test/Transforms/GlobalOpt/cxx-dtor.ll
Anders Carlsson
andersca at mac.com
Sun Mar 20 10:59:11 PDT 2011
Author: andersca
Date: Sun Mar 20 12:59:11 2011
New Revision: 127970
URL: http://llvm.org/viewvc/llvm-project?rev=127970&view=rev
Log:
Add an optimization to GlobalOpt that eliminates calls to __cxa_atexit, if the function passed is empty.
Added:
llvm/trunk/test/Transforms/GlobalOpt/cxx-dtor.ll
Modified:
llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=127970&r1=127969&r2=127970&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Sun Mar 20 12:59:11 2011
@@ -54,6 +54,7 @@
STATISTIC(NumNestRemoved , "Number of nest attributes removed");
STATISTIC(NumAliasesResolved, "Number of global aliases resolved");
STATISTIC(NumAliasesRemoved, "Number of global aliases eliminated");
+STATISTIC(NumCXXDtorsRemoved, "Number of global C++ destructors removed");
namespace {
struct GlobalStatus;
@@ -77,6 +78,7 @@
bool ProcessInternalGlobal(GlobalVariable *GV,Module::global_iterator &GVI,
const SmallPtrSet<const PHINode*, 16> &PHIUsers,
const GlobalStatus &GS);
+ bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn);
};
}
@@ -2696,12 +2698,106 @@
return Changed;
}
+static Function *FindCXAAtExit(Module &M) {
+ Function *Fn = M.getFunction("__cxa_atexit");
+
+ if (!Fn)
+ return 0;
+
+ const FunctionType *FTy = Fn->getFunctionType();
+
+ // Checking that the function has the right number of parameters and that they
+ // all have pointer types should be enough.
+ if (FTy->getNumParams() != 3 ||
+ !FTy->getParamType(0)->isPointerTy() ||
+ !FTy->getParamType(1)->isPointerTy() ||
+ !FTy->getParamType(2)->isPointerTy())
+ return 0;
+
+ return Fn;
+}
+
+/// cxxDtorIsEmpty - Returns whether the given function is an empty C++
+/// destructor and can therefore be eliminated.
+/// 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 only allowed instructions are 'ret' or 'call' to empty C++ dtor.
+static bool cxxDtorIsEmpty(const Function& Fn) {
+ if (Fn.empty())
+ return true;
+
+ if (++Fn.begin() != Fn.end())
+ return false;
+
+ const BasicBlock &EntryBlock = Fn.getEntryBlock();
+ for (BasicBlock::const_iterator I = EntryBlock.begin(), E = EntryBlock.end();
+ I != E; ++I) {
+ if (const CallInst *CI = dyn_cast<CallInst>(I)) {
+ const Function *CalledFn = CI->getCalledFunction();
+
+ if (!CalledFn)
+ return false;
+
+ if (!cxxDtorIsEmpty(*CalledFn))
+ return false;
+ } else if (isa<ReturnInst>(*I))
+ return true;
+ else
+ return false;
+ }
+
+ return false;
+}
+
+bool GlobalOpt::OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn) {
+ /// Itanium C++ ABI p3.3.5:
+ ///
+ /// After constructing a global (or local static) object, that will require
+ /// destruction on exit, a termination function is registered as follows:
+ ///
+ /// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
+ ///
+ /// This registration, e.g. __cxa_atexit(f,p,d), is intended to cause the
+ /// call f(p) when DSO d is unloaded, before all such termination calls
+ /// registered before this one. It returns zero if registration is
+ /// successful, nonzero on failure.
+
+ // This pass will look for calls to __cxa_atexit where the function is trivial
+ // and remove them.
+ bool Changed = false;
+
+ for (Function::use_iterator I = CXAAtExitFn->use_begin(),
+ E = CXAAtExitFn->use_end(); I != E;) {
+ CallSite CS(*I++);
+ if (!CS.getInstruction())
+ continue;
+
+ Function *DtorFn =
+ dyn_cast<Function>(CS.getArgument(0)->stripPointerCasts());
+ if (!DtorFn)
+ continue;
+
+ if (!cxxDtorIsEmpty(*DtorFn))
+ continue;
+
+ // Just remove the call.
+ CS.getInstruction()->eraseFromParent();
+ ++NumCXXDtorsRemoved;
+
+ Changed |= true;
+ }
+
+ return Changed;
+}
+
bool GlobalOpt::runOnModule(Module &M) {
bool Changed = false;
// Try to find the llvm.globalctors list.
GlobalVariable *GlobalCtors = FindGlobalCtors(M);
+ Function *CXAAtExitFn = FindCXAAtExit(M);
+
bool LocalChange = true;
while (LocalChange) {
LocalChange = false;
@@ -2718,6 +2814,11 @@
// Resolve aliases, when possible.
LocalChange |= OptimizeGlobalAliases(M);
+
+ // Try to remove trivial global destructors.
+ if (CXAAtExitFn)
+ LocalChange |= OptimizeEmptyGlobalCXXDtors(CXAAtExitFn);
+
Changed |= LocalChange;
}
Added: llvm/trunk/test/Transforms/GlobalOpt/cxx-dtor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GlobalOpt/cxx-dtor.ll?rev=127970&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GlobalOpt/cxx-dtor.ll (added)
+++ llvm/trunk/test/Transforms/GlobalOpt/cxx-dtor.ll Sun Mar 20 12:59:11 2011
@@ -0,0 +1,31 @@
+; RUN: opt < %s -globalopt -S | FileCheck %s
+
+%0 = type { i32, void ()* }
+%struct.A = type { i8 }
+
+ at a = global %struct.A zeroinitializer, align 1
+ at __dso_handle = external global i8*
+ at llvm.global_ctors = appending global [1 x %0] [%0 { i32 65535, void ()* @_GLOBAL__I_a }]
+
+; CHECK-NOT: call i32 @__cxa_atexit
+
+define internal void @__cxx_global_var_init() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
+ %1 = call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
+ ret void
+}
+
+define linkonce_odr void @_ZN1AD1Ev(%struct.A* %this) nounwind align 2 {
+ call void @_ZN1AD2Ev(%struct.A* %this)
+ ret void
+}
+
+declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
+
+define linkonce_odr void @_ZN1AD2Ev(%struct.A* %this) nounwind align 2 {
+ ret void
+}
+
+define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
+ call void @__cxx_global_var_init()
+ ret void
+}
More information about the llvm-commits
mailing list