diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 7dbb95faaf85..adab7491d27a 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -879,7 +879,7 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) { /// This function returns true if the value is inert. An ObjC ARC runtime call /// taking an inert operand can be safely deleted. -static bool isInertARCValue(Value *V) { +static bool isInertARCValue(Value *V, SmallPtrSet &VisitedPhis) { V = V->stripPointerCasts(); if (IsNullOrUndef(V)) @@ -891,9 +891,12 @@ static bool isInertARCValue(Value *V) { return true; if (auto PN = dyn_cast(V)) { + // Ignore this phi if it has already been discovered. + if (!VisitedPhis.insert(PN).second) + return true; // Look through phis's operands. for (Value *Opnd : PN->incoming_values()) - if (!isInertARCValue(Opnd)) + if (!isInertARCValue(Opnd, VisitedPhis)) return false; return true; } @@ -907,8 +910,10 @@ void ObjCARCOpt::OptimizeIndividualCallImpl( LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n"); // We can delete this call if it takes an inert value. + SmallPtrSet VisitedPhis; + if (IsNoopOnGlobal(Class)) - if (isInertARCValue(Inst->getOperand(0))) { + if (isInertARCValue(Inst->getOperand(0), VisitedPhis)) { if (!Inst->getType()->isVoidTy()) Inst->replaceAllUsesWith(Inst->getOperand(0)); Inst->eraseFromParent(); diff --git a/llvm/test/Transforms/ObjCARC/inert-global.ll b/llvm/test/Transforms/ObjCARC/inert-global.ll index c23d2f98b949..464d78b715e5 100644 --- a/llvm/test/Transforms/ObjCARC/inert-global.ll +++ b/llvm/test/Transforms/ObjCARC/inert-global.ll @@ -8,6 +8,7 @@ @.str = private unnamed_addr constant [4 x i8] c"abc\00", section "__TEXT,__cstring,cstring_literals", align 1 @.str1 = private unnamed_addr constant [4 x i8] c"def\00", section "__TEXT,__cstring,cstring_literals", align 1 @_unnamed_cfstring_ = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i64 3 }, section "__DATA,__cfstring", align 8 #0 +@_unnamed_cfstring_.1 = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i64 3 }, section "__DATA,__cfstring", align 8 #0 @_unnamed_cfstring_wo_attr = private global %struct.__NSConstantString_tag { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str1, i32 0, i32 0), i64 3 }, section "__DATA,__cfstring", align 8 @_NSConcreteGlobalBlock = external global i8* @.str.1 = private unnamed_addr constant [6 x i8] c"v8@?0\00", align 1 @@ -87,6 +88,40 @@ return: ret %0* %phi2 } +; CHECK-LABEL: define void @test_conditional1( +; CHECK-NOT: @llvm.objc +; CHECK: ret void + +define void @test_conditional1(i32 %i) { +entry: + %v0 = add nsw i32 %i, -1 + %c1 = icmp eq i32 %v0, 0 + br i1 %c1, label %while.end, label %while.body + +while.body: + %v1 = phi i32 [ %v5, %if.end ], [ %v0, %entry ] + %v2 = phi i8* [ %v4, %if.end ], [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_.1 to i8*), %entry ] + %v3 = tail call i8* @llvm.objc.retain(i8* %v2) + %cmp = icmp eq i32 %v1, 2 + br i1 %cmp, label %if.then, label %if.end + +if.then: + call void @llvm.objc.release(i8* %v2) + br label %if.end + +if.end: + %v4 = phi i8* [ bitcast (%struct.__NSConstantString_tag* @_unnamed_cfstring_ to i8*), %if.then ], [ %v2, %while.body ] + call void @llvm.objc.release(i8* %v2) + %v5 = add nsw i32 %v1, -1 + %tobool = icmp eq i32 %v5, 0 + br i1 %tobool, label %while.end, label %while.body + +while.end: + %v6 = phi i8* [ null, %entry ], [ %v4, %if.end ] + call void @llvm.objc.release(i8* %v6) + ret void +} + declare void @foo() declare i8* @llvm.objc.retain(i8*) local_unnamed_addr