r258962 - Emit calls to objc_unsafeClaimAutoreleasedReturnValue when

John McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 27 10:32:31 PST 2016


Author: rjmccall
Date: Wed Jan 27 12:32:30 2016
New Revision: 258962

URL: http://llvm.org/viewvc/llvm-project?rev=258962&view=rev
Log:
Emit calls to objc_unsafeClaimAutoreleasedReturnValue when
reclaiming a call result in order to ignore it or assign it
to an __unsafe_unretained variable.  This avoids adding
an unwanted retain/release pair when the return value is
not actually returned autoreleased (e.g. when it is returned
from a nonatomic getter or a typical collection accessor).

This runtime function is only available on the latest Apple
OS releases; the backwards-compatibility story is that you
don't get the optimization unless your deployment target is
recent enough.  Sorry.

rdar://20530049

Added:
    cfe/trunk/test/CodeGenObjC/arc-unsafeclaim.m
Modified:
    cfe/trunk/include/clang/Basic/ObjCRuntime.h
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/CodeGenModule.h

Modified: cfe/trunk/include/clang/Basic/ObjCRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/ObjCRuntime.h?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/ObjCRuntime.h (original)
+++ cfe/trunk/include/clang/Basic/ObjCRuntime.h Wed Jan 27 12:32:30 2016
@@ -308,6 +308,23 @@ public:
     }
   }
 
+  /// Is objc_unsafeClaimAutoreleasedReturnValue available?
+  bool hasARCUnsafeClaimAutoreleasedReturnValue() const {
+    switch (getKind()) {
+    case MacOSX:
+      return getVersion() >= VersionTuple(10, 11);
+    case iOS:
+      return getVersion() >= VersionTuple(9);
+    case WatchOS:
+      return getVersion() >= VersionTuple(2);
+    case GNUstep:
+      return false;
+
+    default:
+      return false;
+    }
+  }
+
   /// \brief Try to parse an Objective-C runtime specification from the given
   /// string.
   ///

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Jan 27 12:32:30 2016
@@ -715,8 +715,7 @@ void CodeGenFunction::EmitScalarInit(con
     llvm_unreachable("present but none");
 
   case Qualifiers::OCL_ExplicitNone:
-    // nothing to do
-    value = EmitScalarExpr(init);
+    value = EmitARCUnsafeUnretainedScalarExpr(init);
     break;
 
   case Qualifiers::OCL_Strong: {

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Wed Jan 27 12:32:30 2016
@@ -1366,8 +1366,9 @@ Value *ScalarExprEmitter::VisitCastExpr(
   QualType DestTy = CE->getType();
   CastKind Kind = CE->getCastKind();
 
-  if (!DestTy->isVoidType())
-    TestAndClearIgnoreResultAssign();
+  // These cases are generally not written to ignore the result of
+  // evaluating their sub-expressions, so we clear this now.
+  bool Ignored = TestAndClearIgnoreResultAssign();
 
   // Since almost all cast kinds apply to scalars, this switch doesn't have
   // a default case, so the compiler will warn on a missing case.  The cases
@@ -1494,11 +1495,8 @@ Value *ScalarExprEmitter::VisitCastExpr(
     return CGF.EmitARCRetainScalarExpr(E);
   case CK_ARCConsumeObject:
     return CGF.EmitObjCConsumeObject(E->getType(), Visit(E));
-  case CK_ARCReclaimReturnedObject: {
-    llvm::Value *value = Visit(E);
-    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
-    return CGF.EmitObjCConsumeObject(E->getType(), value);
-  }
+  case CK_ARCReclaimReturnedObject:
+    return CGF.EmitARCReclaimReturnedObject(E, /*allowUnsafe*/ Ignored);
   case CK_ARCExtendBlockObject:
     return CGF.EmitARCExtendBlockObject(E);
 
@@ -2993,15 +2991,17 @@ Value *ScalarExprEmitter::VisitBinAssign
     std::tie(LHS, RHS) = CGF.EmitARCStoreAutoreleasing(E);
     break;
 
+  case Qualifiers::OCL_ExplicitNone:
+    std::tie(LHS, RHS) = CGF.EmitARCStoreUnsafeUnretained(E, Ignore);
+    break;
+
   case Qualifiers::OCL_Weak:
     RHS = Visit(E->getRHS());
     LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
     RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore);
     break;
 
-  // No reason to do any of these differently.
   case Qualifiers::OCL_None:
-  case Qualifiers::OCL_ExplicitNone:
     // __block variables need to have the rhs evaluated first, plus
     // this should improve codegen just a little.
     RHS = Visit(E->getRHS());

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Wed Jan 27 12:32:30 2016
@@ -1980,20 +1980,14 @@ llvm::Value *CodeGenFunction::EmitARCRet
   return result;
 }
 
-/// Retain the given object which is the result of a function call.
-///   call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
-///
-/// Yes, this function name is one character away from a different
-/// call with completely different semantics.
-llvm::Value *
-CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
   // Fetch the void(void) inline asm which marks that we're going to
-  // retain the autoreleased return value.
+  // do something with the autoreleased return value.
   llvm::InlineAsm *&marker
-    = CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
+    = CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
   if (!marker) {
     StringRef assembly
-      = CGM.getTargetCodeGenInfo()
+      = CGF.CGM.getTargetCodeGenInfo()
            .getARCRetainAutoreleasedReturnValueMarker();
 
     // If we have an empty assembly string, there's nothing to do.
@@ -2001,9 +1995,9 @@ CodeGenFunction::EmitARCRetainAutoreleas
 
     // Otherwise, at -O0, build an inline asm that we're going to call
     // in a moment.
-    } else if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+    } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
       llvm::FunctionType *type =
-        llvm::FunctionType::get(VoidTy, /*variadic*/false);
+        llvm::FunctionType::get(CGF.VoidTy, /*variadic*/false);
       
       marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
 
@@ -2012,25 +2006,50 @@ CodeGenFunction::EmitARCRetainAutoreleas
     // optimizer to pick up.
     } else {
       llvm::NamedMDNode *metadata =
-        CGM.getModule().getOrInsertNamedMetadata(
+        CGF.CGM.getModule().getOrInsertNamedMetadata(
                             "clang.arc.retainAutoreleasedReturnValueMarker");
       assert(metadata->getNumOperands() <= 1);
       if (metadata->getNumOperands() == 0) {
-        metadata->addOperand(llvm::MDNode::get(
-            getLLVMContext(), llvm::MDString::get(getLLVMContext(), assembly)));
+        auto &ctx = CGF.getLLVMContext();
+        metadata->addOperand(llvm::MDNode::get(ctx,
+                                     llvm::MDString::get(ctx, assembly)));
       }
     }
   }
 
   // Call the marker asm if we made one, which we do only at -O0.
   if (marker)
-    Builder.CreateCall(marker);
+    CGF.Builder.CreateCall(marker);
+}
 
+/// Retain the given object which is the result of a function call.
+///   call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
+///
+/// Yes, this function name is one character away from a different
+/// call with completely different semantics.
+llvm::Value *
+CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
+  emitAutoreleasedReturnValueMarker(*this);
   return emitARCValueOperation(*this, value,
-                     CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
+              CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
                                "objc_retainAutoreleasedReturnValue");
 }
 
+/// Claim a possibly-autoreleased return value at +0.  This is only
+/// valid to do in contexts which do not rely on the retain to keep
+/// the object valid for for all of its uses; for example, when
+/// the value is ignored, or when it is being assigned to an
+/// __unsafe_unretained variable.
+///
+///   call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
+llvm::Value *
+CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
+  emitAutoreleasedReturnValueMarker(*this);
+  return emitARCValueOperation(*this, value,
+              CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
+                               "objc_unsafeClaimAutoreleasedReturnValue");
+}
+
 /// Release the given object.
 ///   call void \@objc_release(i8* %value)
 void CodeGenFunction::EmitARCRelease(llvm::Value *value,
@@ -2446,25 +2465,22 @@ static TryEmitResult tryEmitARCRetainLoa
   return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
 }
 
-static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
-                                           llvm::Value *value);
-
-/// Given that the given expression is some sort of call (which does
-/// not return retained), emit a retain following it.
-static llvm::Value *emitARCRetainCall(CodeGenFunction &CGF, const Expr *e) {
-  llvm::Value *value = CGF.EmitScalarExpr(e);
-  return emitARCRetainAfterCall(CGF, value);
-}
-
-static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
-                                           llvm::Value *value) {
+typedef llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
+                                         llvm::Value *value)>
+  ValueTransform;
+
+/// Insert code immediately after a call.
+static llvm::Value *emitARCOperationAfterCall(CodeGenFunction &CGF,
+                                              llvm::Value *value,
+                                              ValueTransform doAfterCall,
+                                              ValueTransform doFallback) {
   if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
     CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
 
     // Place the retain immediately following the call.
     CGF.Builder.SetInsertPoint(call->getParent(),
                                ++llvm::BasicBlock::iterator(call));
-    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+    value = doAfterCall(CGF, value);
 
     CGF.Builder.restoreIP(ip);
     return value;
@@ -2474,7 +2490,7 @@ static llvm::Value *emitARCRetainAfterCa
     // Place the retain at the beginning of the normal destination block.
     llvm::BasicBlock *BB = invoke->getNormalDest();
     CGF.Builder.SetInsertPoint(BB, BB->begin());
-    value = CGF.EmitARCRetainAutoreleasedReturnValue(value);
+    value = doAfterCall(CGF, value);
 
     CGF.Builder.restoreIP(ip);
     return value;
@@ -2483,7 +2499,7 @@ static llvm::Value *emitARCRetainAfterCa
   // the operand.
   } else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
     llvm::Value *operand = bitcast->getOperand(0);
-    operand = emitARCRetainAfterCall(CGF, operand);
+    operand = emitARCOperationAfterCall(CGF, operand, doAfterCall, doFallback);
     bitcast->setOperand(0, operand);
     return bitcast;
 
@@ -2491,7 +2507,46 @@ static llvm::Value *emitARCRetainAfterCa
   } else {
     // Retain using the non-block variant: we never need to do a copy
     // of a block that's been returned to us.
-    return CGF.EmitARCRetainNonBlock(value);
+    return doFallback(CGF, value);
+  }
+}
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), emit a retain following it.
+static llvm::Value *emitARCRetainCallResult(CodeGenFunction &CGF,
+                                            const Expr *e) {
+  llvm::Value *value = CGF.EmitScalarExpr(e);
+  return emitARCOperationAfterCall(CGF, value,
+           [](CodeGenFunction &CGF, llvm::Value *value) {
+             return CGF.EmitARCRetainAutoreleasedReturnValue(value);
+           },
+           [](CodeGenFunction &CGF, llvm::Value *value) {
+             return CGF.EmitARCRetainNonBlock(value);
+           });
+}
+
+/// Given that the given expression is some sort of call (which does
+/// not return retained), perform an unsafeClaim following it.
+static llvm::Value *emitARCUnsafeClaimCallResult(CodeGenFunction &CGF,
+                                                 const Expr *e) {
+  llvm::Value *value = CGF.EmitScalarExpr(e);
+  return emitARCOperationAfterCall(CGF, value,
+           [](CodeGenFunction &CGF, llvm::Value *value) {
+             return CGF.EmitARCUnsafeClaimAutoreleasedReturnValue(value);
+           },
+           [](CodeGenFunction &CGF, llvm::Value *value) {
+             return value;
+           });
+}
+
+llvm::Value *CodeGenFunction::EmitARCReclaimReturnedObject(const Expr *E,
+                                                      bool allowUnsafeClaim) {
+  if (allowUnsafeClaim &&
+      CGM.getLangOpts().ObjCRuntime.hasARCUnsafeClaimAutoreleasedReturnValue()) {
+    return emitARCUnsafeClaimCallResult(*this, E);
+  } else {
+    llvm::Value *value = emitARCRetainCallResult(*this, E);
+    return EmitObjCConsumeObject(E->getType(), value);
   }
 }
 
@@ -2531,17 +2586,52 @@ static bool shouldEmitSeparateBlockRetai
   return true;
 }
 
-/// Try to emit a PseudoObjectExpr at +1.
+namespace {
+/// A CRTP base class for emitting expressions of retainable object
+/// pointer type in ARC.
+template <typename Impl, typename Result> class ARCExprEmitter {
+protected:
+  CodeGenFunction &CGF;
+  Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+  ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {}
+
+public:
+  Result visit(const Expr *e);
+  Result visitCastExpr(const CastExpr *e);
+  Result visitPseudoObjectExpr(const PseudoObjectExpr *e);
+  Result visitBinaryOperator(const BinaryOperator *e);
+  Result visitBinAssign(const BinaryOperator *e);
+  Result visitBinAssignUnsafeUnretained(const BinaryOperator *e);
+  Result visitBinAssignAutoreleasing(const BinaryOperator *e);
+  Result visitBinAssignWeak(const BinaryOperator *e);
+  Result visitBinAssignStrong(const BinaryOperator *e);
+
+  // Minimal implementation:
+  //   Result visitLValueToRValue(const Expr *e)
+  //   Result visitConsumeObject(const Expr *e)
+  //   Result visitExtendBlockObject(const Expr *e)
+  //   Result visitReclaimReturnedObject(const Expr *e)
+  //   Result visitCall(const Expr *e)
+  //   Result visitExpr(const Expr *e)
+  //
+  //   Result emitBitCast(Result result, llvm::Type *resultType)
+  //   llvm::Value *getValueOfResult(Result result)
+};
+}
+
+/// Try to emit a PseudoObjectExpr under special ARC rules.
 ///
 /// This massively duplicates emitPseudoObjectRValue.
-static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
-                                                  const PseudoObjectExpr *E) {
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitPseudoObjectExpr(const PseudoObjectExpr *E) {
   SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
 
   // Find the result expression.
   const Expr *resultExpr = E->getResultExpr();
   assert(resultExpr);
-  TryEmitResult result;
+  Result result;
 
   for (PseudoObjectExpr::const_semantics_iterator
          i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
@@ -2557,8 +2647,9 @@ static TryEmitResult tryEmitARCRetainPse
       // expression, try to evaluate the source as +1.
       if (ov == resultExpr) {
         assert(!OVMA::shouldBindAsLValue(ov));
-        result = tryEmitARCRetainScalarExpr(CGF, ov->getSourceExpr());
-        opaqueData = OVMA::bind(CGF, ov, RValue::get(result.getPointer()));
+        result = asImpl().visit(ov->getSourceExpr());
+        opaqueData = OVMA::bind(CGF, ov,
+                            RValue::get(asImpl().getValueOfResult(result)));
 
       // Otherwise, just bind it.
       } else {
@@ -2569,7 +2660,7 @@ static TryEmitResult tryEmitARCRetainPse
     // Otherwise, if the expression is the result, evaluate it
     // and remember the result.
     } else if (semantic == resultExpr) {
-      result = tryEmitARCRetainScalarExpr(CGF, semantic);
+      result = asImpl().visit(semantic);
 
     // Otherwise, evaluate the expression in an ignored context.
     } else {
@@ -2584,146 +2675,240 @@ static TryEmitResult tryEmitARCRetainPse
   return result;
 }
 
-static TryEmitResult
-tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) {
+  switch (e->getCastKind()) {
+
+  // No-op casts don't change the type, so we just ignore them.
+  case CK_NoOp:
+    return asImpl().visit(e->getSubExpr());
+
+  // These casts can change the type.
+  case CK_CPointerToObjCPointerCast:
+  case CK_BlockPointerToObjCPointerCast:
+  case CK_AnyPointerToBlockPointerCast:
+  case CK_BitCast: {
+    llvm::Type *resultType = CGF.ConvertType(e->getType());
+    assert(e->getSubExpr()->getType()->hasPointerRepresentation());
+    Result result = asImpl().visit(e->getSubExpr());
+    return asImpl().emitBitCast(result, resultType);
+  }
+
+  // Handle some casts specially.
+  case CK_LValueToRValue:
+    return asImpl().visitLValueToRValue(e->getSubExpr());
+  case CK_ARCConsumeObject:
+    return asImpl().visitConsumeObject(e->getSubExpr());
+  case CK_ARCExtendBlockObject:
+    return asImpl().visitExtendBlockObject(e->getSubExpr());
+  case CK_ARCReclaimReturnedObject:
+    return asImpl().visitReclaimReturnedObject(e->getSubExpr());
+
+  // Otherwise, use the default logic.
+  default:
+    return asImpl().visitExpr(e);
+  }
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinaryOperator(const BinaryOperator *e) {
+  switch (e->getOpcode()) {
+  case BO_Comma:
+    CGF.EmitIgnoredExpr(e->getLHS());
+    CGF.EnsureInsertPoint();
+    return asImpl().visit(e->getRHS());
+
+  case BO_Assign:
+    return asImpl().visitBinAssign(e);
+
+  default:
+    return asImpl().visitExpr(e);
+  }
+}
+
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visitBinAssign(const BinaryOperator *e) {
+  switch (e->getLHS()->getType().getObjCLifetime()) {
+  case Qualifiers::OCL_ExplicitNone:
+    return asImpl().visitBinAssignUnsafeUnretained(e);
+
+  case Qualifiers::OCL_Weak:
+    return asImpl().visitBinAssignWeak(e);
+
+  case Qualifiers::OCL_Autoreleasing:
+    return asImpl().visitBinAssignAutoreleasing(e);
+
+  case Qualifiers::OCL_Strong:
+    return asImpl().visitBinAssignStrong(e);
+
+  case Qualifiers::OCL_None:
+    return asImpl().visitExpr(e);
+  }
+  llvm_unreachable("bad ObjC ownership qualifier");
+}
+
+/// The default rule for __unsafe_unretained emits the RHS recursively,
+/// stores into the unsafe variable, and propagates the result outward.
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::
+                    visitBinAssignUnsafeUnretained(const BinaryOperator *e) {
+  // Recursively emit the RHS.
+  // For __block safety, do this before emitting the LHS.
+  Result result = asImpl().visit(e->getRHS());
+
+  // Perform the store.
+  LValue lvalue =
+    CGF.EmitCheckedLValue(e->getLHS(), CodeGenFunction::TCK_Store);
+  CGF.EmitStoreThroughLValue(RValue::get(asImpl().getValueOfResult(result)),
+                             lvalue);
+
+  return result;
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignAutoreleasing(const BinaryOperator *e) {
+  return asImpl().visitExpr(e);
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignWeak(const BinaryOperator *e) {
+  return asImpl().visitExpr(e);
+}
+
+template <typename Impl, typename Result>
+Result
+ARCExprEmitter<Impl,Result>::visitBinAssignStrong(const BinaryOperator *e) {
+  return asImpl().visitExpr(e);
+}
+
+/// The general expression-emission logic.
+template <typename Impl, typename Result>
+Result ARCExprEmitter<Impl,Result>::visit(const Expr *e) {
   // We should *never* see a nested full-expression here, because if
   // we fail to emit at +1, our caller must not retain after we close
-  // out the full-expression.
+  // out the full-expression.  This isn't as important in the unsafe
+  // emitter.
   assert(!isa<ExprWithCleanups>(e));
 
-  // The desired result type, if it differs from the type of the
-  // ultimate opaque expression.
-  llvm::Type *resultType = nullptr;
-
-  while (true) {
-    e = e->IgnoreParens();
-
-    // There's a break at the end of this if-chain;  anything
-    // that wants to keep looping has to explicitly continue.
-    if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
-      switch (ce->getCastKind()) {
-      // No-op casts don't change the type, so we just ignore them.
-      case CK_NoOp:
-        e = ce->getSubExpr();
-        continue;
-
-      case CK_LValueToRValue: {
-        TryEmitResult loadResult
-          = tryEmitARCRetainLoadOfScalar(CGF, ce->getSubExpr());
-        if (resultType) {
-          llvm::Value *value = loadResult.getPointer();
-          value = CGF.Builder.CreateBitCast(value, resultType);
-          loadResult.setPointer(value);
-        }
-        return loadResult;
-      }
+  // Look through parens, __extension__, generic selection, etc.
+  e = e->IgnoreParens();
 
-      // These casts can change the type, so remember that and
-      // soldier on.  We only need to remember the outermost such
-      // cast, though.
-      case CK_CPointerToObjCPointerCast:
-      case CK_BlockPointerToObjCPointerCast:
-      case CK_AnyPointerToBlockPointerCast:
-      case CK_BitCast:
-        if (!resultType)
-          resultType = CGF.ConvertType(ce->getType());
-        e = ce->getSubExpr();
-        assert(e->getType()->hasPointerRepresentation());
-        continue;
-
-      // For consumptions, just emit the subexpression and thus elide
-      // the retain/release pair.
-      case CK_ARCConsumeObject: {
-        llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
-        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
-        return TryEmitResult(result, true);
-      }
+  // Handle certain kinds of casts.
+  if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
+    return asImpl().visitCastExpr(ce);
+
+  // Handle the comma operator.
+  } else if (auto op = dyn_cast<BinaryOperator>(e)) {
+    return asImpl().visitBinaryOperator(op);
+
+  // TODO: handle conditional operators here
+
+  // For calls and message sends, use the retained-call logic.
+  // Delegate inits are a special case in that they're the only
+  // returns-retained expression that *isn't* surrounded by
+  // a consume.
+  } else if (isa<CallExpr>(e) ||
+             (isa<ObjCMessageExpr>(e) &&
+              !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
+    return asImpl().visitCall(e);
+
+  // Look through pseudo-object expressions.
+  } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
+    return asImpl().visitPseudoObjectExpr(pseudo);
+  }
 
-      // Block extends are net +0.  Naively, we could just recurse on
-      // the subexpression, but actually we need to ensure that the
-      // value is copied as a block, so there's a little filter here.
-      case CK_ARCExtendBlockObject: {
-        llvm::Value *result; // will be a +0 value
-
-        // If we can't safely assume the sub-expression will produce a
-        // block-copied value, emit the sub-expression at +0.
-        if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) {
-          result = CGF.EmitScalarExpr(ce->getSubExpr());
-
-        // Otherwise, try to emit the sub-expression at +1 recursively.
-        } else {
-          TryEmitResult subresult
-            = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr());
-          result = subresult.getPointer();
-
-          // If that produced a retained value, just use that,
-          // possibly casting down.
-          if (subresult.getInt()) {
-            if (resultType)
-              result = CGF.Builder.CreateBitCast(result, resultType);
-            return TryEmitResult(result, true);
-          }
-
-          // Otherwise it's +0.
-        }
-
-        // Retain the object as a block, then cast down.
-        result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
-        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
-        return TryEmitResult(result, true);
-      }
+  return asImpl().visitExpr(e);
+}
 
-      // For reclaims, emit the subexpression as a retained call and
-      // skip the consumption.
-      case CK_ARCReclaimReturnedObject: {
-        llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
-        if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
-        return TryEmitResult(result, true);
-      }
+namespace {
 
-      default:
-        break;
-      }
+/// An emitter for +1 results.
+struct ARCRetainExprEmitter :
+  public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> {
 
-    // Skip __extension__.
-    } else if (const UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
-      if (op->getOpcode() == UO_Extension) {
-        e = op->getSubExpr();
-        continue;
-      }
+  ARCRetainExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
+
+  llvm::Value *getValueOfResult(TryEmitResult result) {
+    return result.getPointer();
+  }
+
+  TryEmitResult emitBitCast(TryEmitResult result, llvm::Type *resultType) {
+    llvm::Value *value = result.getPointer();
+    value = CGF.Builder.CreateBitCast(value, resultType);
+    result.setPointer(value);
+    return result;
+  }
+
+  TryEmitResult visitLValueToRValue(const Expr *e) {
+    return tryEmitARCRetainLoadOfScalar(CGF, e);
+  }
+
+  /// For consumptions, just emit the subexpression and thus elide
+  /// the retain/release pair.
+  TryEmitResult visitConsumeObject(const Expr *e) {
+    llvm::Value *result = CGF.EmitScalarExpr(e);
+    return TryEmitResult(result, true);
+  }
+
+  /// Block extends are net +0.  Naively, we could just recurse on
+  /// the subexpression, but actually we need to ensure that the
+  /// value is copied as a block, so there's a little filter here.
+  TryEmitResult visitExtendBlockObject(const Expr *e) {
+    llvm::Value *result; // will be a +0 value
+
+    // If we can't safely assume the sub-expression will produce a
+    // block-copied value, emit the sub-expression at +0.
+    if (shouldEmitSeparateBlockRetain(e)) {
+      result = CGF.EmitScalarExpr(e);
 
-    // For calls and message sends, use the retained-call logic.
-    // Delegate inits are a special case in that they're the only
-    // returns-retained expression that *isn't* surrounded by
-    // a consume.
-    } else if (isa<CallExpr>(e) ||
-               (isa<ObjCMessageExpr>(e) &&
-                !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
-      llvm::Value *result = emitARCRetainCall(CGF, e);
-      if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
-      return TryEmitResult(result, true);
-
-    // Look through pseudo-object expressions.
-    } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
-      TryEmitResult result
-        = tryEmitARCRetainPseudoObject(CGF, pseudo);
-      if (resultType) {
-        llvm::Value *value = result.getPointer();
-        value = CGF.Builder.CreateBitCast(value, resultType);
-        result.setPointer(value);
+    // Otherwise, try to emit the sub-expression at +1 recursively.
+    } else {
+      TryEmitResult subresult = asImpl().visit(e);
+
+      // If that produced a retained value, just use that.
+      if (subresult.getInt()) {
+        return subresult;
       }
-      return result;
+
+      // Otherwise it's +0.
+      result = subresult.getPointer();
     }
 
-    // Conservatively halt the search at any other expression kind.
-    break;
+    // Retain the object as a block.
+    result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
+    return TryEmitResult(result, true);
   }
 
-  // We didn't find an obvious production, so emit what we've got and
-  // tell the caller that we didn't manage to retain.
-  llvm::Value *result = CGF.EmitScalarExpr(e);
-  if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
-  return TryEmitResult(result, false);
+  /// For reclaims, emit the subexpression as a retained call and
+  /// skip the consumption.
+  TryEmitResult visitReclaimReturnedObject(const Expr *e) {
+    llvm::Value *result = emitARCRetainCallResult(CGF, e);
+    return TryEmitResult(result, true);
+  }
+
+  /// When we have an undecorated call, retroactively do a claim.
+  TryEmitResult visitCall(const Expr *e) {
+    llvm::Value *result = emitARCRetainCallResult(CGF, e);
+    return TryEmitResult(result, true);
+  }
+
+  // TODO: maybe special-case visitBinAssignWeak?
+
+  TryEmitResult visitExpr(const Expr *e) {
+    // We didn't find an obvious production, so emit what we've got and
+    // tell the caller that we didn't manage to retain.
+    llvm::Value *result = CGF.EmitScalarExpr(e);
+    return TryEmitResult(result, false);
+  }
+};
+}
+
+static TryEmitResult
+tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+  return ARCRetainExprEmitter(CGF).visit(e);
 }
 
 static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
@@ -2807,6 +2992,96 @@ llvm::Value *CodeGenFunction::EmitObjCTh
   return EmitScalarExpr(expr);
 }
 
+namespace {
+
+/// An emitter for assigning into an __unsafe_unretained context.
+struct ARCUnsafeUnretainedExprEmitter :
+  public ARCExprEmitter<ARCUnsafeUnretainedExprEmitter, llvm::Value*> {
+
+  ARCUnsafeUnretainedExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
+
+  llvm::Value *getValueOfResult(llvm::Value *value) {
+    return value;
+  }
+
+  llvm::Value *emitBitCast(llvm::Value *value, llvm::Type *resultType) {
+    return CGF.Builder.CreateBitCast(value, resultType);
+  }
+
+  llvm::Value *visitLValueToRValue(const Expr *e) {
+    return CGF.EmitScalarExpr(e);
+  }
+
+  /// For consumptions, just emit the subexpression and perform the
+  /// consumption like normal.
+  llvm::Value *visitConsumeObject(const Expr *e) {
+    llvm::Value *value = CGF.EmitScalarExpr(e);
+    return CGF.EmitObjCConsumeObject(e->getType(), value);
+  }
+
+  /// No special logic for block extensions.  (This probably can't
+  /// actually happen in this emitter, though.)
+  llvm::Value *visitExtendBlockObject(const Expr *e) {
+    return CGF.EmitARCExtendBlockObject(e);
+  }
+
+  /// For reclaims, perform an unsafeClaim if that's enabled.
+  llvm::Value *visitReclaimReturnedObject(const Expr *e) {
+    return CGF.EmitARCReclaimReturnedObject(e, /*unsafe*/ true);
+  }
+
+  /// When we have an undecorated call, just emit it without adding
+  /// the unsafeClaim.
+  llvm::Value *visitCall(const Expr *e) {
+    return CGF.EmitScalarExpr(e);
+  }
+
+  /// Just do normal scalar emission in the default case.
+  llvm::Value *visitExpr(const Expr *e) {
+    return CGF.EmitScalarExpr(e);
+  }
+};
+}
+
+static llvm::Value *emitARCUnsafeUnretainedScalarExpr(CodeGenFunction &CGF,
+                                                      const Expr *e) {
+  return ARCUnsafeUnretainedExprEmitter(CGF).visit(e);
+}
+
+/// EmitARCUnsafeUnretainedScalarExpr - Semantically equivalent to
+/// immediately releasing the resut of EmitARCRetainScalarExpr, but
+/// avoiding any spurious retains, including by performing reclaims
+/// with objc_unsafeClaimAutoreleasedReturnValue.
+llvm::Value *CodeGenFunction::EmitARCUnsafeUnretainedScalarExpr(const Expr *e) {
+  // Look through full-expressions.
+  if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+    enterFullExpression(cleanups);
+    RunCleanupsScope scope(*this);
+    return emitARCUnsafeUnretainedScalarExpr(*this, cleanups->getSubExpr());
+  }
+
+  return emitARCUnsafeUnretainedScalarExpr(*this, e);
+}
+
+std::pair<LValue,llvm::Value*>
+CodeGenFunction::EmitARCStoreUnsafeUnretained(const BinaryOperator *e,
+                                              bool ignored) {
+  // Evaluate the RHS first.  If we're ignoring the result, assume
+  // that we can emit at an unsafe +0.
+  llvm::Value *value;
+  if (ignored) {
+    value = EmitARCUnsafeUnretainedScalarExpr(e->getRHS());
+  } else {
+    value = EmitScalarExpr(e->getRHS());
+  }
+
+  // Emit the LHS and perform the store.
+  LValue lvalue = EmitLValue(e->getLHS());
+  EmitStoreOfScalar(value, lvalue);
+
+  return std::pair<LValue,llvm::Value*>(std::move(lvalue), value);
+}
+
 std::pair<LValue,llvm::Value*>
 CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
                                     bool ignored) {

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Wed Jan 27 12:32:30 2016
@@ -2807,19 +2807,25 @@ public:
   llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
   llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
   llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
+  llvm::Value *EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value);
 
   std::pair<LValue,llvm::Value*>
   EmitARCStoreAutoreleasing(const BinaryOperator *e);
   std::pair<LValue,llvm::Value*>
   EmitARCStoreStrong(const BinaryOperator *e, bool ignored);
+  std::pair<LValue,llvm::Value*>
+  EmitARCStoreUnsafeUnretained(const BinaryOperator *e, bool ignored);
 
   llvm::Value *EmitObjCThrowOperand(const Expr *expr);
   llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
   llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
 
   llvm::Value *EmitARCExtendBlockObject(const Expr *expr);
+  llvm::Value *EmitARCReclaimReturnedObject(const Expr *e,
+                                            bool allowUnsafeClaim);
   llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
   llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+  llvm::Value *EmitARCUnsafeUnretainedScalarExpr(const Expr *expr);
 
   void EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values);
 

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=258962&r1=258961&r2=258962&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Wed Jan 27 12:32:30 2016
@@ -166,6 +166,9 @@ struct ObjCEntrypoints {
   /// id objc_storeWeak(id*, id);
   llvm::Constant *objc_storeWeak;
 
+  /// id objc_unsafeClaimAutoreleasedReturnValue(id);
+  llvm::Constant *objc_unsafeClaimAutoreleasedReturnValue;
+
   /// A void(void) inline asm to use to mark that the return value of
   /// a call will be immediately retain.
   llvm::InlineAsm *retainAutoreleasedReturnValueMarker;

Added: cfe/trunk/test/CodeGenObjC/arc-unsafeclaim.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-unsafeclaim.m?rev=258962&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-unsafeclaim.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-unsafeclaim.m Wed Jan 27 12:32:30 2016
@@ -0,0 +1,231 @@
+//   Make sure it works on x86-64.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime=macosx-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED
+
+//   Make sure it works on ARM.
+// 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
+// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED
+
+//   Make sure it works on ARM64.
+// 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
+// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-optzns -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED
+
+//   Make sure that it's implicitly disabled if the runtime version isn't high enough.
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED
+// RUN: %clang_cc1 -triple arm64-apple-ios8 -fobjc-runtime=ios-8 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED -check-prefix=DISABLED-MARKED
+
+ 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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT:           ret void
+
+// DISABLED-LABEL:     define void @test_assign()
+// DISABLED:             [[T0:%.*]] = call [[A:.*]]* @makeA()
+// DISABLED-MARKED-NEXT: call void asm sideeffect
+// DISABLED-NEXT:        [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// DISABLED-NEXT:        [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+
+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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT:           [[OLD:%.*]] = load i8*, i8** [[X]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT:           call void @objc_release(i8* [[OLD]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           [[OLD:%.*]] = load i8*, i8** [[Y]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-NEXT:           call void @objc_release(i8* [[OLD]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[Y]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[Y]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-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()
+// CHECK-MARKED-NEXT:    call void asm sideeffect
+// CHECK-NEXT:           [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:           [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:           [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:           [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8*
+// CHECK-NEXT:           [[OLD:%.*]] = load i8*, i8** [[X]]
+// CHECK-NEXT:           store i8* [[T4]], i8** [[X]]
+// CHECK-NEXT:           call void @objc_release(i8* [[OLD]])
+// CHECK-NEXT:           store i8* [[T4]], i8** [[Y]]
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-UNOPTIMIZED-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+// CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
+// CHECK-OPTIMIZED-NEXT: call void @objc_release(i8* [[T0]])
+// CHECK-OPTIMIZED-NEXT: bitcast
+// CHECK-OPTIMIZED-NEXT: lifetime.end
+// CHECK-NEXT: ret void
+
+void test_ignored() {
+  makeA();
+}
+// CHECK-LABEL:     define void @test_ignored()
+// CHECK:             [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT:        [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:        [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:        bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:        ret void
+
+void test_cast_to_void() {
+  (void) makeA();
+}
+// CHECK-LABEL:     define void @test_cast_to_void()
+// CHECK:             [[T0:%.*]] = call [[A]]* @makeA()
+// CHECK-MARKED-NEXT: call void asm sideeffect
+// CHECK-NEXT:        [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8*
+// CHECK-NEXT:        [[T2:%.*]] = call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* [[T1]])
+// CHECK-NEXT:        bitcast i8* [[T2]] to [[A]]*
+// CHECK-NEXT:        ret void
+
+
+
+// This is always at the end of the module.
+
+// CHECK-OPTIMIZED: !clang.arc.retainAutoreleasedReturnValueMarker = !{!0}




More information about the cfe-commits mailing list