@@ -87,6 +87,7 @@ STATISTIC(NumNestRemoved , "Number of nest attributes removed");
87
87
STATISTIC (NumAliasesResolved, " Number of global aliases resolved" );
88
88
STATISTIC (NumAliasesRemoved, " Number of global aliases eliminated" );
89
89
STATISTIC (NumCXXDtorsRemoved, " Number of global C++ destructors removed" );
90
+ STATISTIC (NumAtExitRemoved, " Number of atexit handlers removed" );
90
91
STATISTIC (NumInternalFunc, " Number of internal functions" );
91
92
STATISTIC (NumColdCC, " Number of functions marked coldcc" );
92
93
STATISTIC (NumIFuncsResolved, " Number of statically resolved IFuncs" );
@@ -2328,36 +2329,38 @@ OptimizeGlobalAliases(Module &M,
2328
2329
}
2329
2330
2330
2331
static Function *
2331
- FindCXAAtExit (Module &M, function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
2332
+ FindAtExitLibFunc (Module &M,
2333
+ function_ref<TargetLibraryInfo &(Function &)> GetTLI,
2334
+ LibFunc Func) {
2332
2335
// Hack to get a default TLI before we have actual Function.
2333
2336
auto FuncIter = M.begin ();
2334
2337
if (FuncIter == M.end ())
2335
2338
return nullptr ;
2336
2339
auto *TLI = &GetTLI (*FuncIter);
2337
2340
2338
- LibFunc F = LibFunc_cxa_atexit;
2339
- if (!TLI->has (F))
2341
+ if (!TLI->has (Func))
2340
2342
return nullptr ;
2341
2343
2342
- Function *Fn = M.getFunction (TLI->getName (F ));
2344
+ Function *Fn = M.getFunction (TLI->getName (Func ));
2343
2345
if (!Fn)
2344
2346
return nullptr ;
2345
2347
2346
2348
// Now get the actual TLI for Fn.
2347
2349
TLI = &GetTLI (*Fn);
2348
2350
2349
2351
// Make sure that the function has the correct prototype.
2350
- if (!TLI->getLibFunc (*Fn, F) || F != LibFunc_cxa_atexit)
2352
+ LibFunc F;
2353
+ if (!TLI->getLibFunc (*Fn, F) || F != Func)
2351
2354
return nullptr ;
2352
2355
2353
2356
return Fn;
2354
2357
}
2355
2358
2356
- // / Returns whether the given function is an empty C++ destructor and can
2357
- // / therefore be eliminated.
2358
- // / Note that we assume that other optimization passes have already simplified
2359
- // / the code so we simply check for 'ret'.
2360
- static bool cxxDtorIsEmpty (const Function &Fn) {
2359
+ // / Returns whether the given function is an empty C++ destructor or atexit
2360
+ // / handler and can therefore be eliminated. Note that we assume that other
2361
+ // / optimization passes have already simplified the code so we simply check for
2362
+ // / 'ret'.
2363
+ static bool IsEmptyAtExitFunction (const Function &Fn) {
2361
2364
// FIXME: We could eliminate C++ destructors if they're readonly/readnone and
2362
2365
// nounwind, but that doesn't seem worth doing.
2363
2366
if (Fn.isDeclaration ())
@@ -2373,7 +2376,7 @@ static bool cxxDtorIsEmpty(const Function &Fn) {
2373
2376
return false ;
2374
2377
}
2375
2378
2376
- static bool OptimizeEmptyGlobalCXXDtors (Function *CXAAtExitFn) {
2379
+ static bool OptimizeEmptyGlobalAtExitDtors (Function *CXAAtExitFn, bool isCXX ) {
2377
2380
// / Itanium C++ ABI p3.3.5:
2378
2381
// /
2379
2382
// / After constructing a global (or local static) object, that will require
@@ -2386,8 +2389,8 @@ static bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn) {
2386
2389
// / registered before this one. It returns zero if registration is
2387
2390
// / successful, nonzero on failure.
2388
2391
2389
- // This pass will look for calls to __cxa_atexit where the function is trivial
2390
- // and remove them.
2392
+ // This pass will look for calls to __cxa_atexit or atexit where the function
2393
+ // is trivial and remove them.
2391
2394
bool Changed = false ;
2392
2395
2393
2396
for (User *U : llvm::make_early_inc_range (CXAAtExitFn->users ())) {
@@ -2400,14 +2403,17 @@ static bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn) {
2400
2403
2401
2404
Function *DtorFn =
2402
2405
dyn_cast<Function>(CI->getArgOperand (0 )->stripPointerCasts ());
2403
- if (!DtorFn || !cxxDtorIsEmpty (*DtorFn))
2406
+ if (!DtorFn || !IsEmptyAtExitFunction (*DtorFn))
2404
2407
continue ;
2405
2408
2406
2409
// Just remove the call.
2407
2410
CI->replaceAllUsesWith (Constant::getNullValue (CI->getType ()));
2408
2411
CI->eraseFromParent ();
2409
2412
2410
- ++NumCXXDtorsRemoved;
2413
+ if (isCXX)
2414
+ ++NumCXXDtorsRemoved;
2415
+ else
2416
+ ++NumAtExitRemoved;
2411
2417
2412
2418
Changed |= true ;
2413
2419
}
@@ -2525,9 +2531,12 @@ optimizeGlobalsInModule(Module &M, const DataLayout &DL,
2525
2531
2526
2532
// Try to remove trivial global destructors if they are not removed
2527
2533
// already.
2528
- Function *CXAAtExitFn = FindCXAAtExit (M, GetTLI);
2529
- if (CXAAtExitFn)
2530
- LocalChange |= OptimizeEmptyGlobalCXXDtors (CXAAtExitFn);
2534
+ if (Function *CXAAtExitFn =
2535
+ FindAtExitLibFunc (M, GetTLI, LibFunc_cxa_atexit))
2536
+ LocalChange |= OptimizeEmptyGlobalAtExitDtors (CXAAtExitFn, true );
2537
+
2538
+ if (Function *AtExitFn = FindAtExitLibFunc (M, GetTLI, LibFunc_atexit))
2539
+ LocalChange |= OptimizeEmptyGlobalAtExitDtors (AtExitFn, false );
2531
2540
2532
2541
// Optimize IFuncs whose callee's are statically known.
2533
2542
LocalChange |= OptimizeStaticIFuncs (M);
0 commit comments