diff options
author | John McCall <rjmccall@apple.com> | 2011-08-25 23:04:34 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-08-25 23:04:34 +0000 |
commit | 410ffb2bc5f072d58a73c14560345bcf77dec1cc (patch) | |
tree | 162e003b95c3b8460288bdb6f6ee347e3ac61a77 /lib | |
parent | 8c7e67d7644c3ab298bd6be724c9480da0979af6 (diff) |
Track whether an AggValueSlot is potentially aliased, and do not
emit call results into potentially aliased slots. This allows us
to properly mark indirect return slots as noalias, at the cost
of requiring an extra memcpy when assigning an aggregate call
result into a l-value. It also brings us into compliance with
the x86-64 ABI.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138599 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 9 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 54 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGValue.h | 21 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 3 |
10 files changed, 70 insertions, 33 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index dc3e702d6a..846e1aa393 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -907,6 +907,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the struct return argument. if (CGM.ReturnTypeUsesSRet(FI)) { AI->setName("agg.result"); + AI->addAttr(llvm::Attribute::NoAlias); ++AI; } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 8e46fcd3ed..8bdfbf1231 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -401,7 +401,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, AggValueSlot AggSlot = AggValueSlot::forAddr(V, Qualifiers(), AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); CGF.EmitAggExpr(BaseInit->getInit(), AggSlot); @@ -441,7 +442,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.getQuals(), AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); CGF.EmitAggExpr(MemberInit->getInit(), Slot); } @@ -1330,7 +1332,8 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, Qualifiers(), AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 609542c9c6..5fa99a513a 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -1046,7 +1046,8 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, // TODO: how can we delay here if D is captured by its initializer? EmitAggExpr(init, AggValueSlot::forLValue(lvalue, AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers)); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index f4bed79527..e4c327b3ab 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -47,7 +47,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile()); } else { CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers)); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index da892c7715..1ed24ccd65 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -360,7 +360,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, = AggValueSlot::IsDestructed_t(InitializedDecl != 0); AggSlot = AggValueSlot::forAddr(ReferenceTemporary, Qualifiers(), isDestructed, - AggValueSlot::DoesNotNeedGCBarriers); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); } if (InitializedDecl) { diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 4a151fcfb8..c42c87b1ac 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -35,11 +35,18 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { AggValueSlot Dest; bool IgnoreResult; + /// We want to use 'dest' as the return slot except under two + /// conditions: + /// - The destination slot requires garbage collection, so we + /// need to use the GC API. + /// - The destination slot is potentially aliased. + bool shouldUseDestForReturnSlot() const { + return !(Dest.requiresGCollection() || Dest.isPotentiallyAliased()); + } + 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 (Dest.requiresGCollection()) return ReturnValueSlot(); + if (!shouldUseDestForReturnSlot()) + return ReturnValueSlot(); return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile()); } @@ -69,7 +76,7 @@ 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); + void EmitMoveFromReturnSlot(const Expr *E, RValue Src); AggValueSlot::NeedsGCBarriers_t needsGC(QualType T) { if (CGF.getLangOptions().getGCMode() && TypeRequiresGCollection(T)) @@ -179,23 +186,27 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) { return Record->hasObjectMember(); } -/// \brief Perform the final move to DestPtr if RequiresGCollection is set. +/// \brief Perform the final move to DestPtr if for some reason +/// getReturnValueSlot() didn't use it directly. /// /// 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 (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()); - CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), - Src.getAggregateAddr(), - SizeVal); +/// EmitMoveFromReturnSlot(E, Result); +/// +/// 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) { + if (shouldUseDestForReturnSlot()) { + // Logically, Dest.getAddr() should equal Src.getAggregateAddr(). + // The possibility of undef rvalues complicates that a lot, + // though, so we can't really assert. + return; } + + // Otherwise, do a final copy, + assert(Dest.getAddr() != Src.getAggregateAddr()); + EmitFinalDestCopy(E, Src, /*Ignore*/ true); } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. @@ -316,7 +327,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { LValue LV = CGF.EmitLValue(E->getSubExpr()); assert(LV.isPropertyRef()); RValue RV = CGF.EmitLoadOfPropertyRefLValue(LV, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); break; } @@ -381,12 +392,12 @@ void AggExprEmitter::VisitCallExpr(const CallExpr *E) { } RValue RV = CGF.EmitCallExpr(E, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); } void AggExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { RValue RV = CGF.EmitObjCMessageExpr(E, getReturnValueSlot()); - EmitGCMove(E, RV); + EmitMoveFromReturnSlot(E, RV); } void AggExprEmitter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { @@ -600,6 +611,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) { CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, Dest.isZeroed())); } else if (LV.isSimple()) { CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 83a42fb9c5..179dc75b31 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -820,7 +820,8 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, LoadObjCSelf(), Ivar, 0); EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers)); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } // constructor returns 'self'. CodeGenTypes &Types = CGM.getTypes(); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index b7b127fc50..461a173f53 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -786,7 +786,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } else { EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Qualifiers(), AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers)); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased)); } EmitBranchThroughCleanup(ReturnBlock); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index dda9693f42..c448949d13 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -347,9 +347,14 @@ class AggValueSlot { /// be set. bool ZeroedFlag : 1; + /// AliasedFlag - This generally defaults to false, but can be true + /// if the memory is known not to be aliased. + bool AliasedFlag : 1; + public: - enum IsZeroed_t { IsNotZeroed, IsZeroed }; + enum IsAliased_t { IsNotAliased, IsAliased }; enum IsDestructed_t { IsNotDestructed, IsDestructed }; + enum IsZeroed_t { IsNotZeroed, IsZeroed }; enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers }; /// ignored - Returns an aggregate value slot indicating that the @@ -358,7 +363,10 @@ public: AggValueSlot AV; AV.Addr = 0; AV.Quals = Qualifiers(); - AV.LifetimeFlag = AV.RequiresGCollection = AV.ZeroedFlag = 0; + AV.LifetimeFlag = AV.RequiresGCollection = AV.ZeroedFlag = false; + + // If there's ever an address here, it will be a temporary. + AV.AliasedFlag = false; return AV; } @@ -375,6 +383,7 @@ public: static AggValueSlot forAddr(llvm::Value *addr, Qualifiers quals, IsDestructed_t isDestructed, NeedsGCBarriers_t needsGC, + IsAliased_t isAliased = IsAliased, IsZeroed_t isZeroed = IsNotZeroed) { AggValueSlot AV; AV.Addr = addr; @@ -382,14 +391,16 @@ public: AV.LifetimeFlag = isDestructed; AV.RequiresGCollection = needsGC; AV.ZeroedFlag = isZeroed; + AV.AliasedFlag = isAliased; return AV; } static AggValueSlot forLValue(LValue LV, IsDestructed_t isDestructed, NeedsGCBarriers_t needsGC, + IsAliased_t isAliased = IsAliased, IsZeroed_t isZeroed = IsNotZeroed) { return forAddr(LV.getAddress(), LV.getQuals(), - isDestructed, needsGC, isZeroed); + isDestructed, needsGC, isAliased, isZeroed); } IsDestructed_t isLifetimeExternallyManaged() const { @@ -421,6 +432,10 @@ public: return Addr == 0; } + IsAliased_t isPotentiallyAliased() const { + return IsAliased_t(AliasedFlag); + } + RValue asRValue() const { return RValue::getAggregate(getAddr(), isVolatile()); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 2d47301ec5..36dcffcd4c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1466,7 +1466,8 @@ public: AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") { return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(), AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers); + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased); } /// Emit a cast to void* in the appropriate address space. |