From 0860d0ba2f14e62572434cd159a086f91b20895d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 16 Jun 2011 20:57:14 +0000 Subject: [PATCH] Fix ARCOpt to insert releases on both successors of an invoke rather than trying to insert them immediately after the invoke. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@133188 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/ObjCARC.cpp | 37 ++++++++++++----- test/Transforms/ObjCARC/invoke.ll | 67 +++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 test/Transforms/ObjCARC/invoke.ll diff --git a/lib/Transforms/Scalar/ObjCARC.cpp b/lib/Transforms/Scalar/ObjCARC.cpp index e65e2853c2a..6cd35e5c9e7 100644 --- a/lib/Transforms/Scalar/ObjCARC.cpp +++ b/lib/Transforms/Scalar/ObjCARC.cpp @@ -2550,16 +2550,33 @@ void ObjCARCOpt::MoveCalls(Value *Arg, for (SmallPtrSet::const_iterator PI = RetainsToMove.ReverseInsertPts.begin(), PE = RetainsToMove.ReverseInsertPts.end(); PI != PE; ++PI) { - Instruction *InsertPt = llvm::next(BasicBlock::iterator(*PI)); - Value *MyArg = ArgTy == ParamTy ? Arg : - new BitCastInst(Arg, ParamTy, "", InsertPt); - CallInst *Call = CallInst::Create(ReleaseFunc, MyArg, "", InsertPt); - // Attach a clang.imprecise_release metadata tag, if appropriate. - if (MDNode *M = ReleasesToMove.ReleaseMetadata) - Call->setMetadata(ImpreciseReleaseMDKind, M); - Call->setDoesNotThrow(); - if (ReleasesToMove.IsTailCallRelease) - Call->setTailCall(); + Instruction *LastUse = *PI; + Instruction *InsertPts[] = { 0, 0, 0 }; + if (InvokeInst *II = dyn_cast(LastUse)) { + // We can't insert code immediately after an invoke instruction, so + // insert code at the beginning of both successor blocks instead. + // The invoke's return value isn't available in the unwind block, + // but our releases will never depend on it, because they must be + // paired with retains from before the invoke. + InsertPts[0] = II->getNormalDest()->getFirstNonPHI(); + InsertPts[1] = II->getUnwindDest()->getFirstNonPHI(); + } else { + // Insert code immediately after the last use. + InsertPts[0] = llvm::next(BasicBlock::iterator(LastUse)); + } + + for (Instruction **I = InsertPts; *I; ++I) { + Instruction *InsertPt = *I; + Value *MyArg = ArgTy == ParamTy ? Arg : + new BitCastInst(Arg, ParamTy, "", InsertPt); + CallInst *Call = CallInst::Create(ReleaseFunc, MyArg, "", InsertPt); + // Attach a clang.imprecise_release metadata tag, if appropriate. + if (MDNode *M = ReleasesToMove.ReleaseMetadata) + Call->setMetadata(ImpreciseReleaseMDKind, M); + Call->setDoesNotThrow(); + if (ReleasesToMove.IsTailCallRelease) + Call->setTailCall(); + } } // Delete the original retain and release calls. diff --git a/test/Transforms/ObjCARC/invoke.ll b/test/Transforms/ObjCARC/invoke.ll new file mode 100644 index 00000000000..a1b87d230bd --- /dev/null +++ b/test/Transforms/ObjCARC/invoke.ll @@ -0,0 +1,67 @@ +; RUN: opt -S -objc-arc < %s | FileCheck %s + +declare i8* @objc_retain(i8*) +declare void @objc_release(i8*) +declare i8* @objc_msgSend(i8*, i8*, ...) +declare void @use_pointer(i8*) +declare void @callee() + +; ARCOpt shouldn't try to move the releases to the block containing the invoke. + +; CHECK: define void @test0( +; CHECK: invoke.cont: +; CHECK: call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 +; CHECK: ret void +; CHECK: lpad: +; CHECK: call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 +; CHECK: ret void +define void @test0(i8* %zipFile) { +entry: + call i8* @objc_retain(i8* %zipFile) nounwind + call void @use_pointer(i8* %zipFile) + invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 + ret void + +lpad: ; preds = %entry + call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 + ret void +} + +; ARCOpt should move the release before the callee calls. + +; CHECK: define void @test1( +; CHECK: invoke.cont: +; CHECK: call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 +; CHECK: call void @callee() +; CHECK: br label %done +; CHECK: lpad: +; CHECK: call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 +; CHECK: call void @callee() +; CHECK: br label %done +; CHECK: done: +; CHECK-NEXT: ret void +define void @test1(i8* %zipFile) { +entry: + call i8* @objc_retain(i8* %zipFile) nounwind + call void @use_pointer(i8* %zipFile) + invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*)*)(i8* %zipFile) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + call void @callee() + br label %done + +lpad: ; preds = %entry + call void @callee() + br label %done + +done: + call void @objc_release(i8* %zipFile) nounwind, !clang.imprecise_release !0 + ret void +} + +!0 = metadata !{} -- 2.34.1