diff options
Diffstat (limited to 'lib/Transforms/ObjCARC/ObjCARCOpts.cpp')
| -rw-r--r-- | lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 80 |
1 files changed, 66 insertions, 14 deletions
diff --git a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 9a02174556fcc..6653ff0bb91a4 100644 --- a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -1,9 +1,8 @@ //===- ObjCARCOpts.cpp - ObjC ARC Optimization ----------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -74,6 +73,11 @@ using namespace llvm::objcarc; #define DEBUG_TYPE "objc-arc-opts" +static cl::opt<unsigned> MaxPtrStates("arc-opt-max-ptr-states", + cl::Hidden, + cl::desc("Maximum number of ptr states the optimizer keeps track of"), + cl::init(4095)); + /// \defgroup ARCUtilities Utility declarations/definitions specific to ARC. /// @{ @@ -220,6 +224,10 @@ namespace { return !PerPtrTopDown.empty(); } + unsigned top_down_ptr_list_size() const { + return std::distance(top_down_ptr_begin(), top_down_ptr_end()); + } + using bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::iterator; using const_bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::const_iterator; @@ -238,6 +246,10 @@ namespace { return !PerPtrBottomUp.empty(); } + unsigned bottom_up_ptr_list_size() const { + return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end()); + } + /// Mark this block as being an entry block, which has one path from the /// entry by definition. void SetAsEntry() { TopDownPathCount = 1; } @@ -481,6 +493,10 @@ namespace { /// A flag indicating whether this optimization pass should run. bool Run; + /// A flag indicating whether the optimization that removes or moves + /// retain/release pairs should be performed. + bool DisableRetainReleasePairing = false; + /// Flags which determine whether each of the interesting runtime functions /// is in fact used in the current function. unsigned UsedInThisFunction; @@ -642,7 +658,7 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) { "Old = " << *RetainRV << "\n"); - Constant *NewDecl = EP.get(ARCRuntimeEntryPointKind::Retain); + Function *NewDecl = EP.get(ARCRuntimeEntryPointKind::Retain); cast<CallInst>(RetainRV)->setCalledFunction(NewDecl); LLVM_DEBUG(dbgs() << "New = " << *RetainRV << "\n"); @@ -691,7 +707,7 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F, << *AutoreleaseRV << "\n"); CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV); - Constant *NewDecl = EP.get(ARCRuntimeEntryPointKind::Autorelease); + Function *NewDecl = EP.get(ARCRuntimeEntryPointKind::Autorelease); AutoreleaseRVCI->setCalledFunction(NewDecl); AutoreleaseRVCI->setTailCall(false); // Never tail call objc_autorelease. Class = ARCInstKind::Autorelease; @@ -744,6 +760,19 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n"); + // Some of the ARC calls can be deleted if their arguments are global + // variables that are inert in ARC. + if (IsNoopOnGlobal(Class)) { + Value *Opnd = Inst->getOperand(0); + if (auto *GV = dyn_cast<GlobalVariable>(Opnd->stripPointerCasts())) + if (GV->hasAttribute("objc_arc_inert")) { + if (!Inst->getType()->isVoidTy()) + Inst->replaceAllUsesWith(Opnd); + Inst->eraseFromParent(); + continue; + } + } + switch (Class) { default: break; @@ -830,7 +859,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { // Create the declaration lazily. LLVMContext &C = Inst->getContext(); - Constant *Decl = EP.get(ARCRuntimeEntryPointKind::Release); + Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release); CallInst *NewCall = CallInst::Create(Decl, Call->getArgOperand(0), "", Call); NewCall->setMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease), @@ -849,7 +878,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { // For functions which can never be passed stack arguments, add // a tail keyword. - if (IsAlwaysTail(Class)) { + if (IsAlwaysTail(Class) && !cast<CallInst>(Inst)->isNoTailCall()) { Changed = true; LLVM_DEBUG( dbgs() << "Adding tail keyword to function since it can never be " @@ -1273,6 +1302,13 @@ bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB, LLVM_DEBUG(dbgs() << " Visiting " << *Inst << "\n"); NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates); + + // Bail out if the number of pointers being tracked becomes too large so + // that this pass can complete in a reasonable amount of time. + if (MyStates.bottom_up_ptr_list_size() > MaxPtrStates) { + DisableRetainReleasePairing = true; + return false; + } } // If there's a predecessor with an invoke, visit the invoke as if it were @@ -1395,6 +1431,13 @@ ObjCARCOpt::VisitTopDown(BasicBlock *BB, LLVM_DEBUG(dbgs() << " Visiting " << Inst << "\n"); NestingDetected |= VisitInstructionTopDown(&Inst, Releases, MyStates); + + // Bail out if the number of pointers being tracked becomes too large so + // that this pass can complete in a reasonable amount of time. + if (MyStates.top_down_ptr_list_size() > MaxPtrStates) { + DisableRetainReleasePairing = true; + return false; + } } LLVM_DEBUG(dbgs() << "\nState Before Checking for CFG Hazards:\n" @@ -1501,13 +1544,19 @@ bool ObjCARCOpt::Visit(Function &F, // Use reverse-postorder on the reverse CFG for bottom-up. bool BottomUpNestingDetected = false; - for (BasicBlock *BB : llvm::reverse(ReverseCFGPostOrder)) + for (BasicBlock *BB : llvm::reverse(ReverseCFGPostOrder)) { BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains); + if (DisableRetainReleasePairing) + return false; + } // Use reverse-postorder for top-down. bool TopDownNestingDetected = false; - for (BasicBlock *BB : llvm::reverse(PostOrder)) + for (BasicBlock *BB : llvm::reverse(PostOrder)) { TopDownNestingDetected |= VisitTopDown(BB, BBStates, Releases); + if (DisableRetainReleasePairing) + return false; + } return TopDownNestingDetected && BottomUpNestingDetected; } @@ -1528,7 +1577,7 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, for (Instruction *InsertPt : ReleasesToMove.ReverseInsertPts) { Value *MyArg = ArgTy == ParamTy ? Arg : new BitCastInst(Arg, ParamTy, "", InsertPt); - Constant *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); + Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt); Call->setDoesNotThrow(); Call->setTailCall(); @@ -1541,7 +1590,7 @@ void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove, for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) { Value *MyArg = ArgTy == ParamTy ? Arg : new BitCastInst(Arg, ParamTy, "", InsertPt); - Constant *Decl = EP.get(ARCRuntimeEntryPointKind::Release); + Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release); CallInst *Call = CallInst::Create(Decl, MyArg, "", InsertPt); // Attach a clang.imprecise_release metadata tag, if appropriate. if (MDNode *M = ReleasesToMove.ReleaseMetadata) @@ -1877,7 +1926,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) { Changed = true; // If the load has a builtin retain, insert a plain retain for it. if (Class == ARCInstKind::LoadWeakRetained) { - Constant *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); + Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); CallInst *CI = CallInst::Create(Decl, EarlierCall, "", Call); CI->setTailCall(); } @@ -1906,7 +1955,7 @@ void ObjCARCOpt::OptimizeWeakCalls(Function &F) { Changed = true; // If the load has a builtin retain, insert a plain retain for it. if (Class == ARCInstKind::LoadWeakRetained) { - Constant *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); + Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain); CallInst *CI = CallInst::Create(Decl, EarlierCall, "", Call); CI->setTailCall(); } @@ -2003,6 +2052,9 @@ bool ObjCARCOpt::OptimizeSequences(Function &F) { // Analyze the CFG of the function, and all instructions. bool NestingDetected = Visit(F, BBStates, Retains, Releases); + if (DisableRetainReleasePairing) + return false; + // Transform. bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains, Releases, |
