From: John McCall Date: Sat, 22 May 2010 22:13:32 +0000 (+0000) Subject: Re-teach IR gen to perform GC moves on rvalues resulting from various ObjC X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fa037bd3f79d3c70197a3224bb1b29c6c4af0098;p=clang Re-teach IR gen to perform GC moves on rvalues resulting from various ObjC expressions. Essentially, GC breaks a certain form of the return-value optimization. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104454 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 18c69121d4..a4e64fb3d6 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -39,8 +39,14 @@ class AggExprEmitter : public StmtVisitor { bool RequiresGCollection; ReturnValueSlot getReturnValueSlot() const { + // If the destination slot requires garbage collection, we can't + // use the real return value slot, because we have to use the GC + // API. + if (RequiresGCollection) return ReturnValueSlot(); + return ReturnValueSlot(DestPtr, VolatileDest); } + public: AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v, bool ignore, bool isinit, bool requiresGCollection) @@ -62,6 +68,10 @@ public: void EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore = false); void EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore = false); + void EmitGCMove(const Expr *E, RValue Src); + + bool TypeRequiresGCollection(QualType T); + //===--------------------------------------------------------------------===// // Visitor Methods //===--------------------------------------------------------------------===// @@ -141,6 +151,39 @@ void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) { EmitFinalDestCopy(E, LV); } +/// \brief True if the given aggregate type requires special GC API calls. +bool AggExprEmitter::TypeRequiresGCollection(QualType T) { + // Only record types have members that might require garbage collection. + const RecordType *RecordTy = T->getAs(); + if (!RecordTy) return false; + + // Don't mess with non-trivial C++ types. + RecordDecl *Record = RecordTy->getDecl(); + if (isa(Record) && + (!cast(Record)->hasTrivialCopyConstructor() || + !cast(Record)->hasTrivialDestructor())) + return false; + + // Check whether the type has an object member. + return Record->hasObjectMember(); +} + +/// \brief Perform the final move to DestPtr if RequiresGCollection is set. +/// +/// The idea is that you do something like this: +/// RValue Result = EmitSomething(..., getReturnValueSlot()); +/// EmitGCMove(E, Result); +/// If GC doesn't interfere, this will cause the result to be emitted +/// directly into the return value slot. If GC does interfere, a final +/// move will be performed. +void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { + if (!RequiresGCollection) return; + + CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, + Src.getAggregateAddr(), + E->getType()); +} + /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { assert(Src.isAggregate() && "value must be aggregate value!"); @@ -308,28 +351,24 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { return; } - // If the struct doesn't require GC, we can just pass the destination - // directly to EmitCall. - if (!RequiresGCollection) { - CGF.EmitCallExpr(E, getReturnValueSlot()); - return; - } - - RValue RV = CGF.EmitCallExpr(E); - EmitFinalDestCopy(E, RV); + RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { - CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); + RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *E) { - CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + RValue RV = CGF.EmitObjCPropertyGet(E, getReturnValueSlot()); + EmitGCMove(E, RV); } void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { @@ -435,11 +474,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { RValue::getAggregate(AggLoc, VolatileDest)); } else { bool RequiresGCollection = false; - if (CGF.getContext().getLangOptions().NeXTRuntime) { - QualType LHSTy = E->getLHS()->getType(); - if (const RecordType *FDTTy = LHSTy.getTypePtr()->getAs()) - RequiresGCollection = FDTTy->getDecl()->hasObjectMember(); - } + if (CGF.getContext().getLangOptions().getGCMode()) + RequiresGCollection = TypeRequiresGCollection(E->getLHS()->getType()); + // Codegen the RHS so that it stores directly into the LHS. CGF.EmitAggExpr(E->getRHS(), LHS.getAddress(), LHS.isVolatileQualified(), false, false, RequiresGCollection);