diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h @@ -105,7 +105,8 @@ class BundledRetainClaimRVs { public: - BundledRetainClaimRVs(bool ContractPass) : ContractPass(ContractPass) {} + BundledRetainClaimRVs(bool ContractPass, bool UseMarker) + : ContractPass(ContractPass), UseMarker(UseMarker) {} ~BundledRetainClaimRVs(); /// Insert a retainRV/claimRV call to the normal destination blocks of invokes @@ -155,6 +156,9 @@ DenseMap RVCalls; bool ContractPass; + + /// Indicates whether the target uses a special inline-asm marker. + bool UseMarker; }; } // end namespace objcarc diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp @@ -124,14 +124,19 @@ if (auto *CI = dyn_cast(CB)) CI->setTailCallKind(CallInst::TCK_NoTail); - // Remove the ARC intrinsic function operand from the operand bundle. - OperandBundleDef OB("clang.arc.attachedcall", None); - auto *NewCB = CallBase::Create(CB, OB, CB); - CB->replaceAllUsesWith(NewCB); - CB->eraseFromParent(); - } else { - EraseInstruction(P.first); + if (UseMarker) { + // Remove the retainRV/claimRV function operand from the operand bundle + // to reflect the fact that the backend is responsible for emitting only + // the marker instruction, but not the retainRV/claimRV call. + OperandBundleDef OB("clang.arc.attachedcall", None); + auto *NewCB = CallBase::Create(CB, OB, CB); + CB->replaceAllUsesWith(NewCB); + CB->eraseFromParent(); + } } + + if (!ContractPass || !UseMarker) + EraseInstruction(P.first); } RVCalls.clear(); diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -434,13 +434,21 @@ LLVM_FALLTHROUGH; case ARCInstKind::RetainRV: case ARCInstKind::ClaimRV: { - // If we're compiling for a target which needs a special inline-asm - // marker to do the return value optimization and the retainRV/claimRV call - // wasn't bundled with a call, insert the marker now. + bool IsInstContainedInBundle = BundledInsts->contains(Inst); + + // Return now if the target doesn't need a special inline-asm marker. Return + // true if this is a bundled retainRV/claimRV call, which is going to be + // erased at the end of this pass, to avoid undoing objc-arc-expand and + // replacing uses of the retainRV/claimRV call's argument with its result. if (!RVInstMarker) - return false; + return IsInstContainedInBundle; + + // The target needs a special inline-asm marker. - if (BundledInsts->contains(Inst)) + // We don't have to emit the marker if this is a bundled call since the + // backend is responsible for emitting it. Return false to undo + // objc-arc-expand. + if (IsInstContainedInBundle) return false; BasicBlock::iterator BBI = Inst->getIterator(); @@ -540,7 +548,7 @@ AA = A; DT = D; PA.setAA(A); - BundledRetainClaimRVs BRV(true); + BundledRetainClaimRVs BRV(true, RVInstMarker); BundledInsts = &BRV; std::pair R = BundledInsts->insertAfterInvokes(F, DT); diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -2461,7 +2461,7 @@ return false; Changed = CFGChanged = false; - BundledRetainClaimRVs BRV(false); + BundledRetainClaimRVs BRV(false, objcarc::getRVInstMarker(*F.getParent())); BundledInsts = &BRV; LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName() diff --git a/llvm/test/Transforms/ObjCARC/contract-attached-call-no-marker.ll b/llvm/test/Transforms/ObjCARC/contract-attached-call-no-marker.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/ObjCARC/contract-attached-call-no-marker.ll @@ -0,0 +1,24 @@ +; RUN: opt -objc-arc-contract -S < %s | FileCheck %s +; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s + +; CHECK-LABEL: define void @test0() { +; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] +; CHECK-NEXT: ret void + +define void @test0() { + %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.retainAutoreleasedReturnValue) ] + ret void +} + +; CHECK-LABEL: define void @test1() { +; CHECK: %[[CALL:.*]] = notail call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] +; CHECK-NEXT: ret void + +define void @test1() { + %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i8* (i8*)* @llvm.objc.unsafeClaimAutoreleasedReturnValue) ] + ret void +} + +declare i8* @foo() +declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*) +declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*)