diff options
author | John McCall <rjmccall@apple.com> | 2010-09-15 10:14:12 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-09-15 10:14:12 +0000 |
commit | 558d2abc7f9fd6801cc7677200992313ae90b5d8 (patch) | |
tree | 7624495cd37a259daceff9065f500f9522cbd775 /lib/CodeGen | |
parent | 8f3b834471b158d65d490e3458fa16ba659ec105 (diff) |
one piece of code is responsible for the lifetime of every aggregate
slot. The easiest way to do that was to bundle up the information
we care about for aggregate slots into a new structure which demands
that its creators at least consider the question.
I could probably be convinced that the ObjC 'needs GC' bit should
be rolled into this structure.
Implement generalized copy elision. The main obstacle here is that
IR-generation must be much more careful about making sure that exactly
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113962 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGException.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 45 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 157 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 36 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGTemporaries.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGValue.h | 63 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 37 |
14 files changed, 213 insertions, 170 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index d4e703ce03..35a2ada974 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -352,7 +352,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { SourceLocation()); } - RValue r = EmitAnyExpr(E, Addr, false); + RValue r = EmitAnyExpr(E, AggValueSlot::forAddr(Addr, false, true)); if (r.isScalar()) { llvm::Value *Loc = r.getScalarVal(); const llvm::Type *Ty = Types[i+BlockFields]; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index bf26799b83..a6ac0acfb9 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -362,7 +362,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, BaseClassDecl, isBaseVirtual); - CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); + AggValueSlot AggSlot = AggValueSlot::forAddr(V, false, /*Lifetime*/ true); + + CGF.EmitAggExpr(BaseInit->getInit(), AggSlot); if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl, @@ -388,11 +390,11 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, Next = CGF.Builder.CreateAdd(ArrayIndex, Next, "inc"); CGF.Builder.CreateStore(Next, ArrayIndexVar); } + + AggValueSlot Slot = AggValueSlot::forAddr(Dest, LHS.isVolatileQualified(), + /*Lifetime*/ true); - CGF.EmitAggExpr(MemberInit->getInit(), Dest, - LHS.isVolatileQualified(), - /*IgnoreResult*/ false, - /*IsInitializer*/ true); + CGF.EmitAggExpr(MemberInit->getInit(), Slot); return; } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 965400135e..b743c0c6b4 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -761,7 +761,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, } else if (Init->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { - EmitAggExpr(Init, Loc, isVolatile); + EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true)); } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 565c865c34..1b42f6189e 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -38,7 +38,7 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { - CGF.EmitAggExpr(Init, DeclPtr, isVolatile); + CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true)); } } diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 7fb616e5a1..1063e28b84 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -457,7 +457,7 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, // evaluated but before the exception is caught. But the best way // to handle that is to teach EmitAggExpr to do the final copy // differently if it can't be elided. - CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false); + CGF.EmitAnyExprToMem(E, TypedExnLoc, /*Volatile*/ false, /*IsInit*/ true); CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), ShouldFreeVar); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index bb0462f963..9c1a3cf249 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -78,35 +78,31 @@ llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { return EmitComplexToScalarConversion(EmitComplexExpr(E), E->getType(),BoolTy); } -/// EmitAnyExpr - Emit code to compute the specified expression which can have -/// any type. The result is returned as an RValue struct. If this is an -/// aggregate expression, the aggloc/agglocvolatile arguments indicate where the +/// EmitAnyExpr - Emit code to compute the specified expression which +/// 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, llvm::Value *AggLoc, - bool IsAggLocVolatile, bool IgnoreResult, - bool IsInitializer) { +RValue CodeGenFunction::EmitAnyExpr(const Expr *E, AggValueSlot AggSlot, + bool IgnoreResult) { if (!hasAggregateLLVMType(E->getType())) return RValue::get(EmitScalarExpr(E, IgnoreResult)); else if (E->getType()->isAnyComplexType()) return RValue::getComplex(EmitComplexExpr(E, false, false, IgnoreResult, IgnoreResult)); - EmitAggExpr(E, AggLoc, IsAggLocVolatile, IgnoreResult, IsInitializer); - return RValue::getAggregate(AggLoc, IsAggLocVolatile); + EmitAggExpr(E, AggSlot, IgnoreResult); + return AggSlot.asRValue(); } /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will /// always be accessible even if no aggregate location is provided. -RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E, - bool IsAggLocVolatile, - bool IsInitializer) { - llvm::Value *AggLoc = 0; +RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) { + AggValueSlot AggSlot = AggValueSlot::ignored(); if (hasAggregateLLVMType(E->getType()) && !E->getType()->isAnyComplexType()) - AggLoc = CreateMemTemp(E->getType(), "agg.tmp"); - return EmitAnyExpr(E, AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false, - IsInitializer); + AggSlot = CreateAggTemp(E->getType(), "agg.tmp"); + return EmitAnyExpr(E, AggSlot); } /// EmitAnyExprToMem - Evaluate an expression into a given memory @@ -118,7 +114,7 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, if (E->getType()->isComplexType()) EmitComplexExprIntoAddr(E, Location, IsLocationVolatile); else if (hasAggregateLLVMType(E->getType())) - EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit); + EmitAggExpr(E, AggValueSlot::forAddr(Location, IsLocationVolatile, IsInit)); else { RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); LValue LV = MakeAddrLValue(Location, E->getType()); @@ -247,13 +243,16 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, } // Create a reference temporary if necessary. + AggValueSlot AggSlot = AggValueSlot::ignored(); if (CGF.hasAggregateLLVMType(E->getType()) && - !E->getType()->isAnyComplexType()) + !E->getType()->isAnyComplexType()) { ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), InitializedDecl); + AggSlot = AggValueSlot::forAddr(ReferenceTemporary, false, + InitializedDecl != 0); + } - RV = CGF.EmitAnyExpr(E, ReferenceTemporary, /*IsAggLocVolatile=*/false, - /*IgnoreResult=*/false, InitializedDecl); + RV = CGF.EmitAnyExpr(E, AggSlot); if (InitializedDecl) { // Get the destructor for the reference temporary. @@ -1673,7 +1672,7 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ const Expr *InitExpr = E->getInitializer(); LValue Result = MakeAddrLValue(DeclPtr, E->getType()); - EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false); + EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false, /*Init*/ true); return Result; } @@ -1965,9 +1964,9 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { } LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { - llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp"); - EmitCXXConstructExpr(Temp, E); - return MakeAddrLValue(Temp, E->getType()); + AggValueSlot Slot = CreateAggTemp(E->getType(), "tmp"); + EmitCXXConstructExpr(E, Slot); + return MakeAddrLValue(Slot.getAddr(), E->getType()); } LValue diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index f1bc692cf4..9ed20f382e 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -32,10 +32,8 @@ namespace { class AggExprEmitter : public StmtVisitor<AggExprEmitter> { CodeGenFunction &CGF; CGBuilderTy &Builder; - llvm::Value *DestPtr; - bool VolatileDest; + AggValueSlot Dest; bool IgnoreResult; - bool IsInitializer; bool RequiresGCollection; ReturnValueSlot getReturnValueSlot() const { @@ -44,15 +42,19 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { // API. if (RequiresGCollection) return ReturnValueSlot(); - return ReturnValueSlot(DestPtr, VolatileDest); + return ReturnValueSlot(Dest.getAddr(), Dest.isVolatile()); + } + + AggValueSlot EnsureSlot(QualType T) { + if (!Dest.isIgnored()) return Dest; + return CGF.CreateAggTemp(T, "agg.tmp.ensured"); } public: - AggExprEmitter(CodeGenFunction &cgf, llvm::Value *destPtr, bool v, - bool ignore, bool isinit, bool requiresGCollection) - : CGF(cgf), Builder(CGF.Builder), - DestPtr(destPtr), VolatileDest(v), IgnoreResult(ignore), - IsInitializer(isinit), RequiresGCollection(requiresGCollection) { + AggExprEmitter(CodeGenFunction &cgf, AggValueSlot Dest, + bool ignore, bool requiresGCollection) + : CGF(cgf), Builder(CGF.Builder), Dest(Dest), + IgnoreResult(ignore), RequiresGCollection(requiresGCollection) { } //===--------------------------------------------------------------------===// @@ -182,7 +184,7 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { unsigned long size = TypeInfo.first/8; const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); - CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, + CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), Src.getAggregateAddr(), SizeVal); } @@ -192,13 +194,13 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { assert(Src.isAggregate() && "value must be aggregate value!"); - // If DestPtr is null, then we're evaluating an aggregate expression + // 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 (DestPtr == 0) { + if (Dest.isIgnored()) { if (!Src.isVolatileQualified() || CGF.CGM.getLangOptions().CPlusPlus || (IgnoreResult && Ignore)) @@ -206,7 +208,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { // If the source is volatile, we must read from it; to do that, we need // some place to put it. - DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp"); + Dest = CGF.CreateAggTemp(E->getType(), "agg.tmp"); } if (RequiresGCollection) { @@ -216,16 +218,17 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, - DestPtr, Src.getAggregateAddr(), - SizeVal); + Dest.getAddr(), + Src.getAggregateAddr(), + SizeVal); 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(DestPtr, Src.getAggregateAddr(), E->getType(), - VolatileDest|Src.isVolatileQualified()); + CGF.EmitAggregateCopy(Dest.getAddr(), Src.getAggregateAddr(), E->getType(), + Dest.isVolatile()|Src.isVolatileQualified()); } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. @@ -242,7 +245,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { //===----------------------------------------------------------------------===// void AggExprEmitter::VisitCastExpr(CastExpr *E) { - if (!DestPtr && E->getCastKind() != CK_Dynamic) { + if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) { Visit(E->getSubExpr()); return; } @@ -259,8 +262,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { else CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast"); - if (DestPtr) - CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination"); + if (!Dest.isIgnored()) + CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination"); break; } @@ -268,7 +271,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { // GCC union extension QualType Ty = E->getSubExpr()->getType(); QualType PtrTy = CGF.getContext().getPointerType(Ty); - llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr, + llvm::Value *CastPtr = Builder.CreateBitCast(Dest.getAddr(), CGF.ConvertType(PtrTy)); EmitInitializationToLValue(E->getSubExpr(), CGF.MakeAddrLValue(CastPtr, Ty), Ty); @@ -327,13 +330,12 @@ void AggExprEmitter::VisitObjCImplicitSetterGetterRefExpr( } void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { - CGF.EmitAnyExpr(E->getLHS(), 0, false, true); - CGF.EmitAggExpr(E->getRHS(), DestPtr, VolatileDest, - /*IgnoreResult=*/false, IsInitializer); + CGF.EmitAnyExpr(E->getLHS(), AggValueSlot::ignored(), true); + Visit(E->getRHS()); } void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { - CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); + CGF.EmitCompoundStmt(*E->getSubStmt(), true, Dest); } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { @@ -360,27 +362,21 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { - llvm::Value *AggLoc = DestPtr; - if (!AggLoc) - AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); - CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); - CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), - RValue::getAggregate(AggLoc, VolatileDest)); + AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); + CGF.EmitAggExpr(E->getRHS(), Slot); + CGF.EmitObjCPropertySet(LHS.getPropertyRefExpr(), Slot.asRValue()); } else if (LHS.isKVCRef()) { - llvm::Value *AggLoc = DestPtr; - if (!AggLoc) - AggLoc = CGF.CreateMemTemp(E->getRHS()->getType()); - CGF.EmitAggExpr(E->getRHS(), AggLoc, VolatileDest); - CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), - RValue::getAggregate(AggLoc, VolatileDest)); + AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); + CGF.EmitAggExpr(E->getRHS(), Slot); + CGF.EmitObjCPropertySet(LHS.getKVCRefExpr(), Slot.asRValue()); } else { bool RequiresGCollection = false; 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); + AggValueSlot LHSSlot = AggValueSlot::forLValue(LHS, true); + CGF.EmitAggExpr(E->getRHS(), LHSSlot, false, RequiresGCollection); EmitFinalDestCopy(E, LHS, true); } } @@ -434,58 +430,40 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { } void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - llvm::Value *Val = DestPtr; - - if (!Val) { - // Create a temporary variable. - Val = CGF.CreateMemTemp(E->getType(), "tmp"); - - // FIXME: volatile - CGF.EmitAggExpr(E->getSubExpr(), Val, false); - } else - Visit(E->getSubExpr()); - - // Don't make this a live temporary if we're emitting an initializer expr. - if (!IsInitializer) - CGF.EmitCXXTemporary(E->getTemporary(), Val); + // Ensure that we have a slot, but if we already do, remember + // whether its lifetime was externally managed. + bool WasManaged = Dest.isLifetimeExternallyManaged(); + Dest = EnsureSlot(E->getType()); + Dest.setLifetimeExternallyManaged(); + + Visit(E->getSubExpr()); + + // Set up the temporary's destructor if its lifetime wasn't already + // being managed. + if (!WasManaged) + CGF.EmitCXXTemporary(E->getTemporary(), Dest.getAddr()); } void AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { - llvm::Value *Val = DestPtr; - - if (!Val) // Create a temporary variable. - Val = CGF.CreateMemTemp(E->getType(), "tmp"); - - CGF.EmitCXXConstructExpr(Val, E); + AggValueSlot Slot = EnsureSlot(E->getType()); + CGF.EmitCXXConstructExpr(E, Slot); } void AggExprEmitter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { - llvm::Value *Val = DestPtr; - - CGF.EmitCXXExprWithTemporaries(E, Val, VolatileDest, IsInitializer); + CGF.EmitCXXExprWithTemporaries(E, Dest); } void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { - llvm::Value *Val = DestPtr; - - if (!Val) { - // Create a temporary variable. - Val = CGF.CreateMemTemp(E->getType(), "tmp"); - } - EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()), - E->getType()); + QualType T = E->getType(); + AggValueSlot Slot = EnsureSlot(T); + EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T); } void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { - llvm::Value *Val = DestPtr; - - if (!Val) { - // Create a temporary variable. - Val = CGF.CreateMemTemp(E->getType(), "tmp"); - } - EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()), - E->getType()); + QualType T = E->getType(); + AggValueSlot Slot = EnsureSlot(T); + EmitNullInitializationToLValue(CGF.MakeAddrLValue(Slot.getAddr(), T), T); } void @@ -500,7 +478,7 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV, QualType T) { } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false); } else if (CGF.hasAggregateLLVMType(T)) { - CGF.EmitAnyExpr(E, LV.getAddress(), false); + CGF.EmitAggExpr(E, AggValueSlot::forAddr(LV.getAddress(), false, true)); } else { CGF.EmitStoreThroughLValue(CGF.EmitAnyExpr(E), LV, T); } @@ -537,6 +515,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (E->hadArrayRangeDesignator()) CGF.ErrorUnsupported(E, "GNU array range designator extension"); + llvm::Value *DestPtr = Dest.getAddr(); + // Handle initialization of an array. if (E->getType()->isArrayType()) { const llvm::PointerType *APType = @@ -660,19 +640,20 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *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. +/// +/// \param IsInitializer - true if this evaluation is initializing an +/// object whose lifetime is already being managed. // // FIXME: Take Qualifiers object. -void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, - bool VolatileDest, bool IgnoreResult, - bool IsInitializer, +void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot, + bool IgnoreResult, bool RequiresGCollection) { assert(E && hasAggregateLLVMType(E->getType()) && "Invalid aggregate expression to emit"); - assert ((DestPtr != 0 || VolatileDest == false) - && "volatile aggregate can't be 0"); + assert((Slot.getAddr() != 0 || Slot.isIgnored()) + && "slot has bits but no address"); - AggExprEmitter(*this, DestPtr, VolatileDest, IgnoreResult, IsInitializer, - RequiresGCollection) + AggExprEmitter(*this, Slot, IgnoreResult, RequiresGCollection) .Visit(const_cast<Expr*>(E)); } @@ -680,7 +661,9 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!"); llvm::Value *Temp = CreateMemTemp(E->getType()); LValue LV = MakeAddrLValue(Temp, E->getType()); - EmitAggExpr(E, Temp, LV.isVolatileQualified()); + AggValueSlot Slot + = AggValueSlot::forAddr(Temp, LV.isVolatileQualified(), false); + EmitAggExpr(E, Slot); return LV; } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 10e29d199c..584f6c099b 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -219,16 +219,12 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, LValue LV = EmitLValue(E->getArg(0)); llvm::Value *This; if (LV.isPropertyRef() || LV.isKVCRef()) { - llvm::Value *AggLoc = CreateMemTemp(E->getArg(1)->getType()); - EmitAggExpr(E->getArg(1), AggLoc, false /*VolatileDest*/); + AggValueSlot Slot = CreateAggTemp(E->getArg(1)->getType()); + EmitAggExpr(E->getArg(1), Slot); if (LV.isPropertyRef()) - EmitObjCPropertySet(LV.getPropertyRefExpr(), - RValue::getAggregate(AggLoc, - false /*VolatileDest*/)); + EmitObjCPropertySet(LV.getPropertyRefExpr(), Slot.asRValue()); else - EmitObjCPropertySet(LV.getKVCRefExpr(), - RValue::getAggregate(AggLoc, - false /*VolatileDest*/)); + EmitObjCPropertySet(LV.getKVCRefExpr(), Slot.asRValue()); return RValue::getAggregate(0, false); } else @@ -269,17 +265,16 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, } void -CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, - const CXXConstructExpr *E) { - assert(Dest && "Must have a destination!"); +CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, + AggValueSlot Dest) { + assert(!Dest.isIgnored() && "Must have a destination!"); const CXXConstructorDecl *CD = E->getConstructor(); // If we require zero initialization before (or instead of) calling the // constructor, as can be the case with a non-user-provided default // constructor, emit the zero initialization now. if (E->requiresZeroInitialization()) - EmitNullInitialization(Dest, E->getType()); - + EmitNullInitialization(Dest.getAddr(), E->getType()); // If this is a call to a trivial default constructor, do nothing. if (CD->isTrivial() && CD->isDefaultConstructor()) @@ -289,8 +284,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, // its first argument instead, if in fact that argument is a temporary // object. if (getContext().getLangOptions().ElideConstructors && E->isElidable()) { - if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) { - EmitAggExpr(Arg, Dest, false); + if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) { + EmitAggExpr(E->getArg(0), Dest); return; } } @@ -302,7 +297,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const llvm::Type *BasePtr = ConvertType(BaseElementTy); BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(Dest, BasePtr); + Builder.CreateBitCast(Dest.getAddr(), BasePtr); EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr, E->arg_begin(), E->arg_end()); @@ -315,7 +310,7 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; // Call the constructor. - EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest, + EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(), E->arg_begin(), E->arg_end()); } } @@ -539,8 +534,11 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, else if (AllocType->isAnyComplexType()) CGF.EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified()); - else - CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); + else { + AggValueSlot Slot + = AggValueSlot::forAddr(NewPtr, AllocType.isVolatileQualified(), true); + CGF.EmitAggExpr(Init, Slot); + } } void diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 45c5fb9f0b..d4b1bd940c 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1063,7 +1063,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { CGF.EmitLoadOfKVCRefLValue(LV, E->getType()); } else - CGF.EmitAnyExpr(E, 0, false, true); + CGF.EmitAnyExpr(E, AggValueSlot::ignored(), true); return 0; } case CK_VectorSplat: { @@ -1127,7 +1127,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // Okay, this is a cast from an aggregate. It must be a cast to void. Just // evaluate the result and return. - CGF.EmitAggExpr(E, 0, false, true); + CGF.EmitAggExpr(E, AggValueSlot::ignored(), true); return 0; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 5b0c2630a0..8abcbea5d0 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -386,8 +386,7 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), GetCopyStructFn, ReturnValueSlot(), Args); } else if (PID->getSetterCXXAssignment()) { - EmitAnyExpr(PID->getSetterCXXAssignment(), (llvm::Value *)0, false, true, - false); + EmitAnyExpr(PID->getSetterCXXAssignment(), AggValueSlot::ignored(), true); } else { // FIXME: Find a clean way to avoid AST node creation. @@ -438,8 +437,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - EmitAggExpr(IvarInit->getInit(), LV.getAddress(), - LV.isVolatileQualified(), false, true); + EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, true)); } // constructor returns 'self'. CodeGenTypes &Types = CGM.getTypes(); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 16145f766a..a70534d2ca 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -75,7 +75,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { if (!isa<Expr>(S)) ErrorUnsupported(S, "statement"); - EmitAnyExpr(cast<Expr>(S), 0, false, true); + EmitAnyExpr(cast<Expr>(S), AggValueSlot::ignored(), true); // Expression emitters don't handle unreachable blocks yet, so look for one // explicitly here. This handles the common case of a call to a noreturn @@ -146,7 +146,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) { /// this captures the expression result of the last sub-statement and returns it /// (for use by the statement expression extension). RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, - llvm::Value *AggLoc, bool isAggVol) { + AggValueSlot AggSlot) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),S.getLBracLoc(), "LLVM IR generation of compound statement ('{}')"); @@ -184,7 +184,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, EnsureInsertPoint(); - RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc); + RV = EmitAnyExpr(cast<Expr>(LastStmt), AggSlot); } return RV; @@ -643,7 +643,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { } else if (RV->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(RV, ReturnValue, false); } else { - EmitAggExpr(RV, ReturnValue, false); + EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, false, true)); } EmitBranchThroughCleanup(ReturnBlock); diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index dfb8dc63c5..ba01b72e54 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -77,12 +77,9 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, RValue CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, - llvm::Value *AggLoc, - bool IsAggLocVolatile, - bool IsInitializer) { + AggValueSlot Slot) { RunCleanupsScope Scope(*this); - return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, - /*IgnoreResult=*/false, IsInitializer); + return EmitAnyExpr(E->getSubExpr(), Slot); } LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index f57ecd245f..42b8335ecd 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -321,6 +321,69 @@ public: } }; +/// An aggregate value slot. +class AggValueSlot { + /// The address and associated flags. + uintptr_t AddrAndFlags; + + static const uintptr_t VolatileFlag = 0x1; + static const uintptr_t LifetimeFlag = 0x2; + static const uintptr_t AddrMask = ~(VolatileFlag | LifetimeFlag); + +public: + /// ignored - Returns an aggregate value slot indicating that the + /// aggregate value is being ignored. + static AggValueSlot ignored() { + AggValueSlot AV; + AV.AddrAndFlags = 0; + return AV; + } + + /// forAddr - Make a slot for an aggregate value. + /// + /// \param Volatile - true if the slot should be volatile-initialized + /// \param LifetimeExternallyManaged - true if the slot's lifetime + /// is being externally managed; false if a destructor should be + /// registered for any temporaries evaluated into the slot + static AggValueSlot forAddr(llvm::Value *Addr, bool Volatile, + bool LifetimeExternallyManaged) { + AggValueSlot AV; + AV.AddrAndFlags = reinterpret_cast<uintptr_t>(Addr); + if (Volatile) AV.AddrAndFlags |= VolatileFlag; + if (LifetimeExternallyManaged) AV.AddrAndFlags |= LifetimeFlag; + return AV; + } + + static AggValueSlot forLValue(LValue LV, bool LifetimeExternallyManaged) { + return forAddr(LV.getAddress(), LV.isVolatileQualified(), + LifetimeExternallyManaged); + } + + bool isLifetimeExternallyManaged() const { + return AddrAndFlags & LifetimeFlag; + } + void setLifetimeExternallyManaged() { + AddrAndFlags |= LifetimeFlag; + } + + bool isVolatile() const { + return AddrAndFlags & VolatileFlag; + } + + llvm::Value *getAddr() const { + return reinterpret_cast<llvm::Value*>(AddrAndFlags & AddrMask); + } + + bool isIgnored() const { + return AddrAndFlags == 0; + } + + RValue asRValue() const { + return RValue::getAggregate(getAddr(), isVolatile()); + } + +}; + } // end namespace CodeGen } // end namespace clang |