r176924 - Tighten up the rules for precise lifetime and document

John McCall rjmccall at apple.com
Tue Mar 12 20:10:55 PDT 2013


Author: rjmccall
Date: Tue Mar 12 22:10:54 2013
New Revision: 176924

URL: http://llvm.org/viewvc/llvm-project?rev=176924&view=rev
Log:
Tighten up the rules for precise lifetime and document
the requirements on the ARC optimizer.

rdar://13407451

Added:
    cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m
Modified:
    cfe/trunk/docs/AutomaticReferenceCounting.rst
    cfe/trunk/lib/CodeGen/CGBlocks.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/lib/CodeGen/CGValue.h
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenObjC/arc.m

Modified: cfe/trunk/docs/AutomaticReferenceCounting.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/AutomaticReferenceCounting.rst?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/docs/AutomaticReferenceCounting.rst (original)
+++ cfe/trunk/docs/AutomaticReferenceCounting.rst Tue Mar 12 22:10:54 2013
@@ -1330,27 +1330,179 @@ This is a new rule of the Objective-C la
 Optimization
 ============
 
-ARC applies aggressive rules for the optimization of local behavior.  These
-rules are based around a core assumption of :arc-term:`local balancing`: that
-other code will perform retains and releases as necessary (and only as
-necessary) for its own safety, and so the optimizer does not need to consider
-global properties of the retain and release sequence.  For example, if a retain
-and release immediately bracket a call, the optimizer can delete the retain and
-release on the assumption that the called function will not do a constant
-number of unmotivated releases followed by a constant number of "balancing"
-retains, such that the local retain/release pair is the only thing preventing
-the called function from ending up with a dangling reference.
-
-The optimizer assumes that when a new value enters local control, e.g. from a
-load of a non-local object or as the result of a function call, it is
-instaneously valid.  Subsequently, a retain and release of a value are
-necessary on a computation path only if there is a use of that value before the
-release and after any operation which might cause a release of the value
-(including indirectly or non-locally), and only if the value is not
-demonstrably already retained.
+Within this section, the word :arc-term:`function` will be used to
+refer to any structured unit of code, be it a C function, an
+Objective-C method, or a block.
 
-The complete optimization rules are quite complicated, but it would still be
-useful to document them here.
+This specification describes ARC as performing specific ``retain`` and
+``release`` operations on retainable object pointers at specific
+points during the execution of a program.  These operations make up a
+non-contiguous subsequence of the computation history of the program.
+The portion of this sequence for a particular retainable object
+pointer for which a specific function execution is directly
+responsible is the :arc-term:`formal local retain history` of the
+object pointer.  The corresponding actual sequence executed is the
+`dynamic local retain history`.
+
+However, under certain circumstances, ARC is permitted to re-order and
+eliminate operations in a manner which may alter the overall
+computation history beyond what is permitted by the general "as if"
+rule of C/C++ and the :ref:`restrictions <_arc.objects.retains>` on
+the implementation of ``retain`` and ``release``.
+
+.. admonition:: Rationale
+
+  Specifically, ARC is sometimes permitted to optimize ``release``
+  operations in ways which might cause an object to be deallocated
+  before it would otherwise be.  Without this, it would be almost
+  impossible to eliminate any ``retain``/``release`` pairs.  For
+  example, consider the following code:
+
+  .. code-block:: objc
+    id x = _ivar;
+    [x foo];
+
+  If we were not permitted in any event to shorten the lifetime of the
+  object in ``x``, then we would not be able to eliminate this retain
+  and release unless we could prove that the message send could not
+  modify ``_ivar`` (or deallocate ``self``).  Since message sends are
+  opaque to the optimizer, this is not possible, and so ARC's hands
+  would be almost completely tied.
+
+ARC makes no guarantees about the execution of a computation history
+which contains undefined behavior.  In particular, ARC makes no
+guarantees in the presence of race conditions.
+
+ARC may assume that any retainable object pointers it receives or
+generates are instantaneously valid from that point until a point
+which, by the concurrency model of the host language, happens-after
+the generation of the pointer and happens-before a release of that
+object (possibly via an aliasing pointer or indirectly due to
+destruction of a different object).
+
+.. admonition:: Rationale
+
+  There is very little point in trying to guarantee correctness in the
+  presence of race conditions.  ARC does not have a stack-scanning
+  garbage collector, and guaranteeing the atomicity of every load and
+  store operation would be prohibitive and preclude a vast amount of
+  optimization.
+
+ARC may assume that non-ARC code engages in sensible balancing
+behavior and does not rely on exact or minimum retain count values
+except as guaranteed by ``__strong`` object invariants or +1 transfer
+conventions.  For example, if an object is provably double-retained
+and double-released, ARC may eliminate the inner retain and release;
+it does not need to guard against code which performs an unbalanced
+release followed by a "balancing" retain.
+
+.. _arc.optimization.liveness:
+
+Object liveness
+---------------
+
+ARC may not allow a retainable object ``X`` to be deallocated at a
+time ``T`` in a computation history if:
+
+* ``X`` is the value stored in a ``__strong`` object ``S`` with
+  :ref:`precise lifetime semantics <arc.optimization.precise>`, or
+
+* ``X`` is the value stored in a ``__strong`` object ``S`` with
+  imprecise lifetime semantics and, at some point after ``T`` but
+  before the next store to ``S``, the computation history features a
+  load from ``S`` and in some way depends on the value loaded, or
+
+* ``X`` is a value described as being released at the end of the
+  current full-expression and, at some point after ``T`` but before
+  the end of the full-expression, the computation history depends
+  on that value.
+
+.. admonition:: Rationale
+
+  The intent of the second rule is to say that objects held in normal
+  ``__strong`` local variables may be released as soon as the value in
+  the variable is no longer being used: either the variable stops
+  being used completely or a new value is stored in the variable.
+
+  The intent of the third rule is to say that return values may be
+  released after they've been used.
+
+A computation history depends on a pointer value ``P`` if it:
+
+* performs a pointer comparison with ``P``,
+* loads from ``P``,
+* stores to ``P``,
+* depends on a pointer value ``Q`` derived via pointer arithmetic
+  from ``P`` (including an instance-variable or field access), or
+* depends on a pointer value ``Q`` loaded from ``P``.
+
+Dependency applies only to values derived directly or indirectly from
+a particular expression result and does not occur merely because a
+separate pointer value dynamically aliases ``P``.  Furthermore, this
+dependency is not carried by values that are stored to objects.
+
+.. admonition:: Rationale
+
+  The restrictions on dependency are intended to make this analysis
+  feasible by an optimizer with only incomplete information about a
+  program.  Essentially, dependence is carried to "obvious" uses of a
+  pointer.  Merely passing a pointer argument to a function does not
+  itself cause dependence, but since generally the optimizer will not
+  be able to prove that the function doesn't depend on that parameter,
+  it will be forced to conservatively assume it does.
+  
+  Dependency propagates to values loaded from a pointer because those
+  values might be invalidated by deallocating the object.  For
+  example, given the code ``__strong id x = p->ivar;``, ARC must not
+  move the release of ``p`` to between the load of ``p->ivar`` and the
+  retain of that value for storing into ``x``.
+
+  Dependency does not propagate through stores of dependent pointer
+  values because doing so would allow dependency to outlive the
+  full-expression which produced the original value.  For example, the
+  address of an instance variable could be written to some global
+  location and then freely accessed during the lifetime of the local,
+  or a function could return an inner pointer of an object and store
+  it to a local.  These cases would be potentially impossible to
+  reason about and so would basically prevent any optimizations based
+  on imprecise lifetime.  There are also uncommon enough to make it
+  reasonable to require the precise-lifetime annotation if someone
+  really wants to rely on them.
+
+  Dependency does propagate through return values of pointer type.
+  The compelling source of need for this rule is a property accessor
+  which returns an un-autoreleased result; the calling function must
+  have the chance to operate on the value, e.g. to retain it, before
+  ARC releases the original pointer.  Note again, however, that
+  dependence does not survive a store, so ARC does not guarantee the
+  continued validity of the return value past the end of the
+  full-expression.
+
+.. _arc.optimization.object_lifetime:
+
+No object lifetime extension
+----------------------------
+
+If, in the formal computation history of the program, an object ``X``
+has been deallocated by the time of an observable side-effect, then
+ARC must cause ``X`` to be deallocated by no later than the occurrence
+of that side-effect, except as influenced by the re-ordering of the
+destruction of objects.
+
+.. admonition:: Rationale
+
+  This rule is intended to prohibit ARC from observably extending the
+  lifetime of a retainable object, other than as specified in this
+  document.  Together with the rule limiting the transformation of
+  releases, this rule requires ARC to eliminate retains and release
+  only in pairs.
+
+  ARC's power to reorder the destruction of objects is critical to its
+  ability to do any optimization, for essentially the same reason that
+  it must retain the power to decrease the lifetime of an object.
+  Unfortunately, while it's generally poor style for the destruction
+  of objects to have arbitrary side-effects, it's certainly possible.
+  Hence the caveat.
 
 .. _arc.optimization.precise:
 

Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Tue Mar 12 22:10:54 2013
@@ -1547,7 +1547,7 @@ CodeGenFunction::GenerateDestroyHelperFu
 
     // Destroy strong objects with a call if requested.
     } else if (useARCStrongDestroy) {
-      EmitARCDestroyStrong(srcField, /*precise*/ false);
+      EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
 
     // Otherwise we call _Block_object_dispose.  It wouldn't be too
     // hard to just emit this as a cleanup if we wanted to make sure
@@ -1656,7 +1656,7 @@ public:
   }
 
   void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
-    CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+    CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
   }
 
   void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1686,7 +1686,7 @@ public:
   }
 
   void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
-    CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+    CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
   }
 
   void profileImpl(llvm::FoldingSetNodeID &id) const {

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Mar 12 22:10:54 2013
@@ -627,7 +627,7 @@ void CodeGenFunction::EmitScalarInit(con
   if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
     llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
     EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
-    EmitARCRelease(oldValue, /*precise*/ false);
+    EmitARCRelease(oldValue, ARCImpreciseLifetime);
     return;
   }
 
@@ -1490,12 +1490,15 @@ namespace {
   /// ns_consumed argument when we can't reasonably do that just by
   /// not doing the initial retain for a __block argument.
   struct ConsumeARCParameter : EHScopeStack::Cleanup {
-    ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+    ConsumeARCParameter(llvm::Value *param,
+                        ARCPreciseLifetime_t precise)
+      : Param(param), Precise(precise) {}
 
     llvm::Value *Param;
+    ARCPreciseLifetime_t Precise;
 
     void Emit(CodeGenFunction &CGF, Flags flags) {
-      CGF.EmitARCRelease(Param, /*precise*/ false);
+      CGF.EmitARCRelease(Param, Precise);
     }
   };
 }
@@ -1585,8 +1588,12 @@ void CodeGenFunction::EmitParmDecl(const
         }
       } else {
         // Push the cleanup for a consumed parameter.
-        if (isConsumed)
-          EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+        if (isConsumed) {
+          ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>()
+                                ? ARCPreciseLifetime : ARCImpreciseLifetime);
+          EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg,
+                                                   precise);
+        }
 
         if (lt == Qualifiers::OCL_Weak) {
           EmitARCInitWeak(DeclPtr, Arg);

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue Mar 12 22:10:54 2013
@@ -1800,10 +1800,6 @@ LValue CodeGenFunction::EmitDeclRefLValu
 
     bool isBlockVariable = VD->hasAttr<BlocksAttr>();
 
-    bool NonGCable = VD->hasLocalStorage() &&
-                     !VD->getType()->isReferenceType() &&
-                     !isBlockVariable;
-
     llvm::Value *V = LocalDeclMap.lookup(VD);
     if (!V && VD->isStaticLocal()) 
       V = CGM.getStaticLocalDeclAddress(VD);
@@ -1837,10 +1833,20 @@ LValue CodeGenFunction::EmitDeclRefLValu
       LV = MakeAddrLValue(V, T, Alignment);
     }
 
+    bool isLocalStorage = VD->hasLocalStorage();
+
+    bool NonGCable = isLocalStorage &&
+                     !VD->getType()->isReferenceType() &&
+                     !isBlockVariable;
     if (NonGCable) {
       LV.getQuals().removeObjCGCAttr();
       LV.setNonGC(true);
     }
+
+    bool isImpreciseLifetime =
+      (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>());
+    if (isImpreciseLifetime)
+      LV.setARCPreciseLifetime(ARCImpreciseLifetime);
     setObjCGCLValueClass(getContext(), E, LV);
     return LV;
   }
@@ -2911,7 +2917,7 @@ RValue CodeGenFunction::EmitCallExpr(con
       case Qualifiers::OCL_Strong:
         EmitARCRelease(Builder.CreateLoad(BaseValue, 
                           PseudoDtor->getDestroyedType().isVolatileQualified()),
-                       /*precise*/ true);
+                       ARCPreciseLifetime);
         break;
 
       case Qualifiers::OCL_Weak:

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Mar 12 22:10:54 2013
@@ -1451,7 +1451,7 @@ static void EmitObjectDelete(CodeGenFunc
       llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr, 
                                              ElementType.isVolatileQualified());
         
-      CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+      CGF.EmitARCRelease(PtrValue, ARCPreciseLifetime);
       break;
     }
         

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Tue Mar 12 22:10:54 2013
@@ -1686,7 +1686,8 @@ namespace {
     llvm::Value *object;
 
     void Emit(CodeGenFunction &CGF, Flags flags) {
-      CGF.EmitARCRelease(object, /*precise*/ true);
+      // Releases at the end of the full-expression are imprecise.
+      CGF.EmitARCRelease(object, ARCImpreciseLifetime);
     }
   };
 }
@@ -1940,7 +1941,8 @@ CodeGenFunction::EmitARCRetainAutoreleas
 
 /// Release the given object.
 ///   call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+void CodeGenFunction::EmitARCRelease(llvm::Value *value,
+                                     ARCPreciseLifetime_t precise) {
   if (isa<llvm::ConstantPointerNull>(value)) return;
 
   llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
@@ -1956,7 +1958,7 @@ void CodeGenFunction::EmitARCRelease(llv
   // Call objc_release.
   llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
 
-  if (!precise) {
+  if (precise == ARCImpreciseLifetime) {
     SmallVector<llvm::Value*,1> args;
     call->setMetadata("clang.imprecise_release",
                       llvm::MDNode::get(Builder.getContext(), args));
@@ -1972,7 +1974,8 @@ void CodeGenFunction::EmitARCRelease(llv
 /// At -O1 and above, just load and call objc_release.
 ///
 ///   call void \@objc_storeStrong(i8** %addr, i8* null)
-void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) {
+void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr,
+                                           ARCPreciseLifetime_t precise) {
   if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
     llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
     llvm::Value *null = llvm::ConstantPointerNull::get(
@@ -2042,7 +2045,7 @@ llvm::Value *CodeGenFunction::EmitARCSto
   EmitStoreOfScalar(newValue, dst);
 
   // Finally, release the old value.
-  EmitARCRelease(oldValue, /*precise*/ false);
+  EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
 
   return newValue;
 }
@@ -2254,13 +2257,13 @@ void CodeGenFunction::EmitObjCMRRAutorel
 void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
                                               llvm::Value *addr,
                                               QualType type) {
-  CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
+  CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
 }
 
 void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
                                                 llvm::Value *addr,
                                                 QualType type) {
-  CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
+  CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
 }
 
 void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2737,7 +2740,7 @@ CodeGenFunction::EmitARCStoreStrong(cons
     llvm::Value *oldValue =
       EmitLoadOfScalar(lvalue);
     EmitStoreOfScalar(value, lvalue);
-    EmitARCRelease(oldValue, /*precise*/ false);
+    EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
   } else {
     value = EmitARCStoreStrong(lvalue, value, ignored);
   }

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Mar 12 22:10:54 2013
@@ -1617,7 +1617,7 @@ struct NullReturnState {
           RValue RV = I->RV;
           assert(RV.isScalar() && 
                  "NullReturnState::complete - arg not on object");
-          CGF.EmitARCRelease(RV.getScalarVal(), true);
+          CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
         }
       }
     }

Modified: cfe/trunk/lib/CodeGen/CGValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGValue.h (original)
+++ cfe/trunk/lib/CodeGen/CGValue.h Tue Mar 12 22:10:54 2013
@@ -97,6 +97,10 @@ public:
   }
 };
 
+/// Does an ARC strong l-value have precise lifetime?
+enum ARCPreciseLifetime_t {
+  ARCImpreciseLifetime, ARCPreciseLifetime,
+};
 
 /// LValue - This represents an lvalue references.  Because C/C++ allow
 /// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
@@ -147,6 +151,10 @@ class LValue {
   // Lvalue is a thread local reference
   bool ThreadLocalRef : 1;
 
+  // Lvalue has ARC imprecise lifetime.  We store this inverted to try
+  // to make the default bitfield pattern all-zeroes.
+  bool ImpreciseLifetime : 1;
+
   Expr *BaseIvarExp;
 
   /// TBAAInfo - TBAA information to attach to dereferences of this LValue.
@@ -164,6 +172,7 @@ private:
 
     // Initialize Objective-C flags.
     this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
+    this->ImpreciseLifetime = false;
     this->ThreadLocalRef = false;
     this->BaseIvarExp = 0;
     this->TBAAInfo = TBAAInfo;
@@ -202,6 +211,13 @@ public:
   bool isThreadLocalRef() const { return ThreadLocalRef; }
   void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
 
+  ARCPreciseLifetime_t isARCPreciseLifetime() const {
+    return ARCPreciseLifetime_t(!ImpreciseLifetime);
+  }
+  void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
+    ImpreciseLifetime = (value == ARCImpreciseLifetime);
+  }
+
   bool isObjCWeak() const {
     return Quals.getObjCGCAttr() == Qualifiers::Weak;
   }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Mar 12 22:10:54 2013
@@ -2446,14 +2446,14 @@ public:
   llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
   llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
   llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
-                                  bool ignored);
+                                  bool resultIgnored);
   llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
-                                      bool ignored);
+                                      bool resultIgnored);
   llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
   llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
   llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
-  void EmitARCDestroyStrong(llvm::Value *addr, bool precise);
-  void EmitARCRelease(llvm::Value *value, bool precise);
+  void EmitARCDestroyStrong(llvm::Value *addr, ARCPreciseLifetime_t precise);
+  void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
   llvm::Value *EmitARCAutorelease(llvm::Value *value);
   llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
   llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);

Added: cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m?rev=176924&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-precise-lifetime.m Tue Mar 12 22:10:54 2013
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
+
+id test0_helper(void) __attribute__((ns_returns_retained));
+void test0() {
+  PRECISE_LIFETIME id x = test0_helper();
+  x = 0;
+  // CHECK:      [[X:%.*]] = alloca i8*
+  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper()
+  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: store i8* null, i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
+  // CHECK-NOT:  clang.imprecise_release
+
+  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
+  // CHECK-NOT:  clang.imprecise_release
+
+  // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9821110
+ at interface Test1
+- (char*) interior __attribute__((objc_returns_inner_pointer));
+// Should we allow this on properties?
+ at end
+extern Test1 *test1_helper(void);
+
+// CHECK: define void @test1a()
+void test1a(void) {
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
+  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+  // CHECK-NEXT: store i8* [[T6]], i8**
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+  // CHECK-NEXT: ret void
+  Test1 *ptr = test1_helper();
+  char *c = [(ptr) interior];
+}
+
+// CHECK: define void @test1b()
+void test1b(void) {
+  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+  // CHECK-NEXT: store [[TEST1]]* [[T3]]
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
+  // CHECK-NEXT: store i8* [[T3]], i8**
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
+  // CHECK-NOT:  clang.imprecise_release
+  // CHECK-NEXT: ret void
+  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
+  char *c = [ptr interior];
+}
+
+ at interface Test2 {
+ at public
+  id ivar;
+}
+ at end
+// CHECK:      define void @test2(
+void test2(Test2 *x) {
+  x->ivar = 0;
+  // CHECK:      [[X:%.*]] = alloca [[TEST2:%.*]]*
+  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8*
+  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
+  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST2]]*
+  // CHECK-NEXT: store [[TEST2]]* [[T2]], [[TEST2]]** [[X]],
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]],
+  // CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2.ivar"
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
+  // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8* [[T1]], i64 [[OFFSET]]
+  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8**
+  // CHECK-NEXT: [[T4:%.*]] = load i8** [[T3]],
+  // CHECK-NEXT: store i8* null, i8** [[T3]],
+  // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]]
+  // CHECK-NOT:  imprecise
+
+  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]]
+  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
+  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+
+  // CHECK-NEXT: ret void
+}
+
+// CHECK:      define void @test3(i8*
+void test3(PRECISE_LIFETIME id x) {
+  // CHECK:      [[X:%.*]] = alloca i8*,
+  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]]
+  // CHECK-NEXT: store i8* [[T0]], i8** [[X]],
+
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
+  // CHECK-NOT:  imprecise_release
+
+  // CHECK-NEXT: ret void  
+}
+
+// CHECK: attributes [[NUW]] = { nounwind }

Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=176924&r1=176923&r2=176924&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Tue Mar 12 22:10:54 2013
@@ -273,27 +273,7 @@ void test8() {
   // CHECK:      [[X:%.*]] = alloca i8*
   // CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper()
   // CHECK-NEXT: store i8* [[T0]], i8** [[X]]
-  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
-  // CHECK-NOT:  imprecise_release
-  // CHECK-NEXT: ret void
-}
-
-id test9_helper(void) __attribute__((ns_returns_retained));
-void test9() {
-  id x __attribute__((objc_precise_lifetime)) = test9_helper();
-  x = 0;
-  // CHECK:      [[X:%.*]] = alloca i8*
-  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test9_helper()
-  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
-
-  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
-  // CHECK-NEXT: store i8* null, i8** [[X]]
-  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
-
-  // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
-  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
-  // CHECK-NOT:  clang.imprecise_release
-
+  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
   // CHECK-NEXT: ret void
 }
 
@@ -1239,57 +1219,6 @@ void test56_test(void) {
 // CHECK-NEXT: [[T5:%.*]] = load i8** [[T4]]
 // CHECK-NEXT: ret i8* [[T5]]
 
-// rdar://problem/9821110
- at interface Test58
-- (char*) interior __attribute__((objc_returns_inner_pointer));
-// Should we allow this on properties?
- at end
-extern Test58 *test58_helper(void);
-
-// CHECK: define void @test58a()
-void test58a(void) {
-  // CHECK:      [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
-  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
-  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
-  // CHECK-NEXT: store [[TEST58]]* [[T3]]
-  // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
-  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
-  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
-  // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
-  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST58]]* [[T3]] to i8*
-  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
-  // CHECK-NEXT: store i8* [[T6]], i8**
-  // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
-  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
-  // CHECK-NEXT: ret void
-  Test58 *ptr = test58_helper();
-  char *c = [(ptr) interior];
-}
-
-// CHECK: define void @test58b()
-void test58b(void) {
-  // CHECK:      [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
-  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
-  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
-  // CHECK-NEXT: store [[TEST58]]* [[T3]]
-  // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
-  // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
-  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
-  // CHECK-NEXT: store i8* [[T3]], i8**
-  // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
-  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
-  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
-  // CHECK-NOT:  clang.imprecise_release
-  // CHECK-NEXT: ret void
-  __attribute__((objc_precise_lifetime)) Test58 *ptr = test58_helper();
-  char *c = [ptr interior];
-}
-
 // rdar://problem/9842343
 void test59(void) {
   extern id test59_getlock(void);





More information about the cfe-commits mailing list