From 85656d2bc35e5af4b67a4c5e7c1f726788231785 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Thu, 25 Apr 2019 19:42:55 +0000 Subject: [PATCH] [ObjC][ARC] Let ARC optimizer bail out if the number of pointer states it keeps track of becomes too large ARC optimizer does a top-down and a bottom-up traversal of the whole function to pair up retain and release instructions and remove them. This can be expensive if the number of instructions in the function and pointer states it tracks are large since it has to look at each pointer state and determine whether the instruction being visited can potentially use the pointer. This patch adds a command line option that sets a limit to the number of pointers it tracks. rdar://problem/49477063 Differential Revision: https://reviews.llvm.org/D61100 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@359226 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 44 ++++++++++++++++++- test/Transforms/ObjCARC/opt-max-ptr-states.ll | 26 +++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 test/Transforms/ObjCARC/opt-max-ptr-states.ll diff --git a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 34de66f05fb..fa30ee6f72b 100644 --- a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -73,6 +73,11 @@ using namespace llvm::objcarc; #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 @@ 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; @@ -237,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; } @@ -480,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; @@ -1272,6 +1289,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 @@ -1394,6 +1418,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" @@ -1500,13 +1531,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; } @@ -2002,6 +2039,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, diff --git a/test/Transforms/ObjCARC/opt-max-ptr-states.ll b/test/Transforms/ObjCARC/opt-max-ptr-states.ll new file mode 100644 index 00000000000..57a1277c71c --- /dev/null +++ b/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 = !{} -- 2.40.0