From e8b3c2e48aa597f08d029ecaed6c1f7ae3a1d111 Mon Sep 17 00:00:00 2001 From: Michael Gottesman Date: Fri, 5 Apr 2013 22:54:32 +0000 Subject: [PATCH] An objc_retain can serve as a use for a different pointer. This is the counterpart to commit r160637, except it performs the action in the bottomup portion of the data flow analysis. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 5 +- test/Transforms/ObjCARC/basic.ll | 95 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 9f59b68d68a..acc32d5eb31 100644 --- a/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -1817,8 +1817,9 @@ ObjCARCOpt::VisitInstructionBottomUp(Instruction *Inst, case S_Retain: llvm_unreachable("bottom-up pointer in retain state!"); } - ANNOTATE_BOTTOMUP(Inst, Arg, OldSeq, S.GetSeq()); - return NestingDetected; + ANNOTATE_BOTTOMUP(Inst, Arg, OldSeq, S.GetSeq()); + // A retain moving bottom up can be a use. + break; } case IC_AutoreleasepoolPop: // Conservatively, clear MyStates for all known pointers. diff --git a/test/Transforms/ObjCARC/basic.ll b/test/Transforms/ObjCARC/basic.ll index 021aebb126f..670e697e522 100644 --- a/test/Transforms/ObjCARC/basic.ll +++ b/test/Transforms/ObjCARC/basic.ll @@ -2607,6 +2607,101 @@ return: ; preds = %if.then, %entry ret i8* %retval } +; An objc_retain can serve as a may-use for a different pointer. +; rdar://11931823 + +; CHECK: define void @test66a( +; CHECK: tail call i8* @objc_retain(i8* %cond) [[NUW]] +; CHECK: tail call void @objc_release(i8* %call) [[NUW]] +; CHECK: tail call i8* @objc_retain(i8* %tmp8) [[NUW]] +; CHECK: tail call void @objc_release(i8* %cond) [[NUW]] +; CHECK: } +define void @test66a(i8* %tmp5, i8* %bar, i1 %tobool, i1 %tobool1, i8* %call) { +entry: + br i1 %tobool, label %cond.true, label %cond.end + +cond.true: + br label %cond.end + +cond.end: ; preds = %cond.true, %entry + %cond = phi i8* [ %tmp5, %cond.true ], [ %call, %entry ] + %tmp7 = tail call i8* @objc_retain(i8* %cond) nounwind + tail call void @objc_release(i8* %call) nounwind + %tmp8 = select i1 %tobool1, i8* %cond, i8* %bar + %tmp9 = tail call i8* @objc_retain(i8* %tmp8) nounwind + tail call void @objc_release(i8* %cond) nounwind + ret void +} + +; CHECK: define void @test66b( +; CHECK: tail call i8* @objc_retain(i8* %cond) [[NUW]] +; CHECK: tail call void @objc_release(i8* %call) [[NUW]] +; CHECK: tail call i8* @objc_retain(i8* %tmp8) [[NUW]] +; CHECK: tail call void @objc_release(i8* %cond) [[NUW]] +; CHECK: } +define void @test66b(i8* %tmp5, i8* %bar, i1 %tobool, i1 %tobool1, i8* %call) { +entry: + br i1 %tobool, label %cond.true, label %cond.end + +cond.true: + br label %cond.end + +cond.end: ; preds = %cond.true, %entry + %cond = phi i8* [ %tmp5, %cond.true ], [ %call, %entry ] + %tmp7 = tail call i8* @objc_retain(i8* %cond) nounwind + tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0 + %tmp8 = select i1 %tobool1, i8* %cond, i8* %bar + %tmp9 = tail call i8* @objc_retain(i8* %tmp8) nounwind + tail call void @objc_release(i8* %cond) nounwind + ret void +} + +; CHECK: define void @test66c( +; CHECK: tail call i8* @objc_retain(i8* %cond) [[NUW]] +; CHECK: tail call void @objc_release(i8* %call) [[NUW]] +; CHECK: tail call i8* @objc_retain(i8* %tmp8) [[NUW]] +; CHECK: tail call void @objc_release(i8* %cond) [[NUW]] +; CHECK: } +define void @test66c(i8* %tmp5, i8* %bar, i1 %tobool, i1 %tobool1, i8* %call) { +entry: + br i1 %tobool, label %cond.true, label %cond.end + +cond.true: + br label %cond.end + +cond.end: ; preds = %cond.true, %entry + %cond = phi i8* [ %tmp5, %cond.true ], [ %call, %entry ] + %tmp7 = tail call i8* @objc_retain(i8* %cond) nounwind + tail call void @objc_release(i8* %call) nounwind + %tmp8 = select i1 %tobool1, i8* %cond, i8* %bar + %tmp9 = tail call i8* @objc_retain(i8* %tmp8) nounwind, !clang.imprecise_release !0 + tail call void @objc_release(i8* %cond) nounwind + ret void +} + +; CHECK: define void @test66d( +; CHECK: tail call i8* @objc_retain(i8* %cond) [[NUW]] +; CHECK: tail call void @objc_release(i8* %call) [[NUW]] +; CHECK: tail call i8* @objc_retain(i8* %tmp8) [[NUW]] +; CHECK: tail call void @objc_release(i8* %cond) [[NUW]] +; CHECK: } +define void @test66d(i8* %tmp5, i8* %bar, i1 %tobool, i1 %tobool1, i8* %call) { +entry: + br i1 %tobool, label %cond.true, label %cond.end + +cond.true: + br label %cond.end + +cond.end: ; preds = %cond.true, %entry + %cond = phi i8* [ %tmp5, %cond.true ], [ %call, %entry ] + %tmp7 = tail call i8* @objc_retain(i8* %cond) nounwind + tail call void @objc_release(i8* %call) nounwind, !clang.imprecise_release !0 + %tmp8 = select i1 %tobool1, i8* %cond, i8* %bar + %tmp9 = tail call i8* @objc_retain(i8* %tmp8) nounwind + tail call void @objc_release(i8* %cond) nounwind, !clang.imprecise_release !0 + ret void +} + ; A few real-world testcases. @.str4 = private unnamed_addr constant [33 x i8] c"-[A z] = { %f, %f, { %f, %f } }\0A\00"