[llvm] 1900503 - [ObjC][ARC] Use operand bundle 'clang.arc.attachedcall' instead of

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 4 16:20:03 PST 2021


Please if at all possible make smaller/incremental patches.

In any case, somewhere in all this, Analysis/ObjCARCUtils.h was introduced
and included from llvm/IR, violating library layering. (Analysis depends on
IR, not the other way around)

So I moved this header into IR (please fix otherwise if there's a better
answer - but the utilities looked generally applicable to IR) and also
fixed a couple of implementation bugs ("LIB" in the header guard macro - we
don't usually do that, and the use of non-member "static" in the header -
that can lead to ODR violations). In git commit
a2a55def354df2cd4de0b1cbd6b2795a07e6905a

On Thu, Mar 4, 2021 at 11:23 AM Akira Hatanaka via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

>
> Author: Akira Hatanaka
> Date: 2021-03-04T11:22:30-08:00
> New Revision: 1900503595cbb84a4c6e140a9ba1a2c574c0586d
>
> URL:
> https://github.com/llvm/llvm-project/commit/1900503595cbb84a4c6e140a9ba1a2c574c0586d
> DIFF:
> https://github.com/llvm/llvm-project/commit/1900503595cbb84a4c6e140a9ba1a2c574c0586d.diff
>
> LOG: [ObjC][ARC] Use operand bundle 'clang.arc.attachedcall' instead of
> explicitly emitting retainRV or claimRV calls in the IR
>
> This reapplies ed4718eccb12bd42214ca4fb17d196d49561c0c7, which was reverted
> because it was causing a miscompile. The bug that was causing the
> miscompile
> has been fixed in 75805dce5ff874676f3559c069fcd6737838f5c0.
>
> Original commit message:
>
> Background:
>
> This fixes a longstanding problem where llvm breaks ARC's autorelease
> optimization (see the link below) by separating calls from the marker
> instructions or retainRV/claimRV calls. The backend changes are in
> https://reviews.llvm.org/D92569.
>
>
> https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-runtime-objc-autoreleasereturnvalue
>
> What this patch does to fix the problem:
>
> - The front-end adds operand bundle "clang.arc.attachedcall" to calls,
>   which indicates the call is implicitly followed by a marker
>   instruction and an implicit retainRV/claimRV call that consumes the
>   call result. In addition, it emits a call to
>   @llvm.objc.clang.arc.noop.use, which consumes the call result, to
>   prevent the middle-end passes from changing the return type of the
>   called function. This is currently done only when the target is arm64
>   and the optimization level is higher than -O0.
>
> - ARC optimizer temporarily emits retainRV/claimRV calls after the calls
>   with the operand bundle in the IR and removes the inserted calls after
>   processing the function.
>
> - ARC contract pass emits retainRV/claimRV calls after the call with the
>   operand bundle. It doesn't remove the operand bundle on the call since
>   the backend needs it to emit the marker instruction. The retainRV and
>   claimRV calls are emitted late in the pipeline to prevent optimization
>   passes from transforming the IR in a way that makes it harder for the
>   ARC middle-end passes to figure out the def-use relationship between
>   the call and the retainRV/claimRV calls (which is the cause of
>   PR31925).
>
> - The function inliner removes an autoreleaseRV call in the callee if
>   nothing in the callee prevents it from being paired up with the
>   retainRV/claimRV call in the caller. It then inserts a release call if
>   claimRV is attached to the call since autoreleaseRV+claimRV is
>   equivalent to a release. If it cannot find an autoreleaseRV call, it
>   tries to transfer the operand bundle to a function call in the callee.
>   This is important since the ARC optimizer can remove the autoreleaseRV
>   returning the callee result, which makes it impossible to pair it up
>   with the retainRV/claimRV call in the caller. If that fails, it simply
>   emits a retain call in the IR if retainRV is attached to the call and
>   does nothing if claimRV is attached to it.
>
> - SCCP refrains from replacing the return value of a call with a
>   constant value if the call has the operand bundle. This ensures the
>   call always has at least one user (the call to
>   @llvm.objc.clang.arc.noop.use).
>
> - This patch also fixes a bug in replaceUsesOfNonProtoConstant where
>   multiple operand bundles of the same kind were being added to a call.
>
> Future work:
>
> - Use the operand bundle on x86-64.
>
> - Fix the auto upgrader to convert call+retainRV/claimRV pairs into
>   calls with the operand bundles.
>
> rdar://71443534
>
> Differential Revision: https://reviews.llvm.org/D92808
>
> Added:
>     clang/test/CodeGenObjC/arc-rv-attr.m
>     llvm/include/llvm/Analysis/ObjCARCUtil.h
>     llvm/test/Transforms/Inline/inline-retainRV-call.ll
>     llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
>     llvm/test/Transforms/SCCP/clang-arc-rv.ll
>
> Modified:
>     clang/lib/CodeGen/CGObjC.cpp
>     clang/lib/CodeGen/CodeGenFunction.h
>     clang/lib/CodeGen/CodeGenModule.cpp
>     clang/lib/CodeGen/CodeGenModule.h
>     clang/test/CodeGenObjC/arc-unsafeclaim.m
>     llvm/docs/LangRef.rst
>     llvm/include/llvm/IR/InstrTypes.h
>     llvm/include/llvm/IR/Intrinsics.td
>     llvm/include/llvm/IR/LLVMContext.h
>     llvm/lib/Analysis/ObjCARCInstKind.cpp
>     llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
>     llvm/lib/IR/AutoUpgrade.cpp
>     llvm/lib/IR/Instructions.cpp
>     llvm/lib/IR/LLVMContext.cpp
>     llvm/lib/IR/Verifier.cpp
>     llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
>     llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
>     llvm/lib/Transforms/ObjCARC/ObjCARC.cpp
>     llvm/lib/Transforms/ObjCARC/ObjCARC.h
>     llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
>     llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
>     llvm/lib/Transforms/ObjCARC/PtrState.cpp
>     llvm/lib/Transforms/ObjCARC/PtrState.h
>     llvm/lib/Transforms/Scalar/SCCP.cpp
>     llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
>     llvm/lib/Transforms/Utils/InlineFunction.cpp
>     llvm/test/Bitcode/operand-bundles-bc-analyzer.ll
>     llvm/test/CodeGen/AArch64/call-rv-marker.ll
>     llvm/test/Transforms/DeadArgElim/deadretval.ll
>     llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll
>     llvm/test/Transforms/ObjCARC/contract.ll
>     llvm/test/Transforms/ObjCARC/intrinsic-use.ll
>     llvm/test/Transforms/ObjCARC/rv.ll
>     llvm/test/Transforms/TailCallElim/deopt-bundle.ll
>     llvm/test/Verifier/operand-bundles.ll
>
> Removed:
>
>
>
>
> ################################################################################
> diff  --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp
> index 3f930c76fe0a2..663666b6bf8b8 100644
> --- a/clang/lib/CodeGen/CGObjC.cpp
> +++ b/clang/lib/CodeGen/CGObjC.cpp
> @@ -23,6 +23,7 @@
>  #include "clang/Basic/Diagnostic.h"
>  #include "clang/CodeGen/CGFunctionInfo.h"
>  #include "llvm/ADT/STLExtras.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/BinaryFormat/MachO.h"
>  #include "llvm/IR/DataLayout.h"
>  #include "llvm/IR/InlineAsm.h"
> @@ -2078,6 +2079,15 @@ void
> CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
>    EmitNounwindRuntimeCall(fn, values);
>  }
>
> +/// Emit a call to "clang.arc.noop.use", which consumes the result of a
> call
> +/// that has operand bundle "clang.arc.attachedcall".
> +void CodeGenFunction::EmitARCNoopIntrinsicUse(ArrayRef<llvm::Value *>
> values) {
> +  llvm::Function *&fn = CGM.getObjCEntrypoints().clang_arc_noop_use;
> +  if (!fn)
> +    fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_noop_use);
> +  EmitNounwindRuntimeCall(fn, values);
> +}
> +
>  static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, llvm::Value
> *RTF) {
>    if (auto *F = dyn_cast<llvm::Function>(RTF)) {
>      // If the target runtime doesn't naturally support ARC, emit weak
> @@ -2304,10 +2314,11 @@ static void
> emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
>      // with this marker yet, so leave a breadcrumb for the ARC
>      // optimizer to pick up.
>      } else {
> -      const char *markerKey =
> "clang.arc.retainAutoreleasedReturnValueMarker";
> -      if (!CGF.CGM.getModule().getModuleFlag(markerKey)) {
> +      const char *retainRVMarkerKey =
> llvm::objcarc::getRVMarkerModuleFlagStr();
> +      if (!CGF.CGM.getModule().getModuleFlag(retainRVMarkerKey)) {
>          auto *str = llvm::MDString::get(CGF.getLLVMContext(), assembly);
> -        CGF.CGM.getModule().addModuleFlag(llvm::Module::Error, markerKey,
> str);
> +        CGF.CGM.getModule().addModuleFlag(llvm::Module::Error,
> +                                          retainRVMarkerKey, str);
>        }
>      }
>    }
> @@ -2317,6 +2328,47 @@ static void
> emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
>      CGF.Builder.CreateCall(marker, None,
> CGF.getBundlesForFunclet(marker));
>  }
>
> +static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value,
> +                                               bool IsRetainRV,
> +                                               CodeGenFunction &CGF) {
> +  emitAutoreleasedReturnValueMarker(CGF);
> +
> +  // Add operand bundle "clang.arc.attachedcall" to the call instead of
> emitting
> +  // retainRV or claimRV calls in the IR. We currently do this only when
> the
> +  // optimization level isn't -O0 since global-isel, which is currently
> run at
> +  // -O0, doesn't know about the operand bundle.
> +
> +  // FIXME: Do this when the target isn't aarch64.
> +  if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 &&
> +      CGF.CGM.getTarget().getTriple().isAArch64()) {
> +    llvm::Value *bundleArgs[] = {llvm::ConstantInt::get(
> +        CGF.Int64Ty,
> +        llvm::objcarc::getAttachedCallOperandBundleEnum(IsRetainRV))};
> +    llvm::OperandBundleDef OB("clang.arc.attachedcall", bundleArgs);
> +    auto *oldCall = cast<llvm::CallBase>(value);
> +    llvm::CallBase *newCall = llvm::CallBase::addOperandBundle(
> +        oldCall, llvm::LLVMContext::OB_clang_arc_attachedcall, OB,
> oldCall);
> +    newCall->copyMetadata(*oldCall);
> +    oldCall->replaceAllUsesWith(newCall);
> +    oldCall->eraseFromParent();
> +    CGF.EmitARCNoopIntrinsicUse(newCall);
> +    return newCall;
> +  }
> +
> +  bool isNoTail =
> +
> CGF.CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail();
> +  llvm::CallInst::TailCallKind tailKind =
> +      isNoTail ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None;
> +  ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints();
> +  llvm::Function *&EP = IsRetainRV
> +                            ? EPs.objc_retainAutoreleasedReturnValue
> +                            : EPs.objc_unsafeClaimAutoreleasedReturnValue;
> +  llvm::Intrinsic::ID IID =
> +      IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue
> +                 :
> llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue;
> +  return emitARCValueOperation(CGF, value, nullptr, EP, IID, tailKind);
> +}
> +
>  /// Retain the given object which is the result of a function call.
>  ///   call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
>  ///
> @@ -2324,15 +2376,7 @@ static void
> emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
>  /// call with completely
> diff erent semantics.
>  llvm::Value *
>  CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value)
> {
> -  emitAutoreleasedReturnValueMarker(*this);
> -  llvm::CallInst::TailCallKind tailKind =
> -      CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail()
> -          ? llvm::CallInst::TCK_NoTail
> -          : llvm::CallInst::TCK_None;
> -  return emitARCValueOperation(
> -      *this, value, nullptr,
> -      CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
> -      llvm::Intrinsic::objc_retainAutoreleasedReturnValue, tailKind);
> +  return emitOptimizedARCReturnCall(value, true, *this);
>  }
>
>  /// Claim a possibly-autoreleased return value at +0.  This is only
> @@ -2344,15 +2388,7 @@
> CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
>  ///   call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
>  llvm::Value *
>  CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value
> *value) {
> -  emitAutoreleasedReturnValueMarker(*this);
> -  llvm::CallInst::TailCallKind tailKind =
> -      CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail()
> -          ? llvm::CallInst::TCK_NoTail
> -          : llvm::CallInst::TCK_None;
> -  return emitARCValueOperation(
> -      *this, value, nullptr,
> -      CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
> -      llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue, tailKind);
> +  return emitOptimizedARCReturnCall(value, false, *this);
>  }
>
>  /// Release the given object.
>
> diff  --git a/clang/lib/CodeGen/CodeGenFunction.h
> b/clang/lib/CodeGen/CodeGenFunction.h
> index 279ee857ecd22..8ef0de018a98b 100644
> --- a/clang/lib/CodeGen/CodeGenFunction.h
> +++ b/clang/lib/CodeGen/CodeGenFunction.h
> @@ -4216,6 +4216,8 @@ class CodeGenFunction : public CodeGenTypeCache {
>
>    void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
>
> +  void EmitARCNoopIntrinsicUse(ArrayRef<llvm::Value *> values);
> +
>    static Destroyer destroyARCStrongImprecise;
>    static Destroyer destroyARCStrongPrecise;
>    static Destroyer destroyARCWeak;
>
> diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp
> b/clang/lib/CodeGen/CodeGenModule.cpp
> index b23d995683bf7..5623bd7542ec5 100644
> --- a/clang/lib/CodeGen/CodeGenModule.cpp
> +++ b/clang/lib/CodeGen/CodeGenModule.cpp
> @@ -4573,7 +4573,6 @@ static void
> replaceUsesOfNonProtoConstant(llvm::Constant *old,
>
>    llvm::Type *newRetTy = newFn->getReturnType();
>    SmallVector<llvm::Value*, 4> newArgs;
> -  SmallVector<llvm::OperandBundleDef, 1> newBundles;
>
>    for (llvm::Value::use_iterator ui = old->use_begin(), ue =
> old->use_end();
>           ui != ue; ) {
> @@ -4630,6 +4629,7 @@ static void
> replaceUsesOfNonProtoConstant(llvm::Constant *old,
>      newArgs.append(callSite->arg_begin(), callSite->arg_begin() + argNo);
>
>      // Copy over any operand bundles.
> +    SmallVector<llvm::OperandBundleDef, 1> newBundles;
>      callSite->getOperandBundlesAsDefs(newBundles);
>
>      llvm::CallBase *newCall;
>
> diff  --git a/clang/lib/CodeGen/CodeGenModule.h
> b/clang/lib/CodeGen/CodeGenModule.h
> index 409ebd3df07fe..d495a169b609b 100644
> --- a/clang/lib/CodeGen/CodeGenModule.h
> +++ b/clang/lib/CodeGen/CodeGenModule.h
> @@ -210,6 +210,9 @@ struct ObjCEntrypoints {
>
>    /// void clang.arc.use(...);
>    llvm::Function *clang_arc_use;
> +
> +  /// void clang.arc.noop.use(...);
> +  llvm::Function *clang_arc_noop_use;
>  };
>
>  /// This class records statistics on instrumentation based profiling.
>
> diff  --git a/clang/test/CodeGenObjC/arc-rv-attr.m
> b/clang/test/CodeGenObjC/arc-rv-attr.m
> new file mode 100644
> index 0000000000000..3b769de1443c7
> --- /dev/null
> +++ b/clang/test/CodeGenObjC/arc-rv-attr.m
> @@ -0,0 +1,177 @@
> +// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0
> -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
> -check-prefix=CHECK
> +
> + at class A;
> +
> +A *makeA(void);
> +
> +void test_assign() {
> +  __unsafe_unretained id x;
> +  x = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_assign()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A:.*]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_assign_assign() {
> +  __unsafe_unretained id x, y;
> +  x = y = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_assign_assign()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_strong_assign_assign() {
> +  __strong id x;
> +  __unsafe_unretained id y;
> +  x = y = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_strong_assign_assign()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 0) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    [[OLD:%.*]] = load i8*, i8** [[X]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[OLD]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    [[T0:%.*]] = load i8*, i8** [[X]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[T0]])
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_assign_strong_assign() {
> +  __unsafe_unretained id x;
> +  __strong id y;
> +  x = y = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_assign_strong_assign()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 0) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    [[OLD:%.*]] = load i8*, i8** [[Y]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[OLD]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    [[T0:%.*]] = load i8*, i8** [[Y]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[T0]])
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_init() {
> +  __unsafe_unretained id x = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_init()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_init_assignment() {
> +  __unsafe_unretained id x;
> +  __unsafe_unretained id y = x = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_init_assignment()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_strong_init_assignment() {
> +  __unsafe_unretained id x;
> +  __strong id y = x = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_strong_init_assignment()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 0) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    [[T0:%.*]] = load i8*, i8** [[Y]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[T0]])
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_init_strong_assignment() {
> +  __strong id x;
> +  __unsafe_unretained id y = x = makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_init_strong_assignment()
> +// CHECK:         [[X:%.*]] = alloca i8*
> +// CHECK:         [[Y:%.*]] = alloca i8*
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 0) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
> +// CHECK-NEXT:    [[OLD:%.*]] = load i8*, i8** [[X]]
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[X]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[OLD]])
> +// CHECK-NEXT:    store i8* [[T1]], i8** [[Y]]
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    [[T0:%.*]] = load i8*, i8** [[X]]
> +// CHECK-NEXT:    call void @llvm.objc.release(i8* [[T0]])
> +// CHECK-NEXT:    bitcast
> +// CHECK-NEXT:    lifetime.end
> +// CHECK-NEXT:    ret void
> +
> +void test_ignored() {
> +  makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_ignored()
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    ret void
> +
> +void test_cast_to_void() {
> +  (void) makeA();
> +}
> +// CHECK-LABEL: define{{.*}} void @test_cast_to_void()
> +// CHECK:         [[T0:%.*]] = call [[A]]* @makeA() [
> "clang.arc.attachedcall"(i64 1) ]
> +// CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use({{.*}}
> [[T0]])
> +// CHECK-NEXT:    ret void
> +
> +// This is always at the end of the module.
> +
> +// CHECK-OPTIMIZED: !llvm.module.flags = !{!0,
> +// CHECK-OPTIMIZED: !0 = !{i32 1,
> !"clang.arc.retainAutoreleasedReturnValueMarker", !"mov{{.*}}marker for
> objc_retainAutoreleaseReturnValue"}
>
> diff  --git a/clang/test/CodeGenObjC/arc-unsafeclaim.m
> b/clang/test/CodeGenObjC/arc-unsafeclaim.m
> index 8f95d1edc96c5..08ff8eca8da51 100644
> --- a/clang/test/CodeGenObjC/arc-unsafeclaim.m
> +++ b/clang/test/CodeGenObjC/arc-unsafeclaim.m
> @@ -4,11 +4,10 @@
>  //   Make sure it works on x86-32.
>  // RUN: %clang_cc1 -triple i386-apple-darwin11
> -fobjc-runtime=macosx-fragile-10.11 -fobjc-arc -emit-llvm -o - %s |
> FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED
> -check-prefix=CHECK-MARKED -check-prefix=CALL
>
> -//   Make sure it works on ARM.
> +//   Make sure it works on ARM64.
>  // RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0
> -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
> -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED
> -check-prefix=CALL
> -// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0
> -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
> -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL
>
> -//   Make sure it works on ARM64.
> +//   Make sure it works on ARM.
>  // RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0
> -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK
> -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED
> -check-prefix=CALL
>  // RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0
> -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
> -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL
>
>
> diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
> index fef7a2af8d15f..343aeaec78bb8 100644
> --- a/llvm/docs/LangRef.rst
> +++ b/llvm/docs/LangRef.rst
> @@ -2328,6 +2328,19 @@ When lowered, any relocated value will be recorded
> in the corresponding
>  :ref:`stackmap entry <statepoint-stackmap-format>`.  See the intrinsic
> description
>  for further details.
>
> +ObjC ARC Attached Call Operand Bundles
> +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +A ``"clang.arc.attachedcall`` operand bundle on a call indicates the call
> is
> +implicitly followed by a marker instruction and a call to an ObjC runtime
> +function that uses the result of the call. If the argument passed to the
> operand
> +bundle is 0, ``@objc_retainAutoreleasedReturnValue`` is called. If 1 is
> passed,
> +``@objc_unsafeClaimAutoreleasedReturnValue`` is called. A call with this
> bundle
> +implicitly uses its return value.
> +
> +The operand bundle is needed to ensure the call is immediately followed
> by the
> +marker instruction or the ObjC runtime call in the final output.
> +
>  .. _moduleasm:
>
>  Module-Level Inline Assembly
>
> diff  --git a/llvm/include/llvm/Analysis/ObjCARCUtil.h
> b/llvm/include/llvm/Analysis/ObjCARCUtil.h
> new file mode 100644
> index 0000000000000..9345c892ff399
> --- /dev/null
> +++ b/llvm/include/llvm/Analysis/ObjCARCUtil.h
> @@ -0,0 +1,50 @@
> +//===- ObjCARCUtil.h - ObjC ARC Utility Functions ---------------*- C++
> -*-===//
> +//
> +// Part of the LLVM Project, under the Apache License v2.0 with LLVM
> Exceptions.
> +// See https://llvm.org/LICENSE.txt for license information.
> +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
> +//
>
> +//===----------------------------------------------------------------------===//
> +/// \file
> +/// This file defines ARC utility functions which are used by various
> parts of
> +/// the compiler.
> +///
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_LIB_ANALYSIS_OBJCARCUTIL_H
> +#define LLVM_LIB_ANALYSIS_OBJCARCUTIL_H
> +
> +#include "llvm/IR/InstrTypes.h"
> +#include "llvm/IR/LLVMContext.h"
> +
> +namespace llvm {
> +namespace objcarc {
> +
> +static inline const char *getRVMarkerModuleFlagStr() {
> +  return "clang.arc.retainAutoreleasedReturnValueMarker";
> +}
> +
> +enum AttachedCallOperandBundle : unsigned { RVOB_Retain, RVOB_Claim };
> +
> +static AttachedCallOperandBundle
> +getAttachedCallOperandBundleEnum(bool IsRetain) {
> +  return IsRetain ? RVOB_Retain : RVOB_Claim;
> +}
> +
> +static inline bool hasAttachedCallOpBundle(const CallBase *CB, bool
> IsRetain) {
> +  auto B = CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall);
> +  if (!B.hasValue())
> +    return false;
> +  return cast<ConstantInt>(B->Inputs[0])->getZExtValue() ==
> +         getAttachedCallOperandBundleEnum(IsRetain);
> +}
> +
> +static inline bool hasAttachedCallOpBundle(const CallBase *CB) {
> +  return CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall)
> +      .hasValue();
> +}
> +
> +} // end namespace objcarc
> +} // end namespace llvm
> +
> +#endif
>
> diff  --git a/llvm/include/llvm/IR/InstrTypes.h
> b/llvm/include/llvm/IR/InstrTypes.h
> index 906264b7d91d9..5c1d2bdd296ea 100644
> --- a/llvm/include/llvm/IR/InstrTypes.h
> +++ b/llvm/include/llvm/IR/InstrTypes.h
> @@ -1223,6 +1223,15 @@ class CallBase : public Instruction {
>                            OperandBundleDef Bundle,
>                            Instruction *InsertPt = nullptr);
>
> +  /// Create a clone of \p CB with operand bundle \p OB added.
> +  static CallBase *addOperandBundle(CallBase *CB, uint32_t ID,
> +                                    OperandBundleDef OB,
> +                                    Instruction *InsertPt = nullptr);
> +
> +  /// Create a clone of \p CB with operand bundle \p ID removed.
> +  static CallBase *removeOperandBundle(CallBase *CB, uint32_t ID,
> +                                       Instruction *InsertPt = nullptr);
> +
>    static bool classof(const Instruction *I) {
>      return I->getOpcode() == Instruction::Call ||
>             I->getOpcode() == Instruction::Invoke ||
>
> diff  --git a/llvm/include/llvm/IR/Intrinsics.td
> b/llvm/include/llvm/IR/Intrinsics.td
> index 385fdfa34b1b9..2ada767fa0a26 100644
> --- a/llvm/include/llvm/IR/Intrinsics.td
> +++ b/llvm/include/llvm/IR/Intrinsics.td
> @@ -450,6 +450,9 @@ def int_objc_storeWeak                      :
> Intrinsic<[llvm_ptr_ty],
>                                                           llvm_ptr_ty]>;
>  def int_objc_clang_arc_use                  : Intrinsic<[],
>                                                          [llvm_vararg_ty]>;
> +def int_objc_clang_arc_noop_use : DefaultAttrsIntrinsic<[],
> +                                                        [llvm_vararg_ty],
> +
> [IntrInaccessibleMemOnly]>;
>  def int_objc_unsafeClaimAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty],
>
>  [llvm_ptr_ty]>;
>  def int_objc_retainedObject                 : Intrinsic<[llvm_ptr_ty],
>
> diff  --git a/llvm/include/llvm/IR/LLVMContext.h
> b/llvm/include/llvm/IR/LLVMContext.h
> index 16eb5c69d3b78..3bd889485dd1d 100644
> --- a/llvm/include/llvm/IR/LLVMContext.h
> +++ b/llvm/include/llvm/IR/LLVMContext.h
> @@ -87,12 +87,13 @@ class LLVMContext {
>    /// operand bundle tags without comparing strings. Keep this in sync
> with
>    /// LLVMContext::LLVMContext().
>    enum : unsigned {
> -    OB_deopt = 0,         // "deopt"
> -    OB_funclet = 1,       // "funclet"
> -    OB_gc_transition = 2, // "gc-transition"
> -    OB_cfguardtarget = 3, // "cfguardtarget"
> -    OB_preallocated = 4,  // "preallocated"
> -    OB_gc_live = 5,       // "gc-live"
> +    OB_deopt = 0,                  // "deopt"
> +    OB_funclet = 1,                // "funclet"
> +    OB_gc_transition = 2,          // "gc-transition"
> +    OB_cfguardtarget = 3,          // "cfguardtarget"
> +    OB_preallocated = 4,           // "preallocated"
> +    OB_gc_live = 5,                // "gc-live"
> +    OB_clang_arc_attachedcall = 6, // "clang.arc.attachedcall"
>    };
>
>    /// getMDKindID - Return a unique non-zero ID for the specified
> metadata kind.
>
> diff  --git a/llvm/lib/Analysis/ObjCARCInstKind.cpp
> b/llvm/lib/Analysis/ObjCARCInstKind.cpp
> index 9519078042271..704d15f3280dc 100644
> --- a/llvm/lib/Analysis/ObjCARCInstKind.cpp
> +++ b/llvm/lib/Analysis/ObjCARCInstKind.cpp
> @@ -140,6 +140,7 @@ ARCInstKind llvm::objcarc::GetFunctionClass(const
> Function *F) {
>      return ARCInstKind::User;
>    case Intrinsic::objc_sync_exit:
>      return ARCInstKind::User;
> +  case Intrinsic::objc_clang_arc_noop_use:
>    case Intrinsic::objc_arc_annotation_topdown_bbstart:
>    case Intrinsic::objc_arc_annotation_topdown_bbend:
>    case Intrinsic::objc_arc_annotation_bottomup_bbstart:
>
> diff  --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> index 3e574dd8fb72d..39730d03502b7 100644
> --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
> @@ -2784,11 +2784,11 @@ void SelectionDAGBuilder::visitInvoke(const
> InvokeInst &I) {
>
>    // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we
> don't
>    // have to do anything here to lower funclet bundles.
> -  assert(!I.hasOperandBundlesOtherThan({LLVMContext::OB_deopt,
> -                                        LLVMContext::OB_gc_transition,
> -                                        LLVMContext::OB_gc_live,
> -                                        LLVMContext::OB_funclet,
> -                                        LLVMContext::OB_cfguardtarget}) &&
> +  assert(!I.hasOperandBundlesOtherThan(
> +             {LLVMContext::OB_deopt, LLVMContext::OB_gc_transition,
> +              LLVMContext::OB_gc_live, LLVMContext::OB_funclet,
> +              LLVMContext::OB_cfguardtarget,
> +              LLVMContext::OB_clang_arc_attachedcall}) &&
>           "Cannot lower invokes with arbitrary operand bundles yet!");
>
>    const Value *Callee(I.getCalledOperand());
> @@ -7895,7 +7895,8 @@ void SelectionDAGBuilder::visitCall(const CallInst
> &I) {
>    // CFGuardTarget bundles are lowered in LowerCallTo.
>    assert(!I.hasOperandBundlesOtherThan(
>               {LLVMContext::OB_deopt, LLVMContext::OB_funclet,
> -              LLVMContext::OB_cfguardtarget,
> LLVMContext::OB_preallocated}) &&
> +              LLVMContext::OB_cfguardtarget, LLVMContext::OB_preallocated,
> +              LLVMContext::OB_clang_arc_attachedcall}) &&
>           "Cannot lower calls with arbitrary operand bundles!");
>
>    SDValue Callee = getValue(I.getCalledOperand());
>
> diff  --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
> index 1250b5d2a906f..8ca091d436c88 100644
> --- a/llvm/lib/IR/AutoUpgrade.cpp
> +++ b/llvm/lib/IR/AutoUpgrade.cpp
> @@ -14,14 +14,15 @@
>
>  #include "llvm/IR/AutoUpgrade.h"
>  #include "llvm/ADT/StringSwitch.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/IR/Constants.h"
>  #include "llvm/IR/DIBuilder.h"
>  #include "llvm/IR/DebugInfo.h"
>  #include "llvm/IR/DiagnosticInfo.h"
>  #include "llvm/IR/Function.h"
>  #include "llvm/IR/IRBuilder.h"
> -#include "llvm/IR/Instruction.h"
>  #include "llvm/IR/InstVisitor.h"
> +#include "llvm/IR/Instruction.h"
>  #include "llvm/IR/IntrinsicInst.h"
>  #include "llvm/IR/Intrinsics.h"
>  #include "llvm/IR/IntrinsicsAArch64.h"
> @@ -4038,7 +4039,7 @@ bool llvm::UpgradeDebugInfo(Module &M) {
>  /// returns true if module is modified.
>  static bool UpgradeRetainReleaseMarker(Module &M) {
>    bool Changed = false;
> -  const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
> +  const char *MarkerKey = objcarc::getRVMarkerModuleFlagStr();
>    NamedMDNode *ModRetainReleaseMarker = M.getNamedMetadata(MarkerKey);
>    if (ModRetainReleaseMarker) {
>      MDNode *Op = ModRetainReleaseMarker->getOperand(0);
>
> diff  --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
> index 6b33c03d66b70..6666d74ecabb3 100644
> --- a/llvm/lib/IR/Instructions.cpp
> +++ b/llvm/lib/IR/Instructions.cpp
> @@ -437,6 +437,35 @@ CallBase::BundleOpInfo
> &CallBase::getBundleOpInfoForOperand(unsigned OpIdx) {
>    return *Current;
>  }
>
> +CallBase *CallBase::addOperandBundle(CallBase *CB, uint32_t ID,
> +                                     OperandBundleDef OB,
> +                                     Instruction *InsertPt) {
> +  if (CB->getOperandBundle(ID))
> +    return CB;
> +
> +  SmallVector<OperandBundleDef, 1> Bundles;
> +  CB->getOperandBundlesAsDefs(Bundles);
> +  Bundles.push_back(OB);
> +  return Create(CB, Bundles, InsertPt);
> +}
> +
> +CallBase *CallBase::removeOperandBundle(CallBase *CB, uint32_t ID,
> +                                        Instruction *InsertPt) {
> +  SmallVector<OperandBundleDef, 1> Bundles;
> +  bool CreateNew = false;
> +
> +  for (unsigned I = 0, E = CB->getNumOperandBundles(); I != E; ++I) {
> +    auto Bundle = CB->getOperandBundleAt(I);
> +    if (Bundle.getTagID() == ID) {
> +      CreateNew = true;
> +      continue;
> +    }
> +    Bundles.emplace_back(Bundle);
> +  }
> +
> +  return CreateNew ? Create(CB, Bundles, InsertPt) : CB;
> +}
> +
>
>  //===----------------------------------------------------------------------===//
>  //                        CallInst Implementation
>
>  //===----------------------------------------------------------------------===//
>
> diff  --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
> index f554c54196bed..79002fb1b1bc7 100644
> --- a/llvm/lib/IR/LLVMContext.cpp
> +++ b/llvm/lib/IR/LLVMContext.cpp
> @@ -78,6 +78,12 @@ LLVMContext::LLVMContext() : pImpl(new
> LLVMContextImpl(*this)) {
>           "gc-transition operand bundle id drifted!");
>    (void)GCLiveEntry;
>
> +  auto *ClangAttachedCall =
> +      pImpl->getOrInsertBundleTag("clang.arc.attachedcall");
> +  assert(ClangAttachedCall->second ==
> LLVMContext::OB_clang_arc_attachedcall &&
> +         "clang.arc.attachedcall operand bundle id drifted!");
> +  (void)ClangAttachedCall;
> +
>    SyncScope::ID SingleThreadSSID =
>        pImpl->getOrInsertSyncScopeID("singlethread");
>    assert(SingleThreadSSID == SyncScope::SingleThread &&
>
> diff  --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
> index f8db3b74dbb48..47bfbfb19524b 100644
> --- a/llvm/lib/IR/Verifier.cpp
> +++ b/llvm/lib/IR/Verifier.cpp
> @@ -3187,7 +3187,8 @@ void Verifier::visitCallBase(CallBase &Call) {
>    // and at most one "preallocated" operand bundle.
>    bool FoundDeoptBundle = false, FoundFuncletBundle = false,
>         FoundGCTransitionBundle = false, FoundCFGuardTargetBundle = false,
> -       FoundPreallocatedBundle = false, FoundGCLiveBundle = false;;
> +       FoundPreallocatedBundle = false, FoundGCLiveBundle = false,
> +       FoundAttachedCallBundle = false;
>    for (unsigned i = 0, e = Call.getNumOperandBundles(); i < e; ++i) {
>      OperandBundleUse BU = Call.getOperandBundleAt(i);
>      uint32_t Tag = BU.getTagID();
> @@ -3228,9 +3229,19 @@ void Verifier::visitCallBase(CallBase &Call) {
>        Assert(!FoundGCLiveBundle, "Multiple gc-live operand bundles",
>               Call);
>        FoundGCLiveBundle = true;
> +    } else if (Tag == LLVMContext::OB_clang_arc_attachedcall) {
> +      Assert(!FoundAttachedCallBundle,
> +             "Multiple \"clang.arc.attachedcall\" operand bundles", Call);
> +      FoundAttachedCallBundle = true;
>      }
>    }
>
> +  if (FoundAttachedCallBundle)
> +    Assert(FTy->getReturnType()->isPointerTy(),
> +           "a call with operand bundle \"clang.arc.attachedcall\" must
> call a "
> +           "function returning a pointer",
> +           Call);
> +
>    // Verify that each inlinable callsite of a debug-info-bearing function
> in a
>    // debug-info-bearing function has a debug location attached to it.
> Failure to
>    // do so causes assertion failures when the inliner sets up inline
> scope info.
>
> diff  --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
> b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
> index 703045412302f..3cc809eb255c3 100644
> --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
> +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
> @@ -29,6 +29,7 @@
>  #include "llvm/ADT/StringRef.h"
>  #include "llvm/ADT/Triple.h"
>  #include "llvm/ADT/Twine.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/Analysis/VectorUtils.h"
>  #include "llvm/CodeGen/CallingConvLower.h"
>  #include "llvm/CodeGen/MachineBasicBlock.h"
> @@ -5711,11 +5712,12 @@ AArch64TargetLowering::LowerCall(CallLoweringInfo
> &CLI,
>    }
>
>    unsigned CallOpc = AArch64ISD::CALL;
> -  // Calls marked with "rv_marker" are special. They should be expanded
> to the
> -  // call, directly followed by a special marker sequence. Use the
> CALL_RVMARKER
> -  // to do that.
> -  if (CLI.CB && CLI.CB->hasRetAttr("rv_marker")) {
> -    assert(!IsTailCall && "tail calls cannot be marked with rv_marker");
> +  // Calls with operand bundle "clang.arc.attachedcall" are special. They
> should
> +  // be expanded to the call, directly followed by a special marker
> sequence.
> +  // Use the CALL_RVMARKER to do that.
> +  if (CLI.CB && objcarc::hasAttachedCallOpBundle(CLI.CB)) {
> +    assert(!IsTailCall &&
> +           "tail calls cannot be marked with clang.arc.attachedcall");
>      CallOpc = AArch64ISD::CALL_RVMARKER;
>    }
>
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
> b/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
> index 258dc92408150..764dc5f927073 100644
> --- a/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
> +++ b/llvm/lib/Transforms/ObjCARC/ARCRuntimeEntryPoints.h
> @@ -42,6 +42,7 @@ enum class ARCRuntimeEntryPointKind {
>    Autorelease,
>    StoreStrong,
>    RetainRV,
> +  ClaimRV,
>    RetainAutorelease,
>    RetainAutoreleaseRV,
>  };
> @@ -61,6 +62,7 @@ class ARCRuntimeEntryPoints {
>      Autorelease = nullptr;
>      StoreStrong = nullptr;
>      RetainRV = nullptr;
> +    ClaimRV = nullptr;
>      RetainAutorelease = nullptr;
>      RetainAutoreleaseRV = nullptr;
>    }
> @@ -85,6 +87,9 @@ class ARCRuntimeEntryPoints {
>      case ARCRuntimeEntryPointKind::RetainRV:
>        return getIntrinsicEntryPoint(RetainRV,
>
>  Intrinsic::objc_retainAutoreleasedReturnValue);
> +    case ARCRuntimeEntryPointKind::ClaimRV:
> +      return getIntrinsicEntryPoint(
> +          ClaimRV, Intrinsic::objc_unsafeClaimAutoreleasedReturnValue);
>      case ARCRuntimeEntryPointKind::RetainAutorelease:
>        return getIntrinsicEntryPoint(RetainAutorelease,
>                                      Intrinsic::objc_retainAutorelease);
> @@ -121,6 +126,9 @@ class ARCRuntimeEntryPoints {
>    /// Declaration for objc_retainAutoreleasedReturnValue().
>    Function *RetainRV = nullptr;
>
> +  /// Declaration for objc_unsafeClaimAutoreleasedReturnValue().
> +  Function *ClaimRV = nullptr;
> +
>    /// Declaration for objc_retainAutorelease().
>    Function *RetainAutorelease = nullptr;
>
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp
> b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp
> index 970136392fdd9..06b12149f5971 100644
> --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp
> +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp
> @@ -14,7 +14,12 @@
>
>  #include "ObjCARC.h"
>  #include "llvm-c/Initialization.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
> +#include "llvm/IR/IRBuilder.h"
> +#include "llvm/IR/InlineAsm.h"
> +#include "llvm/IR/Instructions.h"
>  #include "llvm/InitializePasses.h"
> +#include "llvm/Transforms/Utils/BasicBlockUtils.h"
>
>  namespace llvm {
>    class PassRegistry;
> @@ -37,3 +42,91 @@ void llvm::initializeObjCARCOpts(PassRegistry
> &Registry) {
>  void LLVMInitializeObjCARCOpts(LLVMPassRegistryRef R) {
>    initializeObjCARCOpts(*unwrap(R));
>  }
> +
> +CallInst *objcarc::createCallInstWithColors(
> +    FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr,
> +    Instruction *InsertBefore,
> +    const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
> +  FunctionType *FTy = Func.getFunctionType();
> +  Value *Callee = Func.getCallee();
> +  SmallVector<OperandBundleDef, 1> OpBundles;
> +
> +  if (!BlockColors.empty()) {
> +    const ColorVector &CV =
> BlockColors.find(InsertBefore->getParent())->second;
> +    assert(CV.size() == 1 && "non-unique color for block!");
> +    Instruction *EHPad = CV.front()->getFirstNonPHI();
> +    if (EHPad->isEHPad())
> +      OpBundles.emplace_back("funclet", EHPad);
> +  }
> +
> +  return CallInst::Create(FTy, Callee, Args, OpBundles, NameStr,
> InsertBefore);
> +}
> +
> +std::pair<bool, bool>
> +BundledRetainClaimRVs::insertAfterInvokes(Function &F, DominatorTree *DT)
> {
> +  bool Changed = false, CFGChanged = false;
> +
> +  for (BasicBlock &BB : F) {
> +    auto *I = dyn_cast<InvokeInst>(BB.getTerminator());
> +
> +    if (!I)
> +      continue;
> +
> +    if (!objcarc::hasAttachedCallOpBundle(I))
> +      continue;
> +
> +    BasicBlock *DestBB = I->getNormalDest();
> +
> +    if (!DestBB->getSinglePredecessor()) {
> +      assert(I->getSuccessor(0) == DestBB &&
> +             "the normal dest is expected to be the first successor");
> +      DestBB = SplitCriticalEdge(I, 0, CriticalEdgeSplittingOptions(DT));
> +      CFGChanged = true;
> +    }
> +
> +    // We don't have to call insertRVCallWithColors since DestBB is the
> normal
> +    // destination of the invoke.
> +    insertRVCall(&*DestBB->getFirstInsertionPt(), I);
> +    Changed = true;
> +  }
> +
> +  return std::make_pair(Changed, CFGChanged);
> +}
> +
> +CallInst *BundledRetainClaimRVs::insertRVCall(Instruction *InsertPt,
> +                                              CallBase *AnnotatedCall) {
> +  DenseMap<BasicBlock *, ColorVector> BlockColors;
> +  return insertRVCallWithColors(InsertPt, AnnotatedCall, BlockColors);
> +}
> +
> +CallInst *BundledRetainClaimRVs::insertRVCallWithColors(
> +    Instruction *InsertPt, CallBase *AnnotatedCall,
> +    const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
> +  IRBuilder<> Builder(InsertPt);
> +  bool IsRetainRV = objcarc::hasAttachedCallOpBundle(AnnotatedCall, true);
> +  Function *Func = EP.get(IsRetainRV ? ARCRuntimeEntryPointKind::RetainRV
> +                                     : ARCRuntimeEntryPointKind::ClaimRV);
> +  Type *ParamTy = Func->getArg(0)->getType();
> +  Value *CallArg = Builder.CreateBitCast(AnnotatedCall, ParamTy);
> +  auto *Call =
> +      createCallInstWithColors(Func, CallArg, "", InsertPt, BlockColors);
> +  RVCalls[Call] = AnnotatedCall;
> +  return Call;
> +}
> +
> +BundledRetainClaimRVs::~BundledRetainClaimRVs() {
> +  if (ContractPass) {
> +    // At this point, we know that the annotated calls can't be tail
> calls as
> +    // they are followed by marker instructions and retainRV/claimRV
> calls. Mark
> +    // them as notail, so that the backend knows these calls can't be tail
> +    // calls.
> +    for (auto P : RVCalls)
> +      if (auto *CI = dyn_cast<CallInst>(P.second))
> +        CI->setTailCallKind(CallInst::TCK_NoTail);
> +  } else {
> +    for (auto P : RVCalls)
> +      EraseInstruction(P.first);
> +  }
> +
> +  RVCalls.clear();
> +}
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h
> b/llvm/lib/Transforms/ObjCARC/ObjCARC.h
> index 8227a8c6f75f0..1f9d76969bfd7 100644
> --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h
> +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h
> @@ -22,7 +22,10 @@
>  #ifndef LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
>  #define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H
>
> +#include "ARCRuntimeEntryPoints.h"
> +#include "llvm/Analysis/EHPersonalities.h"
>  #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/Transforms/Utils/Local.h"
>
>  namespace llvm {
> @@ -87,6 +90,75 @@ void getEquivalentPHIs(PHINodeTy &PN, VectorTy
> &PHIList) {
>    }
>  }
>
> +static inline MDString *getRVInstMarker(Module &M) {
> +  const char *MarkerKey = getRVMarkerModuleFlagStr();
> +  return dyn_cast_or_null<MDString>(M.getModuleFlag(MarkerKey));
> +}
> +
> +/// Create a call instruction with the correct funclet token. This should
> be
> +/// called instead of calling CallInst::Create directly unless the call is
> +/// going to be removed from the IR before WinEHPrepare.
> +CallInst *createCallInstWithColors(
> +    FunctionCallee Func, ArrayRef<Value *> Args, const Twine &NameStr,
> +    Instruction *InsertBefore,
> +    const DenseMap<BasicBlock *, ColorVector> &BlockColors);
> +
> +class BundledRetainClaimRVs {
> +public:
> +  BundledRetainClaimRVs(ARCRuntimeEntryPoints &P, bool ContractPass)
> +      : EP(P), ContractPass(ContractPass) {}
> +  ~BundledRetainClaimRVs();
> +
> +  /// Insert a retainRV/claimRV call to the normal destination blocks of
> invokes
> +  /// with operand bundle "clang.arc.attachedcall". If the edge to the
> normal
> +  /// destination block is a critical edge, split it.
> +  std::pair<bool, bool> insertAfterInvokes(Function &F, DominatorTree
> *DT);
> +
> +  /// Insert a retainRV/claimRV call.
> +  CallInst *insertRVCall(Instruction *InsertPt, CallBase *AnnotatedCall);
> +
> +  /// Insert a retainRV/claimRV call with colors.
> +  CallInst *insertRVCallWithColors(
> +      Instruction *InsertPt, CallBase *AnnotatedCall,
> +      const DenseMap<BasicBlock *, ColorVector> &BlockColors);
> +
> +  /// See if an instruction is a bundled retainRV/claimRV call.
> +  bool contains(const Instruction *I) const {
> +    if (auto *CI = dyn_cast<CallInst>(I))
> +      return RVCalls.count(CI);
> +    return false;
> +  }
> +
> +  /// Remove a retainRV/claimRV call entirely.
> +  void eraseInst(CallInst *CI) {
> +    auto It = RVCalls.find(CI);
> +    if (It != RVCalls.end()) {
> +      // Remove call to @llvm.objc.clang.arc.noop.use.
> +      for (auto U = It->second->user_begin(), E = It->second->user_end();
> U != E; ++U)
> +        if (auto *CI = dyn_cast<CallInst>(*U))
> +          if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use)
> {
> +            CI->eraseFromParent();
> +            break;
> +          }
> +
> +      auto *NewCall = CallBase::removeOperandBundle(
> +          It->second, LLVMContext::OB_clang_arc_attachedcall, It->second);
> +      NewCall->copyMetadata(*It->second);
> +      It->second->replaceAllUsesWith(NewCall);
> +      It->second->eraseFromParent();
> +      RVCalls.erase(It);
> +    }
> +    EraseInstruction(CI);
> +  }
> +
> +private:
> +  /// A map of inserted retainRV/claimRV calls to annotated calls/invokes.
> +  DenseMap<CallInst *, CallBase *> RVCalls;
> +
> +  ARCRuntimeEntryPoints &EP;
> +  bool ContractPass;
> +};
> +
>  } // end namespace objcarc
>  } // end namespace llvm
>
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> index 86d161116e8c7..62161b5b6b40a 100644
> --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> @@ -32,6 +32,7 @@
>  #include "llvm/ADT/Statistic.h"
>  #include "llvm/Analysis/AliasAnalysis.h"
>  #include "llvm/Analysis/EHPersonalities.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/IR/Dominators.h"
>  #include "llvm/IR/InlineAsm.h"
>  #include "llvm/IR/InstIterator.h"
> @@ -63,13 +64,12 @@ namespace {
>
>  class ObjCARCContract {
>    bool Changed;
> +  bool CFGChanged;
>    AAResults *AA;
>    DominatorTree *DT;
>    ProvenanceAnalysis PA;
>    ARCRuntimeEntryPoints EP;
> -
> -  /// A flag indicating whether this optimization pass should run.
> -  bool Run;
> +  BundledRetainClaimRVs *BundledInsts = nullptr;
>
>    /// The inline asm string to insert between calls and RetainRV calls to
> make
>    /// the optimization work on targets which need it.
> @@ -98,6 +98,7 @@ class ObjCARCContract {
>  public:
>    bool init(Module &M);
>    bool run(Function &F, AAResults *AA, DominatorTree *DT);
> +  bool hasCFGChanged() const { return CFGChanged; }
>  };
>
>  class ObjCARCContractLegacyPass : public FunctionPass {
> @@ -304,32 +305,6 @@ findRetainForStoreStrongContraction(Value *New,
> StoreInst *Store,
>    return Retain;
>  }
>
> -/// Create a call instruction with the correct funclet token. Should be
> used
> -/// instead of calling CallInst::Create directly.
> -static CallInst *
> -createCallInst(FunctionType *FTy, Value *Func, ArrayRef<Value *> Args,
> -               const Twine &NameStr, Instruction *InsertBefore,
> -               const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
> -  SmallVector<OperandBundleDef, 1> OpBundles;
> -  if (!BlockColors.empty()) {
> -    const ColorVector &CV =
> BlockColors.find(InsertBefore->getParent())->second;
> -    assert(CV.size() == 1 && "non-unique color for block!");
> -    Instruction *EHPad = CV.front()->getFirstNonPHI();
> -    if (EHPad->isEHPad())
> -      OpBundles.emplace_back("funclet", EHPad);
> -  }
> -
> -  return CallInst::Create(FTy, Func, Args, OpBundles, NameStr,
> InsertBefore);
> -}
> -
> -static CallInst *
> -createCallInst(FunctionCallee Func, ArrayRef<Value *> Args, const Twine
> &NameStr,
> -               Instruction *InsertBefore,
> -               const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
> -  return createCallInst(Func.getFunctionType(), Func.getCallee(), Args,
> NameStr,
> -                        InsertBefore, BlockColors);
> -}
> -
>  /// Attempt to merge an objc_release with a store, load, and objc_retain
> to form
>  /// an objc_storeStrong. An objc_storeStrong:
>  ///
> @@ -411,7 +386,8 @@ void
> ObjCARCContract::tryToContractReleaseIntoStoreStrong(
>    if (Args[1]->getType() != I8X)
>      Args[1] = new BitCastInst(Args[1], I8X, "", Store);
>    Function *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong);
> -  CallInst *StoreStrong = createCallInst(Decl, Args, "", Store,
> BlockColors);
> +  CallInst *StoreStrong =
> +      objcarc::createCallInstWithColors(Decl, Args, "", Store,
> BlockColors);
>    StoreStrong->setDoesNotThrow();
>    StoreStrong->setDebugLoc(Store->getDebugLoc());
>
> @@ -456,9 +432,14 @@ bool ObjCARCContract::tryToPeepholeInstruction(
>    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, insert it now.
> +    // marker to do the return value optimization and the
> retainRV/claimRV call
> +    // wasn't bundled with a call, insert the marker now.
>      if (!RVInstMarker)
>        return false;
> +
> +    if (BundledInsts->contains(Inst))
> +      return false;
> +
>      BasicBlock::iterator BBI = Inst->getIterator();
>      BasicBlock *InstParent = Inst->getParent();
>
> @@ -486,7 +467,7 @@ bool ObjCARCContract::tryToPeepholeInstruction(
>                           RVInstMarker->getString(),
>                           /*Constraints=*/"", /*hasSideEffects=*/true);
>
> -      createCallInst(IA, None, "", Inst, BlockColors);
> +      objcarc::createCallInstWithColors(IA, None, "", Inst, BlockColors);
>      }
>    decline_rv_optimization:
>      return false;
> @@ -525,6 +506,12 @@ bool ObjCARCContract::tryToPeepholeInstruction(
>      Inst->eraseFromParent();
>      return true;
>    default:
> +    if (auto *CI = dyn_cast<CallInst>(Inst))
> +      if (CI->getIntrinsicID() == Intrinsic::objc_clang_arc_noop_use) {
> +        // Remove calls to @llvm.objc.clang.arc.noop.use(...).
> +        Changed = true;
> +        CI->eraseFromParent();
> +      }
>      return true;
>    }
>  }
> @@ -534,16 +521,10 @@ bool ObjCARCContract::tryToPeepholeInstruction(
>
>  //===----------------------------------------------------------------------===//
>
>  bool ObjCARCContract::init(Module &M) {
> -  // If nothing in the Module uses ARC, don't do anything.
> -  Run = ModuleHasARC(M);
> -  if (!Run)
> -    return false;
> -
>    EP.init(&M);
>
>    // Initialize RVInstMarker.
> -  const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
> -  RVInstMarker = dyn_cast_or_null<MDString>(M.getModuleFlag(MarkerKey));
> +  RVInstMarker = getRVInstMarker(M);
>
>    return false;
>  }
> @@ -552,14 +533,16 @@ bool ObjCARCContract::run(Function &F, AAResults *A,
> DominatorTree *D) {
>    if (!EnableARCOpts)
>      return false;
>
> -  // If nothing in the Module uses ARC, don't do anything.
> -  if (!Run)
> -    return false;
> -
> -  Changed = false;
> +  Changed = CFGChanged = false;
>    AA = A;
>    DT = D;
>    PA.setAA(A);
> +  BundledRetainClaimRVs BRV(EP, true);
> +  BundledInsts = &BRV;
> +
> +  std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, DT);
> +  Changed |= R.first;
> +  CFGChanged |= R.second;
>
>    DenseMap<BasicBlock *, ColorVector> BlockColors;
>    if (F.hasPersonalityFn() &&
> @@ -584,6 +567,13 @@ bool ObjCARCContract::run(Function &F, AAResults *A,
> DominatorTree *D) {
>
>      LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n");
>
> +    if (auto *CI = dyn_cast<CallInst>(Inst))
> +      if (objcarc::hasAttachedCallOpBundle(CI)) {
> +        BundledInsts->insertRVCallWithColors(&*I, CI, BlockColors);
> +        --I;
> +        Changed = true;
> +      }
> +
>      // First try to peephole Inst. If there is nothing further we can do
> in
>      // terms of undoing objc-arc-expand, process the next inst.
>      if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs,
> @@ -733,7 +723,6 @@ INITIALIZE_PASS_END(ObjCARCContractLegacyPass,
> "objc-arc-contract",
>  void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const
> {
>    AU.addRequired<AAResultsWrapperPass>();
>    AU.addRequired<DominatorTreeWrapperPass>();
> -  AU.setPreservesCFG();
>  }
>
>  Pass *llvm::createObjCARCContractPass() {
> @@ -757,9 +746,11 @@ PreservedAnalyses ObjCARCContractPass::run(Function
> &F,
>
>    bool Changed = OCAC.run(F, &AM.getResult<AAManager>(F),
>                            &AM.getResult<DominatorTreeAnalysis>(F));
> +  bool CFGChanged = OCAC.hasCFGChanged();
>    if (Changed) {
>      PreservedAnalyses PA;
> -    PA.preserveSet<CFGAnalyses>();
> +    if (!CFGChanged)
> +      PA.preserveSet<CFGAnalyses>();
>      return PA;
>    }
>    return PreservedAnalyses::all();
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
> b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
> index 2043a7bfc8876..0769d466be93d 100644
> --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
> +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
> @@ -41,6 +41,7 @@
>  #include "llvm/Analysis/ObjCARCAliasAnalysis.h"
>  #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
>  #include "llvm/Analysis/ObjCARCInstKind.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/IR/BasicBlock.h"
>  #include "llvm/IR/CFG.h"
>  #include "llvm/IR/Constant.h"
> @@ -483,6 +484,7 @@ namespace {
>    /// The main ARC optimization pass.
>  class ObjCARCOpt {
>    bool Changed;
> +  bool CFGChanged;
>    ProvenanceAnalysis PA;
>
>    /// A cache of references to runtime entry point constants.
> @@ -492,8 +494,7 @@ class ObjCARCOpt {
>    /// MDKind identifiers.
>    ARCMDKindCache MDKindCache;
>
> -  /// A flag indicating whether this optimization pass should run.
> -  bool Run;
> +  BundledRetainClaimRVs *BundledInsts = nullptr;
>
>    /// A flag indicating whether the optimization that removes or moves
>    /// retain/release pairs should be performed.
> @@ -573,6 +574,7 @@ class ObjCARCOpt {
>      void init(Module &M);
>      bool run(Function &F, AAResults &AA);
>      void releaseMemory();
> +    bool hasCFGChanged() const { return CFGChanged; }
>  };
>
>  /// The main ARC optimization pass.
> @@ -610,8 +612,6 @@ Pass *llvm::createObjCARCOptPass() { return new
> ObjCARCOptLegacyPass(); }
>  void ObjCARCOptLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
>    AU.addRequired<ObjCARCAAWrapperPass>();
>    AU.addRequired<AAResultsWrapperPass>();
> -  // ARC optimization doesn't currently split critical edges.
> -  AU.setPreservesCFG();
>  }
>
>  /// Turn objc_retainAutoreleasedReturnValue into objc_retain if the
> operand is
> @@ -640,6 +640,9 @@ ObjCARCOpt::OptimizeRetainRVCall(Function &F,
> Instruction *RetainRV) {
>      }
>    }
>
> +  assert(!BundledInsts->contains(RetainRV) &&
> +         "a bundled retainRV's argument should be a call");
> +
>    // Turn it to a plain objc_retain.
>    Changed = true;
>    ++NumPeeps;
> @@ -661,6 +664,9 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
>      Function &F, DenseMap<BasicBlock *, ColorVector> &BlockColors,
>      Instruction *Inst, const Value *&Arg, ARCInstKind Class,
>      Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg) {
> +  if (BundledInsts->contains(Inst))
> +    return false;
> +
>    // Must be in the same basic block.
>    assert(Inst->getParent() == AutoreleaseRV->getParent());
>
> @@ -844,6 +850,12 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F)
> {
>    for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
>      Instruction *Inst = &*I++;
>
> +    if (auto *CI = dyn_cast<CallInst>(Inst))
> +      if (objcarc::hasAttachedCallOpBundle(CI)) {
> +        BundledInsts->insertRVCall(&*I, CI);
> +        Changed = true;
> +      }
> +
>      ARCInstKind Class = GetBasicARCInstKind(Inst);
>
>      // Skip this loop if this instruction isn't itself an ARC intrinsic.
> @@ -922,6 +934,11 @@ void ObjCARCOpt::OptimizeIndividualCallImpl(
>    // We can delete this call if it takes an inert value.
>    SmallPtrSet<Value *, 1> VisitedPhis;
>
> +  if (BundledInsts->contains(Inst)) {
> +    UsedInThisFunction |= 1 << unsigned(Class);
> +    return;
> +  }
> +
>    if (IsNoopOnGlobal(Class))
>      if (isInertARCValue(Inst->getOperand(0), VisitedPhis)) {
>        if (!Inst->getType()->isVoidTy())
> @@ -1539,7 +1556,7 @@ ObjCARCOpt::VisitInstructionTopDown(Instruction
> *Inst,
>      if (Ptr == Arg)
>        continue; // Handled above.
>      TopDownPtrState &S = MI->second;
> -    if (S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class))
> +    if (S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class,
> *BundledInsts))
>        continue;
>
>      S.HandlePotentialUse(Inst, Ptr, PA, Class);
> @@ -2340,7 +2357,7 @@ void ObjCARCOpt::OptimizeReturns(Function &F) {
>      ++NumRets;
>      LLVM_DEBUG(dbgs() << "Erasing: " << *Retain << "\nErasing: " <<
> *Autorelease
>                        << "\n");
> -    EraseInstruction(Retain);
> +    BundledInsts->eraseInst(Retain);
>      EraseInstruction(Autorelease);
>    }
>  }
> @@ -2373,11 +2390,6 @@ void ObjCARCOpt::init(Module &M) {
>    if (!EnableARCOpts)
>      return;
>
> -  // If nothing in the Module uses ARC, don't do anything.
> -  Run = ModuleHasARC(M);
> -  if (!Run)
> -    return;
> -
>    // Intuitively, objc_retain and others are nocapture, however in
> practice
>    // they are not, because they return their argument value. And
> objc_release
>    // calls finalizers which can have arbitrary side effects.
> @@ -2391,16 +2403,18 @@ bool ObjCARCOpt::run(Function &F, AAResults &AA) {
>    if (!EnableARCOpts)
>      return false;
>
> -  // If nothing in the Module uses ARC, don't do anything.
> -  if (!Run)
> -    return false;
> -
> -  Changed = false;
> +  Changed = CFGChanged = false;
> +  BundledRetainClaimRVs BRV(EP, false);
> +  BundledInsts = &BRV;
>
>    LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " <<
> F.getName()
>                      << " >>>"
>                         "\n");
>
> +  std::pair<bool, bool> R = BundledInsts->insertAfterInvokes(F, nullptr);
> +  Changed |= R.first;
> +  CFGChanged |= R.second;
> +
>    PA.setAA(&AA);
>
>  #ifndef NDEBUG
> @@ -2465,9 +2479,11 @@ PreservedAnalyses ObjCARCOptPass::run(Function &F,
>    OCAO.init(*F.getParent());
>
>    bool Changed = OCAO.run(F, AM.getResult<AAManager>(F));
> +  bool CFGChanged = OCAO.hasCFGChanged();
>    if (Changed) {
>      PreservedAnalyses PA;
> -    PA.preserveSet<CFGAnalyses>();
> +    if (!CFGChanged)
> +      PA.preserveSet<CFGAnalyses>();
>      return PA;
>    }
>    return PreservedAnalyses::all();
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/PtrState.cpp
> b/llvm/lib/Transforms/ObjCARC/PtrState.cpp
> index 66fdca062b3d5..d10d5851d5ea0 100644
> --- a/llvm/lib/Transforms/ObjCARC/PtrState.cpp
> +++ b/llvm/lib/Transforms/ObjCARC/PtrState.cpp
> @@ -11,6 +11,7 @@
>  #include "ObjCARC.h"
>  #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
>  #include "llvm/Analysis/ObjCARCInstKind.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/IR/BasicBlock.h"
>  #include "llvm/IR/Instruction.h"
>  #include "llvm/IR/Instructions.h"
> @@ -276,6 +277,13 @@ void BottomUpPtrState::HandlePotentialUse(BasicBlock
> *BB, Instruction *Inst,
>        InsertAfter = skipDebugIntrinsics(InsertAfter);
>
>      InsertReverseInsertPt(&*InsertAfter);
> +
> +    // Don't insert anything between a call/invoke with operand bundle
> +    // "clang.arc.attachedcall" and the retainRV/claimRV call that uses
> the call
> +    // result.
> +    if (auto *CB = dyn_cast<CallBase>(Inst))
> +      if (objcarc::hasAttachedCallOpBundle(CB))
> +        SetCFGHazardAfflicted(true);
>    };
>
>    // Check for possible direct uses.
> @@ -366,10 +374,9 @@ bool TopDownPtrState::MatchWithRelease(ARCMDKindCache
> &Cache,
>    llvm_unreachable("Sequence unknown enum value");
>  }
>
> -bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
> -                                                   const Value *Ptr,
> -                                                   ProvenanceAnalysis &PA,
> -                                                   ARCInstKind Class) {
> +bool TopDownPtrState::HandlePotentialAlterRefCount(
> +    Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
> +    ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs) {
>    // Check for possible releases. Treat clang.arc.use as a releasing
> instruction
>    // to prevent sinking a retain past it.
>    if (!CanDecrementRefCount(Inst, Ptr, PA, Class) &&
> @@ -385,6 +392,12 @@ bool
> TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
>      assert(!HasReverseInsertPts());
>      InsertReverseInsertPt(Inst);
>
> +    // Don't insert anything between a call/invoke with operand bundle
> +    // "clang.arc.attachedcall" and the retainRV/claimRV call that uses
> the call
> +    // result.
> +    if (BundledRVs.contains(Inst))
> +      SetCFGHazardAfflicted(true);
> +
>      // One call can't cause a transition from S_Retain to S_CanRelease
>      // and S_CanRelease to S_Use. If we've made the first transition,
>      // we're done.
>
> diff  --git a/llvm/lib/Transforms/ObjCARC/PtrState.h
> b/llvm/lib/Transforms/ObjCARC/PtrState.h
> index c102219b59c93..232db2bd33bc7 100644
> --- a/llvm/lib/Transforms/ObjCARC/PtrState.h
> +++ b/llvm/lib/Transforms/ObjCARC/PtrState.h
> @@ -31,6 +31,7 @@ class Value;
>  namespace objcarc {
>
>  class ARCMDKindCache;
> +class BundledRetainClaimRVs;
>  class ProvenanceAnalysis;
>
>  /// \enum Sequence
> @@ -201,7 +202,8 @@ struct TopDownPtrState : PtrState {
>                            ProvenanceAnalysis &PA, ARCInstKind Class);
>
>    bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr,
> -                                    ProvenanceAnalysis &PA, ARCInstKind
> Class);
> +                                    ProvenanceAnalysis &PA, ARCInstKind
> Class,
> +                                    const BundledRetainClaimRVs
> &BundledRVs);
>  };
>
>  } // end namespace objcarc
>
> diff  --git a/llvm/lib/Transforms/Scalar/SCCP.cpp
> b/llvm/lib/Transforms/Scalar/SCCP.cpp
> index de6be52adf216..045abefd4741c 100644
> --- a/llvm/lib/Transforms/Scalar/SCCP.cpp
> +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
> @@ -144,9 +144,8 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
>    /// represented here for efficient lookup.
>    SmallPtrSet<Function *, 16> MRVFunctionsTracked;
>
> -  /// MustTailFunctions - Each function here is a callee of non-removable
> -  /// musttail call site.
> -  SmallPtrSet<Function *, 16> MustTailCallees;
> +  /// A list of functions whose return cannot be modified.
> +  SmallPtrSet<Function *, 16> MustPreserveReturnsInFunctions;
>
>    /// TrackingIncomingArguments - This is the set of functions for whose
>    /// arguments we make optimistic assumptions about and try to prove as
> @@ -238,16 +237,14 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
>        TrackedRetVals.insert(std::make_pair(F, ValueLatticeElement()));
>    }
>
> -  /// AddMustTailCallee - If the SCCP solver finds that this function is
> called
> -  /// from non-removable musttail call site.
> -  void AddMustTailCallee(Function *F) {
> -    MustTailCallees.insert(F);
> +  /// Add function to the list of functions whose return cannot be
> modified.
> +  void addToMustPreserveReturnsInFunctions(Function *F) {
> +    MustPreserveReturnsInFunctions.insert(F);
>    }
>
> -  /// Returns true if the given function is called from non-removable
> musttail
> -  /// call site.
> -  bool isMustTailCallee(Function *F) {
> -    return MustTailCallees.count(F);
> +  /// Returns true if the return of the given function cannot be modified.
> +  bool mustPreserveReturn(Function *F) {
> +    return MustPreserveReturnsInFunctions.count(F);
>    }
>
>    void AddArgumentTrackedFunction(Function *F) {
> @@ -319,12 +316,6 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
>      return MRVFunctionsTracked;
>    }
>
> -  /// getMustTailCallees - Get the set of functions which are called
> -  /// from non-removable musttail call sites.
> -  const SmallPtrSet<Function *, 16> getMustTailCallees() {
> -    return MustTailCallees;
> -  }
> -
>    /// markOverdefined - Mark the specified value overdefined.  This
>    /// works with both scalars and structs.
>    void markOverdefined(Value *V) {
> @@ -1650,16 +1641,19 @@ static bool tryToReplaceWithConstant(SCCPSolver
> &Solver, Value *V) {
>    assert(Const && "Constant is nullptr here!");
>
>    // Replacing `musttail` instructions with constant breaks `musttail`
> invariant
> -  // unless the call itself can be removed
> -  CallInst *CI = dyn_cast<CallInst>(V);
> -  if (CI && CI->isMustTailCall() && !CI->isSafeToRemove()) {
> -    Function *F = CI->getCalledFunction();
> +  // unless the call itself can be removed.
> +  // Calls with "clang.arc.attachedcall" implicitly use the return value
> and
> +  // those uses cannot be updated with a constant.
> +  CallBase *CB = dyn_cast<CallBase>(V);
> +  if (CB && ((CB->isMustTailCall() && !CB->isSafeToRemove()) ||
> +
>  CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall))) {
> +    Function *F = CB->getCalledFunction();
>
>      // Don't zap returns of the callee
>      if (F)
> -      Solver.AddMustTailCallee(F);
> +      Solver.addToMustPreserveReturnsInFunctions(F);
>
> -    LLVM_DEBUG(dbgs() << "  Can\'t treat the result of musttail call : "
> << *CI
> +    LLVM_DEBUG(dbgs() << "  Can\'t treat the result of call " << *CB
>                        << " as a constant\n");
>      return false;
>    }
> @@ -1821,11 +1815,12 @@ static void findReturnsToZap(Function &F,
>    if (!Solver.isArgumentTrackedFunction(&F))
>      return;
>
> -  // There is a non-removable musttail call site of this function. Zapping
> -  // returns is not allowed.
> -  if (Solver.isMustTailCallee(&F)) {
> -    LLVM_DEBUG(dbgs() << "Can't zap returns of the function : " <<
> F.getName()
> -                      << " due to present musttail call of it\n");
> +  if (Solver.mustPreserveReturn(&F)) {
> +    LLVM_DEBUG(
> +        dbgs()
> +        << "Can't zap returns of the function : " << F.getName()
> +        << " due to present musttail or \"clang.arc.attachedcall\" call
> of "
> +           "it\n");
>      return;
>    }
>
>
> diff  --git a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
> b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
> index 9e7cccc884127..8cc649a8c1ed8 100644
> --- a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
> +++ b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
> @@ -247,7 +247,10 @@ static bool markTails(Function &F, bool
> &AllCallsAreTailCalls,
>            isa<PseudoProbeInst>(&I))
>          continue;
>
> -      bool IsNoTail = CI->isNoTailCall() || CI->hasOperandBundles();
> +      // Special-case operand bundle "clang.arc.attachedcall".
> +      bool IsNoTail =
> +          CI->isNoTailCall() || CI->hasOperandBundlesOtherThan(
> +
> LLVMContext::OB_clang_arc_attachedcall);
>
>        if (!IsNoTail && CI->doesNotAccessMemory()) {
>          // A call to a readnone function whose arguments are all things
> computed
>
> diff  --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp
> b/llvm/lib/Transforms/Utils/InlineFunction.cpp
> index 3026342cc4a6b..5f75ead1247bb 100644
> --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
> +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
> @@ -27,8 +27,9 @@
>  #include "llvm/Analysis/CaptureTracking.h"
>  #include "llvm/Analysis/EHPersonalities.h"
>  #include "llvm/Analysis/InstructionSimplify.h"
> +#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
> +#include "llvm/Analysis/ObjCARCUtil.h"
>  #include "llvm/Analysis/ProfileSummaryInfo.h"
> -#include "llvm/Transforms/Utils/Local.h"
>  #include "llvm/Analysis/ValueTracking.h"
>  #include "llvm/Analysis/VectorUtils.h"
>  #include "llvm/IR/Argument.h"
> @@ -61,6 +62,7 @@
>  #include "llvm/Support/ErrorHandling.h"
>  #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
>  #include "llvm/Transforms/Utils/Cloning.h"
> +#include "llvm/Transforms/Utils/Local.h"
>  #include "llvm/Transforms/Utils/ValueMapper.h"
>  #include <algorithm>
>  #include <cassert>
> @@ -1650,6 +1652,99 @@ void llvm::updateProfileCallee(
>    }
>  }
>
> +/// An operand bundle "clang.arc.attachedcall" on a call indicates the
> call
> +/// result is implicitly consumed by a call to retainRV or claimRV
> immediately
> +/// after the call. This function inlines the retainRV/claimRV calls.
> +///
> +/// There are three cases to consider:
> +///
> +/// 1. If there is a call to autoreleaseRV that takes a pointer to the
> returned
> +///    object in the callee return block, the autoreleaseRV call and the
> +///    retainRV/claimRV call in the caller cancel out. If the call in the
> caller
> +///    is a claimRV call, a call to objc_release is emitted.
> +///
> +/// 2. If there is a call in the callee return block that doesn't have
> operand
> +///    bundle "clang.arc.attachedcall", the operand bundle on the
> original call
> +///    is transferred to the call in the callee.
> +///
> +/// 3. Otherwise, a call to objc_retain is inserted if the call in the
> caller is
> +///    a retainRV call.
> +static void
> +inlineRetainOrClaimRVCalls(CallBase &CB,
> +                           const SmallVectorImpl<ReturnInst *> &Returns) {
> +  Module *Mod = CB.getModule();
> +  bool IsRetainRV = objcarc::hasAttachedCallOpBundle(&CB, true),
> +       IsClaimRV = !IsRetainRV;
> +
> +  for (auto *RI : Returns) {
> +    Value *RetOpnd = objcarc::GetRCIdentityRoot(RI->getOperand(0));
> +    BasicBlock::reverse_iterator I = ++(RI->getIterator().getReverse());
> +    BasicBlock::reverse_iterator EI = RI->getParent()->rend();
> +    bool InsertRetainCall = IsRetainRV;
> +    IRBuilder<> Builder(RI->getContext());
> +
> +    // Walk backwards through the basic block looking for either a
> matching
> +    // autoreleaseRV call or an unannotated call.
> +    for (; I != EI;) {
> +      auto CurI = I++;
> +
> +      // Ignore casts.
> +      if (isa<CastInst>(*CurI))
> +        continue;
> +
> +      if (auto *II = dyn_cast<IntrinsicInst>(&*CurI)) {
> +        if (II->getIntrinsicID() ==
> Intrinsic::objc_autoreleaseReturnValue &&
> +            II->hasNUses(0) &&
> +            objcarc::GetRCIdentityRoot(II->getOperand(0)) == RetOpnd) {
> +          // If we've found a matching authoreleaseRV call:
> +          // - If claimRV is attached to the call, insert a call to
> objc_release
> +          //   and erase the autoreleaseRV call.
> +          // - If retainRV is attached to the call, just erase the
> autoreleaseRV
> +          //   call.
> +          if (IsClaimRV) {
> +            Builder.SetInsertPoint(II);
> +            Function *IFn =
> +                Intrinsic::getDeclaration(Mod, Intrinsic::objc_release);
> +            Value *BC =
> +                Builder.CreateBitCast(RetOpnd, IFn->getArg(0)->getType());
> +            Builder.CreateCall(IFn, BC, "");
> +          }
> +          II->eraseFromParent();
> +          InsertRetainCall = false;
> +        }
> +      } else if (auto *CI = dyn_cast<CallInst>(&*CurI)) {
> +        if (objcarc::GetRCIdentityRoot(CI) == RetOpnd &&
> +            !objcarc::hasAttachedCallOpBundle(CI)) {
> +          // If we've found an unannotated call that defines RetOpnd, add
> a
> +          // "clang.arc.attachedcall" operand bundle.
> +          Value *BundleArgs[] = {ConstantInt::get(
> +              Builder.getInt64Ty(),
> +              objcarc::getAttachedCallOperandBundleEnum(IsRetainRV))};
> +          OperandBundleDef OB("clang.arc.attachedcall", BundleArgs);
> +          auto *NewCall = CallBase::addOperandBundle(
> +              CI, LLVMContext::OB_clang_arc_attachedcall, OB, CI);
> +          NewCall->copyMetadata(*CI);
> +          CI->replaceAllUsesWith(NewCall);
> +          CI->eraseFromParent();
> +          InsertRetainCall = false;
> +        }
> +      }
> +
> +      break;
> +    }
> +
> +    if (InsertRetainCall) {
> +      // The retainRV is attached to the call and we've failed to find a
> +      // matching autoreleaseRV or an annotated call in the callee. Emit
> a call
> +      // to objc_retain.
> +      Builder.SetInsertPoint(RI);
> +      Function *IFn = Intrinsic::getDeclaration(Mod,
> Intrinsic::objc_retain);
> +      Value *BC = Builder.CreateBitCast(RetOpnd,
> IFn->getArg(0)->getType());
> +      Builder.CreateCall(IFn, BC, "");
> +    }
> +  }
> +}
> +
>  /// This function inlines the called function into the basic block of the
>  /// caller. This returns false if it is not possible to inline this call.
>  /// The program is still in a well defined state if this occurs though.
> @@ -1687,6 +1782,8 @@ llvm::InlineResult llvm::InlineFunction(CallBase
> &CB, InlineFunctionInfo &IFI,
>        // ... and "funclet" operand bundles.
>        if (Tag == LLVMContext::OB_funclet)
>          continue;
> +      if (Tag == LLVMContext::OB_clang_arc_attachedcall)
> +        continue;
>
>        return InlineResult::failure("unsupported operand bundle");
>      }
> @@ -1853,6 +1950,10 @@ llvm::InlineResult llvm::InlineFunction(CallBase
> &CB, InlineFunctionInfo &IFI,
>      // Remember the first block that is newly cloned over.
>      FirstNewBlock = LastBlock; ++FirstNewBlock;
>
> +    // Insert retainRV/clainRV runtime calls.
> +    if (objcarc::hasAttachedCallOpBundle(&CB))
> +      inlineRetainOrClaimRVCalls(CB, Returns);
> +
>      if (IFI.CallerBFI != nullptr && IFI.CalleeBFI != nullptr)
>        // Update the BFI of blocks cloned into the caller.
>        updateCallerBFI(OrigBB, VMap, IFI.CallerBFI, IFI.CalleeBFI,
>
> diff  --git a/llvm/test/Bitcode/operand-bundles-bc-analyzer.ll
> b/llvm/test/Bitcode/operand-bundles-bc-analyzer.ll
> index f22fcbeb271ed..cb7a3ee7eb714 100644
> --- a/llvm/test/Bitcode/operand-bundles-bc-analyzer.ll
> +++ b/llvm/test/Bitcode/operand-bundles-bc-analyzer.ll
> @@ -9,6 +9,7 @@
>  ; CHECK-NEXT:    <OPERAND_BUNDLE_TAG
>  ; CHECK-NEXT:    <OPERAND_BUNDLE_TAG
>  ; CHECK-NEXT:    <OPERAND_BUNDLE_TAG
> +; CHECK-NEXT:    <OPERAND_BUNDLE_TAG
>  ; CHECK-NEXT:  </OPERAND_BUNDLE_TAGS_BLOCK
>
>  ; CHECK:   <FUNCTION_BLOCK
>
> diff  --git a/llvm/test/CodeGen/AArch64/call-rv-marker.ll
> b/llvm/test/CodeGen/AArch64/call-rv-marker.ll
> index 245d2c854c342..3b5ab40839b57 100644
> --- a/llvm/test/CodeGen/AArch64/call-rv-marker.ll
> +++ b/llvm/test/CodeGen/AArch64/call-rv-marker.ll
> @@ -33,7 +33,7 @@ define dso_local i8* @rv_marker_1() {
>  ; GISEL-NOT:       mov x29, x29
>  ;
>  entry:
> -  %call = call "rv_marker" i8* @foo1()
> +  %call = call i8* @foo1() [ "clang.arc.attachedcall"(i64 0) ]
>    ret i8* %call
>  }
>
> @@ -49,7 +49,7 @@ define dso_local void @rv_marker_2_select(i32 %c) {
>  entry:
>    %tobool.not = icmp eq i32 %c, 0
>    %.sink = select i1 %tobool.not, i32 2, i32 1
> -  %call1 = call "rv_marker" i8* @foo0(i32 %.sink)
> +  %call1 = call i8* @foo0(i32 %.sink) [ "clang.arc.attachedcall"(i64 0) ]
>    tail call void @foo2(i8* %call1)
>    ret void
>  }
> @@ -61,7 +61,7 @@ define dso_local void @rv_marker_3() personality i8*
> bitcast (i32 (...)* @__gxx_
>  ; SELDAG-NEXT:   mov x29, x29
>  ;
>  entry:
> -  %call = call "rv_marker" i8* @foo1()
> +  %call = call i8* @foo1() [ "clang.arc.attachedcall"(i64 0) ]
>    invoke void @objc_object(i8* %call) #5
>            to label %invoke.cont unwind label %lpad
>
> @@ -87,7 +87,7 @@ entry:
>    %s = alloca %struct.S, align 1
>    %0 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0
>    call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %0) #2
> -  %call = invoke "rv_marker" i8* @foo1()
> +  %call = invoke i8* @foo1() [ "clang.arc.attachedcall"(i64 0) ]
>            to label %invoke.cont unwind label %lpad
>
>  invoke.cont:                                      ; preds = %entry
> @@ -127,12 +127,12 @@ define dso_local i8* @rv_marker_5_indirect_call() {
>  ;
>  entry:
>    %0 = load i8* ()*, i8* ()** @fptr, align 8
> -  %call = call "rv_marker" i8* %0()
> +  %call = call i8* %0() [ "clang.arc.attachedcall"(i64 0) ]
>    tail call void @foo2(i8* %call)
>    ret i8* %call
>  }
>
> -declare void @foo(i64, i64, i64)
> +declare i8* @foo(i64, i64, i64)
>
>  define dso_local void @rv_marker_multiarg(i64 %a, i64 %b, i64 %c) {
>  ; CHECK-LABEL: rv_marker_multiarg
> @@ -142,7 +142,7 @@ define dso_local void @rv_marker_multiarg(i64 %a, i64
> %b, i64 %c) {
>  ; CHECK-NEXT:   bl  foo
>  ; SELDAG-NEXT:  mov x29, x29
>  ; GISEL-NOT:    mov x29, x29
> -  call "rv_marker" void @foo(i64 %c, i64 %b, i64 %a)
> +  call i8* @foo(i64 %c, i64 %b, i64 %a) [ "clang.arc.attachedcall"(i64 0)
> ]
>    ret void
>  }
>
>
> diff  --git a/llvm/test/Transforms/DeadArgElim/deadretval.ll
> b/llvm/test/Transforms/DeadArgElim/deadretval.ll
> index 5f3817c6728dd..f3b343745e4d2 100644
> --- a/llvm/test/Transforms/DeadArgElim/deadretval.ll
> +++ b/llvm/test/Transforms/DeadArgElim/deadretval.ll
> @@ -1,4 +1,8 @@
> -; RUN: opt < %s -deadargelim -S | not grep DEAD
> +; RUN: opt < %s -deadargelim -S | FileCheck %s
> +
> + at g0 = global i8 0, align 8
> +
> +; CHECK-NOT: DEAD
>
>  ; Dead arg only used by dead retval
>  define internal i32 @test(i32 %DEADARG) {
> @@ -16,3 +20,22 @@ define i32 @test3() {
>          ret i32 %Y
>  }
>
> +; The callee function's return type shouldn't be changed if the call
> result is
> +; used.
> +
> +; CHECK-LABEL: define internal i8* @callee4()
> +
> +define internal i8* @callee4(i8* %a0) {
> +  ret i8* @g0;
> +}
> +
> +declare void @llvm.objc.clang.arc.noop.use(...)
> +
> +; CHECK-LABEL: define i8* @test4(
> +; CHECK: tail call i8* @callee4() [ "clang.arc.attachedcall"(i64 0) ]
> +
> +define i8* @test4() {
> +  %call = tail call i8* @callee4(i8* @g0) [ "clang.arc.attachedcall"(i64
> 0) ]
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %call)
> +  ret i8* @g0
> +}
>
> diff  --git a/llvm/test/Transforms/Inline/inline-retainRV-call.ll
> b/llvm/test/Transforms/Inline/inline-retainRV-call.ll
> new file mode 100644
> index 0000000000000..f8ac2154f9339
> --- /dev/null
> +++ b/llvm/test/Transforms/Inline/inline-retainRV-call.ll
> @@ -0,0 +1,175 @@
> +; RUN: opt < %s -inline -S | FileCheck %s
> +
> + at g0 = global i8* null, align 8
> +declare i8* @foo0()
> +
> +define i8* @callee0_autoreleaseRV() {
> +  %call = call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +  %1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call)
> +  ret i8* %call
> +}
> +
> +; CHECK-LABEL: define void @test0_autoreleaseRV(
> +; CHECK: call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +
> +define void @test0_autoreleaseRV() {
> +  %call = call i8* @callee0_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test0_claimRV_autoreleaseRV(
> +; CHECK: %[[CALL:.*]] = call i8* @foo0() [ "clang.arc.attachedcall"(i64
> 0) ]
> +; CHECK: call void @llvm.objc.release(i8* %[[CALL]])
> +; CHECK-NEXT: ret void
> +
> +define void @test0_claimRV_autoreleaseRV() {
> +  %call = call i8* @callee0_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 1) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test1_autoreleaseRV(
> +; CHECK: invoke i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +
> +define void @test1_autoreleaseRV() personality i8* bitcast (i32 (...)*
> @__gxx_personality_v0 to i8*) {
> +entry:
> +  %call = invoke i8* @callee0_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 0) ]
> +          to label %invoke.cont unwind label %lpad
> +
> +invoke.cont:
> +  ret void
> +
> +lpad:
> +  %0 = landingpad { i8*, i32 }
> +          cleanup
> +  resume { i8*, i32 } undef
> +}
> +
> +; CHECK-LABEL: define void @test1_claimRV_autoreleaseRV(
> +; CHECK: %[[INVOKE:.*]] = invoke i8* @foo0() [
> "clang.arc.attachedcall"(i64 0) ]
> +; CHECK: call void @llvm.objc.release(i8* %[[INVOKE]])
> +; CHECK-NEXT: br
> +
> +define void @test1_claimRV_autoreleaseRV() personality i8* bitcast (i32
> (...)* @__gxx_personality_v0 to i8*) {
> +entry:
> +  %call = invoke i8* @callee0_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 1) ]
> +          to label %invoke.cont unwind label %lpad
> +
> +invoke.cont:
> +  ret void
> +
> +lpad:
> +  %0 = landingpad { i8*, i32 }
> +          cleanup
> +  resume { i8*, i32 } undef
> +}
> +
> +define i8* @callee1_no_autoreleaseRV() {
> +  %call = call i8* @foo0()
> +  ret i8* %call
> +}
> +
> +; CHECK-LABEL: define void @test2_no_autoreleaseRV(
> +; CHECK: call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +; CHECK-NEXT: ret void
> +
> +define void @test2_no_autoreleaseRV() {
> +  %call = call i8* @callee1_no_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test2_claimRV_no_autoreleaseRV(
> +; CHECK: call i8* @foo0() [ "clang.arc.attachedcall"(i64 1) ]
> +; CHECK-NEXT: ret void
> +
> +define void @test2_claimRV_no_autoreleaseRV() {
> +  %call = call i8* @callee1_no_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 1) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test3_no_autoreleaseRV(
> +; CHECK: invoke i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +
> +define void @test3_no_autoreleaseRV() personality i8* bitcast (i32 (...)*
> @__gxx_personality_v0 to i8*) {
> +entry:
> +  %call = invoke i8* @callee1_no_autoreleaseRV() [
> "clang.arc.attachedcall"(i64 0) ]
> +          to label %invoke.cont unwind label %lpad
> +
> +invoke.cont:
> +  ret void
> +
> +lpad:
> +  %0 = landingpad { i8*, i32 }
> +          cleanup
> +  resume { i8*, i32 } undef
> +}
> +
> +define i8* @callee2_nocall() {
> +  %1 = load i8*, i8** @g0, align 8
> +  ret i8* %1
> +}
> +
> +; Check that a call to @llvm.objc.retain is inserted if there is no
> matching
> +; autoreleaseRV call or a call.
> +
> +; CHECK-LABEL: define void @test4_nocall(
> +; CHECK: %[[V0:.*]] = load i8*, i8** @g0,
> +; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %[[V0]])
> +; CHECK-NEXT: ret void
> +
> +define void @test4_nocall() {
> +  %call = call i8* @callee2_nocall() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test4_claimRV_nocall(
> +; CHECK: %[[V0:.*]] = load i8*, i8** @g0,
> +; CHECK-NEXT: ret void
> +
> +define void @test4_claimRV_nocall() {
> +  %call = call i8* @callee2_nocall() [ "clang.arc.attachedcall"(i64 1) ]
> +  ret void
> +}
> +
> +; Check that a call to @llvm.objc.retain is inserted if call to @foo
> already has
> +; the attribute. I'm not sure this will happen in practice.
> +
> +define i8* @callee3_marker() {
> +  %1 = call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret i8* %1
> +}
> +
> +; CHECK-LABEL: define void @test5(
> +; CHECK: %[[V0:.*]] = call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %[[V0]])
> +; CHECK-NEXT: ret void
> +
> +define void @test5() {
> +  %call = call i8* @callee3_marker() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +; Don't pair up an autoreleaseRV in the callee and an retainRV in the
> caller
> +; if there is an instruction between the ret instruction and the call to
> +; autoreleaseRV that isn't a cast instruction.
> +
> +define i8* @callee0_autoreleaseRV2() {
> +  %call = call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +  %1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call)
> +  store i8* null, i8** @g0
> +  ret i8* %call
> +}
> +
> +; CHECK-LABEL: define void @test6(
> +; CHECK: %[[V0:.*]] = call i8* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[V0]])
> +; CHECK: store i8* null, i8** @g0, align 8
> +; CHECK: call i8* @llvm.objc.retain(i8* %[[V0]])
> +; CHECK-NEXT: ret void
> +
> +define void @test6() {
> +  %call = call i8* @callee0_autoreleaseRV2() [
> "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
> +declare i32 @__gxx_personality_v0(...)
>
> diff  --git a/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll
> b/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll
> index c0d6e0033dda2..c40f411c9fb75 100644
> --- a/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll
> +++ b/llvm/test/Transforms/ObjCARC/contract-marker-funclet.ll
> @@ -10,6 +10,16 @@
>  ;   }
>  ; }
>
> +; CHECK-LABEL: define void @"\01?g@@YAXXZ"()
> +; CHECK-LABEL: catch
> +; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""() [
> "funclet"(token %1) ]
> +
> +; CHECK-LABEL: catch.1
> +; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""() [
> "funclet"(token %1) ]
> +
> +; CHECK-LABEL: invoke.cont
> +; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""(){{$}}
> +
>  define void @"\01?g@@YAXXZ"() personality i8* bitcast (i32 (...)*
> @__CxxFrameHandler3 to i8*) {
>  entry:
>    %call = invoke i8* @"\01?f@@YAPAUobjc_object@@XZ"()
> @@ -40,23 +50,41 @@ invoke.cont:                                      ;
> preds = %entry
>    ret void
>  }
>
> +; CHECK-LABEL: define dso_local void @"?test_attr_claimRV@@YAXXZ"()
> +; CHECK: %[[CALL4:.*]] = notail call i8* @"?noexcept_func@
> @YAPAUobjc_object@@XZ"() [ "clang.arc.attachedcall"(i64 1) ]
> +; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*
> %[[CALL4]])
> +
> +; CHECK: %[[V1:.*]] = cleanuppad
> +; CHECK: %[[CALL:.*]] = notail call i8* @"?noexcept_func@
> @YAPAUobjc_object@@XZ"() [ "funclet"(token %[[V1]]),
> "clang.arc.attachedcall"(i64 1) ]
> +; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*
> %[[CALL]]) [ "funclet"(token %[[V1]]) ]
> +
> +define dso_local void @"?test_attr_claimRV@@YAXXZ"() local_unnamed_addr
> #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
> +entry:
> +  invoke void @"?foo@@YAXXZ"()
> +          to label %invoke.cont unwind label %ehcleanup
> +
> +invoke.cont:                                      ; preds = %entry
> +  %call.i4 = tail call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() #2
> [ "clang.arc.attachedcall"(i64 1) ]
> +  ret void
> +
> +ehcleanup:                                        ; preds = %entry
> +  %0 = cleanuppad within none []
> +  %call.i = call i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"() #2 [
> "funclet"(token %0), "clang.arc.attachedcall"(i64 1) ]
> +  cleanupret from %0 unwind to caller
> +}
> +
>  declare i8* @"\01?f@@YAPAUobjc_object@@XZ"()
>
>  declare i32 @__CxxFrameHandler3(...)
>
> +declare void @"?foo@@YAXXZ"()
> +declare i8* @"?noexcept_func@@YAPAUobjc_object@@XZ"()
> +
>  declare dllimport i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
> +declare i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*)
>
>  declare dllimport void @llvm.objc.release(i8*)
>
>  !llvm.module.flags = !{!0}
>
>  !0 = !{i32 1, !"clang.arc.retainAutoreleasedReturnValueMarker",
> !"movl\09%ebp, %ebp\09\09// marker for objc_retainAutoreleaseReturnValue"}
> -
> -; CHECK-LABEL: catch
> -; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""() [
> "funclet"(token %1) ]
> -
> -; CHECK-LABEL: catch.1
> -; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""() [
> "funclet"(token %1) ]
> -
> -; CHECK-LABEL: invoke.cont
> -; CHECK: call void asm sideeffect "movl{{.*}}%ebp, %ebp{{.*}}", ""(){{$}}
>
> diff  --git a/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
> b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
> new file mode 100644
> index 0000000000000..3a817327c3638
> --- /dev/null
> +++ b/llvm/test/Transforms/ObjCARC/contract-rv-attr.ll
> @@ -0,0 +1,63 @@
> +; 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"(i64 0) ]
> +; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL]])
> +
> +define void @test0() {
> +  %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL: define void @test1() {
> +; CHECK: %[[CALL:.*]] = notail call i8* @foo() [
> "clang.arc.attachedcall"(i64 1) ]
> +; CHECK: call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8*
> %[[CALL]])
> +
> +define void @test1() {
> +  %call1 = call i8* @foo() [ "clang.arc.attachedcall"(i64 1) ]
> +  ret void
> +}
> +
> +; CHECK-LABEL:define i8* @test2(
> +; CHECK: %[[CALL1:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"(i64
> 0) ]
> +
> +; CHECK: %[[V0:.*]] = call i8*
> @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL1]])
> +; CHECK-NEXT: br
> +
> +; CHECK: %[[CALL3:.*]] = invoke i8* @foo() [ "clang.arc.attachedcall"(i64
> 0) ]
> +
> +; CHECK: %[[V2:.*]] = call i8*
> @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL3]])
> +; CHECK-NEXT: br
> +
> +; CHECK: %[[RETVAL:.*]] = phi i8* [ %[[V0]], {{.*}} ], [ %[[V2]], {{.*}} ]
> +; CHECK: ret i8* %[[RETVAL]]
> +
> +define i8* @test2(i1 zeroext %b) personality i8* bitcast (i32 (...)*
> @__gxx_personality_v0 to i8*) {
> +entry:
> +  br i1 %b, label %if.then, label %if.end
> +
> +if.then:
> +  %call1 = invoke i8* @foo() [ "clang.arc.attachedcall"(i64 0) ]
> +          to label %cleanup unwind label %lpad
> +
> +lpad:
> +  %0 = landingpad { i8*, i32 }
> +          cleanup
> +  resume { i8*, i32 } undef
> +
> +if.end:
> +  %call3 = invoke i8* @foo() [ "clang.arc.attachedcall"(i64 0) ]
> +          to label %cleanup unwind label %lpad
> +
> +cleanup:
> +  %retval.0 = phi i8* [ %call1, %if.then ], [ %call3, %if.end ]
> +  ret i8* %retval.0
> +}
> +
> +declare i8* @foo()
> +declare i32 @__gxx_personality_v0(...)
> +
> +!llvm.module.flags = !{!0}
> +
> +!0 = !{i32 1, !"clang.arc.retainAutoreleasedReturnValueMarker",
> !"mov\09fp, fp\09\09// marker for objc_retainAutoreleaseReturnValue"}
>
> diff  --git a/llvm/test/Transforms/ObjCARC/contract.ll
> b/llvm/test/Transforms/ObjCARC/contract.ll
> index d62fe221529e2..36f0a842d0e66 100644
> --- a/llvm/test/Transforms/ObjCARC/contract.ll
> +++ b/llvm/test/Transforms/ObjCARC/contract.ll
> @@ -227,7 +227,15 @@ define void @test13() {
>    ret void
>  }
>
> +; CHECK-LABEL: define void @test14(
> +; CHECK-NOT: clang.arc.noop.use
> +; CHECK: ret void
> +define void @test14(i8* %a, i8* %b) {
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %a, i8* %b) nounwind
> +  ret void
> +}
>
>  declare void @llvm.objc.clang.arc.use(...) nounwind
> +declare void @llvm.objc.clang.arc.noop.use(...) nounwind
>
>  ; CHECK: attributes [[NUW]] = { nounwind }
>
> diff  --git a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
> b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
> index 6f3815113d698..bd4ac2965fb34 100644
> --- a/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
> +++ b/llvm/test/Transforms/ObjCARC/intrinsic-use.ll
> @@ -8,8 +8,10 @@ declare void @llvm.objc.release(i8*)
>  declare i8* @llvm.objc.autorelease(i8*)
>
>  declare void @llvm.objc.clang.arc.use(...)
> +declare void @llvm.objc.clang.arc.noop.use(...)
>
>  declare void @test0_helper(i8*, i8**)
> +declare void @can_release(i8*)
>
>  ; Ensure that we honor clang.arc.use as a use and don't miscompile
>  ; the reduced test case from <rdar://13195034>.
> @@ -108,6 +110,21 @@ entry:
>    ret void
>  }
>
> +; ARC optimizer should be able to safely remove the retain/release pair
> as the
> +; call to @llvm.objc.clang.arc.noop.use is a no-op.
> +
> +; CHECK-LABEL: define void @test_arc_noop_use(
> +; CHECK-NEXT:    call void @can_release(i8* %x)
> +; CHECK-NEXT:    call void (...) @llvm.objc.clang.arc.noop.use(
> +; CHECK-NEXT:    ret void
> +
> +define void @test_arc_noop_use(i8** %out, i8* %x) {
> +  call i8* @llvm.objc.retain(i8* %x)
> +  call void @can_release(i8* %x)
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %x)
> +  call void @llvm.objc.release(i8* %x), !clang.imprecise_release !0
> +  ret void
> +}
>
>  !0 = !{}
>
>
> diff  --git a/llvm/test/Transforms/ObjCARC/rv.ll
> b/llvm/test/Transforms/ObjCARC/rv.ll
> index f89e9f7e39d99..29017222ebb11 100644
> --- a/llvm/test/Transforms/ObjCARC/rv.ll
> +++ b/llvm/test/Transforms/ObjCARC/rv.ll
> @@ -11,6 +11,7 @@ declare i8* @llvm.objc.retainAutoreleaseReturnValue(i8*)
>  declare void @llvm.objc.autoreleasePoolPop(i8*)
>  declare void @llvm.objc.autoreleasePoolPush()
>  declare i8* @llvm.objc.retainBlock(i8*)
> +declare void @llvm.objc.clang.arc.noop.use(...)
>
>  declare i8* @objc_retainedObject(i8*)
>  declare i8* @objc_unretainedObject(i8*)
> @@ -452,6 +453,32 @@ bb1:
>    ret i8* %v3
>  }
>
> +; Remove operand bundle "clang.arc.attachedcall" and the autoreleaseRV
> call if the call
> +; is a tail call.
> +
> +; CHECK-LABEL: define i8* @test31(
> +; CHECK-NEXT: %[[CALL:.*]] = tail call i8* @returner()
> +; CHECK-NEXT: ret i8* %[[CALL]]
> +
> +define i8* @test31() {
> +  %call = tail call i8* @returner() [ "clang.arc.attachedcall"(i64 0) ]
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %call)
> +  %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %call)
> +  ret i8* %1
> +}
> +
> +; CHECK-LABEL: define i8* @test32(
> +; CHECK: %[[CALL:.*]] = call i8* @returner() [
> "clang.arc.attachedcall"(i64 0) ]
> +; CHECK: call void (...) @llvm.objc.clang.arc.noop.use(i8* %[[CALL]])
> +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[CALL]])
> +
> +define i8* @test32() {
> +  %call = call i8* @returner() [ "clang.arc.attachedcall"(i64 0) ]
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %call)
> +  %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %call)
> +  ret i8* %1
> +}
> +
>  !0 = !{}
>
>  ; CHECK: attributes [[NUW]] = { nounwind }
>
> diff  --git a/llvm/test/Transforms/SCCP/clang-arc-rv.ll
> b/llvm/test/Transforms/SCCP/clang-arc-rv.ll
> new file mode 100644
> index 0000000000000..bb8f45b41c136
> --- /dev/null
> +++ b/llvm/test/Transforms/SCCP/clang-arc-rv.ll
> @@ -0,0 +1,24 @@
> +; RUN: opt < %s -ipsccp -S | FileCheck %s
> +; Return value can't be zapped if there is a call that has operand bundle
> +; "clang.arc.attachedcall".
> +
> + at g0 = global i8 zeroinitializer, align 1
> +
> +; CHECK-LABEL: @foo(
> +; CHECK: ret i8* @g0
> +
> +define internal i8* @foo() {
> +  ret i8* @g0
> +}
> +
> +; CHECK-LABEL: @test(
> +; CHECK: %[[R:.*]] = call i8* @foo()
> +; CHECK call void (...) @llvm.objc.clang.arc.noop.use(i8* %[[R]])
> +
> +define void @test() {
> +  %r = call i8* @foo() [ "clang.arc.attachedcall"(i64 1) ]
> +  call void (...) @llvm.objc.clang.arc.noop.use(i8* %r)
> +  ret void
> +}
> +
> +declare void @llvm.objc.clang.arc.noop.use(...)
>
> diff  --git a/llvm/test/Transforms/TailCallElim/deopt-bundle.ll
> b/llvm/test/Transforms/TailCallElim/deopt-bundle.ll
> index f651e462c1f56..a075849421716 100644
> --- a/llvm/test/Transforms/TailCallElim/deopt-bundle.ll
> +++ b/llvm/test/Transforms/TailCallElim/deopt-bundle.ll
> @@ -55,3 +55,13 @@ catch:
>  exit:
>    ret void
>  }
> +
> +; CHECK-LABEL: @test_clang_arc_attachedcall(
> +; CHECK: tail call i8* @getObj(
> +
> +declare i8* @getObj()
> +
> +define i8* @test_clang_arc_attachedcall() {
> +  %r = call i8* @getObj() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret i8* %r
> +}
>
> diff  --git a/llvm/test/Verifier/operand-bundles.ll
> b/llvm/test/Verifier/operand-bundles.ll
> index 2598a7889f3fd..4ef0e647988af 100644
> --- a/llvm/test/Verifier/operand-bundles.ll
> +++ b/llvm/test/Verifier/operand-bundles.ll
> @@ -1,10 +1,13 @@
>  ; RUN: not opt -verify < %s 2>&1 | FileCheck %s
>
> +%0 = type opaque
> +declare void @g()
> +declare %0* @foo0()
> +declare i8 @foo1()
> +
>  ; Operand bundles uses are like regular uses, and need to be dominated
>  ; by their defs.
>
> -declare void @g()
> -
>  define void @f0(i32* %ptr) {
>  ; CHECK: Instruction does not dominate all uses!
>  ; CHECK-NEXT:  %x = add i32 42, 1
> @@ -60,3 +63,15 @@ define void @f_gc_transition(i32* %ptr) {
>    %x = add i32 42, 1
>    ret void
>  }
> +
> +define void @f_clang_arc_attachedcall() {
> +; CHECK: Multiple "clang.arc.attachedcall" operand bundles
> +; CHECK-NEXT: call %0* @foo0() [ "clang.arc.attachedcall"(i64 0),
> "clang.arc.attachedcall"(i64 0) ]
> +; CHECK-NEXT: must call a function returning a pointer
> +; CHECK-NEXT: call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
> +
> +  call %0* @foo0() [ "clang.arc.attachedcall"(i64 0) ]
> +  call %0* @foo0() [ "clang.arc.attachedcall"(i64 0),
> "clang.arc.attachedcall"(i64 0) ]
> +  call i8 @foo1() [ "clang.arc.attachedcall"(i64 0) ]
> +  ret void
> +}
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210304/b0cb0cff/attachment-0001.html>


More information about the llvm-commits mailing list