Index: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp =================================================================== --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -73,6 +73,11 @@ #define DEBUG_TYPE "objc-arc-opts" +static cl::opt 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. /// @{ @@ -219,6 +224,10 @@ 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; @@ -237,6 +246,10 @@ 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; } @@ -480,6 +493,10 @@ /// 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; @@ -1272,6 +1289,13 @@ 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 @@ -1394,6 +1418,13 @@ 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" @@ -1500,13 +1531,19 @@ // 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; } @@ -2002,6 +2039,9 @@ // 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, Index: llvm/trunk/test/Transforms/ObjCARC/opt-max-ptr-states.ll =================================================================== --- llvm/trunk/test/Transforms/ObjCARC/opt-max-ptr-states.ll +++ llvm/trunk/test/Transforms/ObjCARC/opt-max-ptr-states.ll @@ -0,0 +1,26 @@ +; RUN: opt -objc-arc -S < %s | FileCheck -check-prefix=ENABLE -check-prefix=CHECK %s +; RUN: opt -objc-arc -arc-opt-max-ptr-states=1 -S < %s | FileCheck -check-prefix=DISABLE -check-prefix=CHECK %s + +@g0 = common global i8* null, align 8 + +; CHECK: call i8* @llvm.objc.retain +; ENABLE-NOT: call i8* @llvm.objc.retain +; DISABLE: call i8* @llvm.objc.retain +; CHECK: call void @llvm.objc.release +; ENABLE-NOT: call void @llvm.objc.release +; DISABLE: call void @llvm.objc.release + +define void @foo0(i8* %a) { + %1 = tail call i8* @llvm.objc.retain(i8* %a) + %2 = tail call i8* @llvm.objc.retain(i8* %a) + %3 = load i8*, i8** @g0, align 8 + store i8* %a, i8** @g0, align 8 + tail call void @llvm.objc.release(i8* %3) + tail call void @llvm.objc.release(i8* %a), !clang.imprecise_release !0 + ret void +} + +declare i8* @llvm.objc.retain(i8*) +declare void @llvm.objc.release(i8*) + +!0 = !{}