]> granicus.if.org Git - clang/commitdiff
Significantly simplify CGExprAgg's logic about ignored results:
authorJohn McCall <rjmccall@apple.com>
Mon, 2 Jul 2012 23:58:38 +0000 (23:58 +0000)
committerJohn McCall <rjmccall@apple.com>
Mon, 2 Jul 2012 23:58:38 +0000 (23:58 +0000)
if we want to ignore a result, the Dest will be null.  Otherwise,
we must copy into it.  This means we need to ensure a slot when
loading from a volatile l-value.

With all that in place, fix a bug with chained assignments into
__block variables of aggregate type where we were losing insight into
the actual source of the value during the second assignment.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159630 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGValue.h
lib/CodeGen/CodeGenFunction.h
test/CodeGen/block-byref-aggr.c

index cb446dfeb4ab44d440b316537a9bb5cf7ddb665d..5f708d7a73f8852e4ef4edab995e531ab2bcb343 100644 (file)
@@ -109,15 +109,18 @@ void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
 /// can have any type.  The result is returned as an RValue struct.
 /// If this is an aggregate expression, AggSlot indicates where the
 /// result should be returned.
-RValue CodeGenFunction::EmitAnyExpr(const Expr *E, AggValueSlot AggSlot,
-                                    bool IgnoreResult) {
+RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
+                                    AggValueSlot aggSlot,
+                                    bool ignoreResult) {
   if (!hasAggregateLLVMType(E->getType()))
-    return RValue::get(EmitScalarExpr(E, IgnoreResult));
+    return RValue::get(EmitScalarExpr(E, ignoreResult));
   else if (E->getType()->isAnyComplexType())
-    return RValue::getComplex(EmitComplexExpr(E, IgnoreResult, IgnoreResult));
+    return RValue::getComplex(EmitComplexExpr(E, ignoreResult, ignoreResult));
 
-  EmitAggExpr(E, AggSlot, IgnoreResult);
-  return AggSlot.asRValue();
+  if (!ignoreResult && aggSlot.isIgnored())
+    aggSlot = CreateAggTemp(E->getType(), "agg-temp");
+  EmitAggExpr(E, aggSlot);
+  return aggSlot.asRValue();
 }
 
 /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
index 9616af633d25dcc665f46c960f71289ce83aa9b7..61f7362ecaef5eb3d7d02937c2623fe0ba20ff56 100644 (file)
@@ -34,7 +34,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
   CodeGenFunction &CGF;
   CGBuilderTy &Builder;
   AggValueSlot Dest;
-  bool IgnoreResult;
 
   /// We want to use 'dest' as the return slot except under two
   /// conditions:
@@ -56,12 +55,14 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
     if (!Dest.isIgnored()) return Dest;
     return CGF.CreateAggTemp(T, "agg.tmp.ensured");
   }
+  void EnsureDest(QualType T) {
+    if (!Dest.isIgnored()) return;
+    Dest = CGF.CreateAggTemp(T, "agg.tmp.ensured");
+  }
 
 public:
-  AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest,
-                 bool ignore)
-    : CGF(cgf), Builder(CGF.Builder), Dest(Dest),
-      IgnoreResult(ignore) {
+  AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest)
+    : CGF(cgf), Builder(CGF.Builder), Dest(Dest) {
   }
 
   //===--------------------------------------------------------------------===//
@@ -74,9 +75,11 @@ public:
   void EmitAggLoadOfLValue(const Expr *E);
 
   /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-  void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false);
-  void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false,
-                         unsigned Alignment = 0);
+  void EmitFinalDestCopy(QualType type, const LValue &src);
+  void EmitFinalDestCopy(QualType type, RValue src,
+                         CharUnits srcAlignment = CharUnits::Zero());
+  void EmitCopy(QualType type, const AggValueSlot &dest,
+                const AggValueSlot &src);
 
   void EmitMoveFromReturnSlot(const Expr *E, RValue Src);
 
@@ -119,7 +122,7 @@ public:
     if (E->getDecl()->getType()->isReferenceType()) {
       if (CodeGenFunction::ConstantEmission result
             = CGF.tryEmitAsConstant(E)) {
-        EmitFinalDestCopy(E, result.getReferenceLValue(CGF, E));
+        EmitFinalDestCopy(E->getType(), result.getReferenceLValue(CGF, E));
         return;
       }
     }
@@ -171,7 +174,7 @@ public:
   void VisitPseudoObjectExpr(PseudoObjectExpr *E) {
     if (E->isGLValue()) {
       LValue LV = CGF.EmitPseudoObjectLValue(E);
-      return EmitFinalDestCopy(E, LV);
+      return EmitFinalDestCopy(E->getType(), LV);
     }
 
     CGF.EmitPseudoObjectRValue(E, EnsureSlot(E->getType()));
@@ -198,7 +201,7 @@ public:
 /// then loads the result into DestPtr.
 void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
   LValue LV = CGF.EmitLValue(E);
-  EmitFinalDestCopy(E, LV);
+  EmitFinalDestCopy(E->getType(), LV);
 }
 
 /// \brief True if the given aggregate type requires special GC API calls.
@@ -228,7 +231,7 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
 /// If nothing interferes, this will cause the result to be emitted
 /// directly into the return value slot.  Otherwise, a final move
 /// will be performed.
-void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
+void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue src) {
   if (shouldUseDestForReturnSlot()) {
     // Logically, Dest.getAddr() should equal Src.getAggregateAddr().
     // The possibility of undef rvalues complicates that a lot,
@@ -236,61 +239,58 @@ void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
     return;
   }
 
-  // Otherwise, do a final copy, 
-  assert(Dest.getAddr() != Src.getAggregateAddr());
-  std::pair<CharUnits, CharUnits> TypeInfo = 
+  // Otherwise, copy from there to the destination.
+  assert(Dest.getAddr() != src.getAggregateAddr());
+  std::pair<CharUnits, CharUnits> typeInfo = 
     CGF.getContext().getTypeInfoInChars(E->getType());
-  CharUnits Alignment = std::min(TypeInfo.second, Dest.getAlignment());
-  EmitFinalDestCopy(E, Src, /*Ignore*/ true, Alignment.getQuantity());
+  EmitFinalDestCopy(E->getType(), src, typeInfo.second);
 }
 
 /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore,
-                                       unsigned Alignment) {
-  assert(Src.isAggregate() && "value must be aggregate value!");
+void AggExprEmitter::EmitFinalDestCopy(QualType type, RValue src,
+                                       CharUnits srcAlign) {
+  assert(src.isAggregate() && "value must be aggregate value!");
+  LValue srcLV = CGF.MakeAddrLValue(src.getAggregateAddr(), type, srcAlign);
+  EmitFinalDestCopy(type, srcLV);
+}
 
+/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
+void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src) {
   // If Dest is ignored, then we're evaluating an aggregate expression
-  // in a context (like an expression statement) that doesn't care
-  // about the result.  C says that an lvalue-to-rvalue conversion is
-  // performed in these cases; C++ says that it is not.  In either
-  // case, we don't actually need to do anything unless the value is
-  // volatile.
-  if (Dest.isIgnored()) {
-    if (!Src.isVolatileQualified() ||
-        CGF.CGM.getLangOpts().CPlusPlus ||
-        (IgnoreResult && Ignore))
-      return;
+  // in a context that doesn't care about the result.  Note that loads
+  // from volatile l-values force the existence of a non-ignored
+  // destination.
+  if (Dest.isIgnored())
+    return;
 
-    // If the source is volatile, we must read from it; to do that, we need
-    // some place to put it.
-    Dest = CGF.CreateAggTemp(E->getType(), "agg.tmp");
-  }
+  AggValueSlot srcAgg =
+    AggValueSlot::forLValue(src, AggValueSlot::IsDestructed,
+                            needsGC(type), AggValueSlot::IsAliased);
+  EmitCopy(type, Dest, srcAgg);
+}
 
-  if (Dest.requiresGCollection()) {
-    CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType());
-    llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
-    llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity());
+/// Perform a copy from the source into the destination.
+///
+/// \param type - the type of the aggregate being copied; qualifiers are
+///   ignored
+void AggExprEmitter::EmitCopy(QualType type, const AggValueSlot &dest,
+                              const AggValueSlot &src) {
+  if (dest.requiresGCollection()) {
+    CharUnits sz = CGF.getContext().getTypeSizeInChars(type);
+    llvm::Value *size = llvm::ConstantInt::get(CGF.SizeTy, sz.getQuantity());
     CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF,
-                                                      Dest.getAddr(),
-                                                      Src.getAggregateAddr(),
-                                                      SizeVal);
+                                                      dest.getAddr(),
+                                                      src.getAddr(),
+                                                      size);
     return;
   }
-  // If the result of the assignment is used, copy the LHS there also.
-  // FIXME: Pass VolatileDest as well.  I think we also need to merge volatile
-  // from the source as well, as we can't eliminate it if either operand
-  // is volatile, unless copy has volatile for both source and destination..
-  CGF.EmitAggregateCopy(Dest.getAddr(), Src.getAggregateAddr(), E->getType(),
-                        Dest.isVolatile()|Src.isVolatileQualified(),
-                        Alignment);
-}
-
-/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
-void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
-  assert(Src.isSimple() && "Can't have aggregate bitfield, vector, etc");
 
-  CharUnits Alignment = std::min(Src.getAlignment(), Dest.getAlignment());
-  EmitFinalDestCopy(E, Src.asAggregateRValue(), Ignore, Alignment.getQuantity());
+  // If the result of the assignment is used, copy the LHS there also.
+  // It's volatile if either side is.  Use the minimum alignment of
+  // the two sides.
+  CGF.EmitAggregateCopy(dest.getAddr(), src.getAddr(), type,
+                        dest.isVolatile() || src.isVolatile(),
+                        std::min(dest.getAlignment(), src.getAlignment()));
 }
 
 static QualType GetStdInitializerListElementType(QualType T) {
@@ -526,7 +526,7 @@ void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){
 }
 
 void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
-  EmitFinalDestCopy(e, CGF.getOpaqueLValueMapping(e));
+  EmitFinalDestCopy(e->getType(), CGF.getOpaqueLValueMapping(e));
 }
 
 void
@@ -582,7 +582,15 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
                 "should have been unpacked before we got here");
   }
 
-  case CK_LValueToRValue: // hope for downstream optimization
+  case CK_LValueToRValue:
+    // If we're loading from a volatile type, force the destination
+    // into existence.
+    if (E->getSubExpr()->getType().isVolatileQualified()) {
+      EnsureDest(E->getType());
+      return Visit(E->getSubExpr());
+    }
+    // fallthrough
+
   case CK_NoOp:
   case CK_AtomicToNonAtomic:
   case CK_NonAtomicToAtomic:
@@ -676,7 +684,73 @@ void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) {
 void AggExprEmitter::VisitPointerToDataMemberBinaryOperator(
                                                     const BinaryOperator *E) {
   LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(E);
-  EmitFinalDestCopy(E, LV);
+  EmitFinalDestCopy(E->getType(), LV);
+}
+
+/// Is the value of the given expression possibly a reference to or
+/// into a __block variable?
+static bool isBlockVarRef(const Expr *E) {
+  // Make sure we look through parens.
+  E = E->IgnoreParens();
+
+  // Check for a direct reference to a __block variable.
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+    const VarDecl *var = dyn_cast<VarDecl>(DRE->getDecl());
+    return (var && var->hasAttr<BlocksAttr>());
+  }
+
+  // More complicated stuff.
+
+  // Binary operators.
+  if (const BinaryOperator *op = dyn_cast<BinaryOperator>(E)) {
+    // For an assignment or pointer-to-member operation, just care
+    // about the LHS.
+    if (op->isAssignmentOp() || op->isPtrMemOp())
+      return isBlockVarRef(op->getLHS());
+
+    // For a comma, just care about the RHS.
+    if (op->getOpcode() == BO_Comma)
+      return isBlockVarRef(op->getRHS());
+
+    // FIXME: pointer arithmetic?
+    return false;
+
+  // Check both sides of a conditional operator.
+  } else if (const AbstractConditionalOperator *op
+               = dyn_cast<AbstractConditionalOperator>(E)) {
+    return isBlockVarRef(op->getTrueExpr())
+        || isBlockVarRef(op->getFalseExpr());
+
+  // OVEs are required to support BinaryConditionalOperators.
+  } else if (const OpaqueValueExpr *op
+               = dyn_cast<OpaqueValueExpr>(E)) {
+    if (const Expr *src = op->getSourceExpr())
+      return isBlockVarRef(src);
+
+  // Casts are necessary to get things like (*(int*)&var) = foo().
+  // We don't really care about the kind of cast here, except
+  // we don't want to look through l2r casts, because it's okay
+  // to get the *value* in a __block variable.
+  } else if (const CastExpr *cast = dyn_cast<CastExpr>(E)) {
+    if (cast->getCastKind() == CK_LValueToRValue)
+      return false;
+    return isBlockVarRef(cast->getSubExpr());
+
+  // Handle unary operators.  Again, just aggressively look through
+  // it, ignoring the operation.
+  } else if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E)) {
+    return isBlockVarRef(uop->getSubExpr());
+
+  // Look into the base of a field access.
+  } else if (const MemberExpr *mem = dyn_cast<MemberExpr>(E)) {
+    return isBlockVarRef(mem->getBase());
+
+  // Look into the base of a subscript.
+  } else if (const ArraySubscriptExpr *sub = dyn_cast<ArraySubscriptExpr>(E)) {
+    return isBlockVarRef(sub->getBase());
+  }
+
+  return false;
 }
 
 void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
@@ -686,20 +760,26 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
                                                  E->getRHS()->getType())
          && "Invalid assignment");
 
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getLHS()))
-    if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
-      if (VD->hasAttr<BlocksAttr>() &&
-          E->getRHS()->HasSideEffects(CGF.getContext())) {
-        // When __block variable on LHS, the RHS must be evaluated first 
-        // as it may change the 'forwarding' field via call to Block_copy.
-        LValue RHS = CGF.EmitLValue(E->getRHS());
-        LValue LHS = CGF.EmitLValue(E->getLHS());
-        Dest = AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
-                                       needsGC(E->getLHS()->getType()),
-                                       AggValueSlot::IsAliased);
-        EmitFinalDestCopy(E, RHS, true);
-        return;
-      }
+  // If the LHS might be a __block variable, and the RHS can
+  // potentially cause a block copy, we need to evaluate the RHS first
+  // so that the assignment goes the right place.
+  // This is pretty semantically fragile.
+  if (isBlockVarRef(E->getLHS()) &&
+      E->getRHS()->HasSideEffects(CGF.getContext())) {
+    // Ensure that we have a destination, and evaluate the RHS into that.
+    EnsureDest(E->getRHS()->getType());
+    Visit(E->getRHS());
+
+    // Now emit the LHS and copy into it.
+    LValue LHS = CGF.EmitLValue(E->getLHS());
+
+    EmitCopy(E->getLHS()->getType(),
+             AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
+                                     needsGC(E->getLHS()->getType()),
+                                     AggValueSlot::IsAliased),
+             Dest);
+    return;
+  }
   
   LValue LHS = CGF.EmitLValue(E->getLHS());
 
@@ -708,8 +788,10 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
     AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, 
                             needsGC(E->getLHS()->getType()),
                             AggValueSlot::IsAliased);
-  CGF.EmitAggExpr(E->getRHS(), LHSSlot, false);
-  EmitFinalDestCopy(E, LHS, true);
+  CGF.EmitAggExpr(E->getRHS(), LHSSlot);
+
+  // Copy into the destination if the assignment isn't ignored.
+  EmitFinalDestCopy(E->getType(), LHS);
 }
 
 void AggExprEmitter::
@@ -762,14 +844,14 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
     return;
   }
 
-  EmitFinalDestCopy(VE, CGF.MakeAddrLValue(ArgPtr, VE->getType()));
+  EmitFinalDestCopy(VE->getType(), CGF.MakeAddrLValue(ArgPtr, VE->getType()));
 }
 
 void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
   // Ensure that we have a slot, but if we already do, remember
   // whether it was externally destructed.
   bool wasExternallyDestructed = Dest.isExternallyDestructed();
-  Dest = EnsureSlot(E->getType());
+  EnsureDest(E->getType());
 
   // We're going to push a destructor if there isn't already one.
   Dest.setExternallyDestructed();
@@ -904,7 +986,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
     llvm::GlobalVariable* GV =
     new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true,
                              llvm::GlobalValue::InternalLinkage, C, "");
-    EmitFinalDestCopy(E, CGF.MakeAddrLValue(GV, E->getType()));
+    EmitFinalDestCopy(E->getType(), CGF.MakeAddrLValue(GV, E->getType()));
     return;
   }
 #endif
@@ -1164,8 +1246,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
 /// type.  The result is computed into DestPtr.  Note that if DestPtr is null,
 /// the value of the aggregate expression is not needed.  If VolatileDest is
 /// true, DestPtr cannot be 0.
-void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
-                                  bool IgnoreResult) {
+void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
   assert(E && hasAggregateLLVMType(E->getType()) &&
          "Invalid aggregate expression to emit");
   assert((Slot.getAddr() != 0 || Slot.isIgnored()) &&
@@ -1174,7 +1255,7 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot,
   // Optimize the slot if possible.
   CheckAggExprForMemSetUse(Slot, E, *this);
  
-  AggExprEmitter(*this, Slot, IgnoreResult).Visit(const_cast<Expr*>(E));
+  AggExprEmitter(*this, Slot).Visit(const_cast<Expr*>(E));
 }
 
 LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
@@ -1189,7 +1270,8 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
 
 void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
                                         llvm::Value *SrcPtr, QualType Ty,
-                                        bool isVolatile, unsigned Alignment) {
+                                        bool isVolatile,
+                                        CharUnits alignment) {
   assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex");
 
   if (getContext().getLangOpts().CPlusPlus) {
@@ -1222,8 +1304,8 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
   std::pair<CharUnits, CharUnits> TypeInfo = 
     getContext().getTypeInfoInChars(Ty);
 
-  if (!Alignment)
-    Alignment = TypeInfo.second.getQuantity();
+  if (alignment.isZero())
+    alignment = TypeInfo.second;
 
   // FIXME: Handle variable sized types.
 
@@ -1281,7 +1363,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
   Builder.CreateMemCpy(DestPtr, SrcPtr,
                        llvm::ConstantInt::get(IntPtrTy, 
                                               TypeInfo.first.getQuantity()),
-                       Alignment, isVolatile);
+                       alignment.getQuantity(), isVolatile);
 }
 
 void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc,
index dd9208f91386aece8668b2ee126931a35a0c3474..a46f313f1f7a7f1b485e23a07357f913f1c86284 100644 (file)
@@ -389,7 +389,8 @@ public:
     return AV;
   }
 
-  static AggValueSlot forLValue(LValue LV, IsDestructed_t isDestructed,
+  static AggValueSlot forLValue(const LValue &LV,
+                                IsDestructed_t isDestructed,
                                 NeedsGCBarriers_t needsGC,
                                 IsAliased_t isAliased,
                                 IsZeroed_t isZeroed = IsNotZeroed) {
index ab0243163682d49d338d0bb66c819139de4636cf..a3d1acf5917f2935acc671e343ef64abcada2e87 100644 (file)
@@ -1566,6 +1566,7 @@ public:
     return LValue::MakeAddr(V, T, Alignment, getContext(),
                             CGM.getTBAAInfo(T));
   }
+
   LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) {
     CharUnits Alignment;
     if (!T->isIncompleteType())
@@ -1622,8 +1623,8 @@ public:
   ///
   /// \param IgnoreResult - True if the resulting value isn't used.
   RValue EmitAnyExpr(const Expr *E,
-                     AggValueSlot AggSlot = AggValueSlot::ignored(),
-                     bool IgnoreResult = false);
+                     AggValueSlot aggSlot = AggValueSlot::ignored(),
+                     bool ignoreResult = false);
 
   // EmitVAListRef - Emit a "reference" to a va_list; this is either the address
   // or the value of the expression, depending on how va_list is defined.
@@ -1649,7 +1650,7 @@ public:
   /// volatile.
   void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr,
                          QualType EltTy, bool isVolatile=false,
-                         unsigned Alignment = 0);
+                         CharUnits Alignment = CharUnits::Zero());
 
   /// StartBlock - Start new block named N. If insert block is a dummy block
   /// then reuse it.
@@ -2363,7 +2364,7 @@ public:
   /// EmitAggExpr - Emit the computation of the specified expression
   /// of aggregate type.  The result is computed into the given slot,
   /// which may be null to indicate that the value is not needed.
-  void EmitAggExpr(const Expr *E, AggValueSlot AS, bool IgnoreResult = false);
+  void EmitAggExpr(const Expr *E, AggValueSlot AS);
 
   /// EmitAggExprToLValue - Emit the computation of the specified expression of
   /// aggregate type into a temporary LValue.
index 3027df04861cb02b617e09a9cdbf5118ef994bef..eb342b856e4fdac33b33a33c9c40e351192a5e2a 100644 (file)
@@ -1,17 +1,66 @@
 // RUN: %clang_cc1 %s -emit-llvm -o - -fblocks -triple x86_64-apple-darwin10 | FileCheck %s
-// rdar://9309454
 
-typedef struct { int v; } RetType;
+// CHECK: [[AGG:%.*]] = type { i32 }
+typedef struct { int v; } Agg;
+Agg makeAgg(void);
 
-RetType func();
+// When assigning into a __block variable, ensure that we compute that
+// address *after* evaluating the RHS when the RHS has the capacity to
+// cause a block copy.  rdar://9309454
+void test0() {
+  __block Agg a = {100};
 
-int main () {
- __attribute__((__blocks__(byref))) RetType a = {100};
+ a = makeAgg();
+}
+// CHECK:    define void @test0()
+// CHECK:      [[A:%.*]] = alloca [[BYREF:%.*]], align 8
+// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
+// CHECK:      [[RESULT:%.*]] = call i32 @makeAgg()
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[AGG]]* [[TEMP]], i32 0, i32 0
+// CHECK-NEXT: store i32 [[RESULT]], i32* [[T0]]
+//   Check that we properly assign into the forwarding pointer.
+// CHECK-NEXT: [[A_FORWARDING:%.*]] = getelementptr inbounds [[BYREF]]* [[A]], i32 0, i32 1
+// CHECK-NEXT: [[T0:%.*]] = load [[BYREF]]** [[A_FORWARDING]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF]]* [[T0]], i32 0, i32 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[AGG]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[AGG]]* [[TEMP]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T2]], i8* [[T3]], i64 4, i32 4, i1 false)
+//   Verify that there's nothing else significant in the function.
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF]]* [[A]] to i8*
+// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+// CHECK-NEXT: ret void
 
- a = func();
+// When chaining assignments into __block variables, make sure we
+// propagate the actual value into the outer variable.
+// rdar://11757470
+void test1() {
+  __block Agg a, b;
+  a = b = makeAgg();
 }
-// CHECK: [[C1:%.*]] = call i32 (...)* @func()
-// CHECK-NEXT: [[CO:%.*]] = getelementptr
-// CHECK-NEXT: store i32 [[C1]], i32* [[CO]]
-// CHECK-NEXT: [[FORWARDING:%.*]] = getelementptr inbounds [[BR:%.*]]* [[A:%.*]], i32 0, i32 1
-// CHECK-NEXT: [[O:%.*]] = load [[BR]]** [[FORWARDING]]
+// CHECK:    define void @test1()
+// CHECK:      [[A:%.*]] = alloca [[A_BYREF:%.*]], align 8
+// CHECK-NEXT: [[B:%.*]] = alloca [[B_BYREF:%.*]], align 8
+// CHECK-NEXT: [[TEMP:%.*]] = alloca [[AGG]], align 4
+// CHECK:      [[RESULT:%.*]] = call i32 @makeAgg()
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[AGG]]* [[TEMP]], i32 0, i32 0
+// CHECK-NEXT: store i32 [[RESULT]], i32* [[T0]]
+//   Check that we properly assign into the forwarding pointer, first for b:
+// CHECK-NEXT: [[B_FORWARDING:%.*]] = getelementptr inbounds [[B_BYREF]]* [[B]], i32 0, i32 1
+// CHECK-NEXT: [[T0:%.*]] = load [[B_BYREF]]** [[B_FORWARDING]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[B_BYREF]]* [[T0]], i32 0, i32 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[AGG]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[AGG]]* [[TEMP]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T2]], i8* [[T3]], i64 4, i32 4, i1 false)
+//   Then for 'a':
+// CHECK-NEXT: [[A_FORWARDING:%.*]] = getelementptr inbounds [[A_BYREF]]* [[A]], i32 0, i32 1
+// CHECK-NEXT: [[T0:%.*]] = load [[A_BYREF]]** [[A_FORWARDING]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A_BYREF]]* [[T0]], i32 0, i32 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[AGG]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[AGG]]* [[TEMP]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T2]], i8* [[T3]], i64 4, i32 4, i1 false)
+//   Verify that there's nothing else significant in the function.
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[B_BYREF]]* [[B]] to i8*
+// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[A_BYREF]]* [[A]] to i8*
+// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
+// CHECK-NEXT: ret void