[cfe-commits] r103849 - in /cfe/trunk/lib: CodeGen/CGExprCXX.cpp Frontend/PCHReaderStmt.cpp Frontend/PCHWriterStmt.cpp Sema/SemaExprCXX.cpp Sema/SemaInit.cpp Sema/SemaInit.h Sema/SemaObjCProperty.cpp Sema/SemaStmt.cpp
Douglas Gregor
dgregor at apple.com
Fri May 14 17:13:29 PDT 2010
Author: dgregor
Date: Fri May 14 19:13:29 2010
New Revision: 103849
URL: http://llvm.org/viewvc/llvm-project?rev=103849&view=rev
Log:
Recognize when the named return value optimization applies in a
"return" statement and mark the corresponding CXXConstructExpr as
elidable. Teach CodeGen that eliding a temporary is different from
eliding an object construction.
This is just a baby step toward NRVO.
Modified:
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaInit.h
cfe/trunk/lib/Sema/SemaObjCProperty.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Fri May 14 19:13:29 2010
@@ -321,11 +321,13 @@
return;
}
// Code gen optimization to eliminate copy constructor and return
- // its first argument instead.
+ // its first argument instead, if in fact that argument is a temporary
+ // object.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- const Expr *Arg = E->getArg(0)->getTemporaryObject();
- EmitAggExpr(Arg, Dest, false);
- return;
+ if (const Expr *Arg = E->getArg(0)->getTemporaryObject()) {
+ EmitAggExpr(Arg, Dest, false);
+ return;
+ }
}
if (Array) {
QualType BaseElementTy = getContext().getBaseElementType(Array);
Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Fri May 14 19:13:29 2010
@@ -956,6 +956,7 @@
E->setRequiresZeroInitialization(Record[Idx++]);
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
E->setArg(I, cast<Expr>(StmtStack[StmtStack.size() - N + I]));
+ E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
return E->getNumArgs();
}
Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Fri May 14 19:13:29 2010
@@ -873,6 +873,7 @@
Record.push_back(E->getNumArgs());
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
Writer.WriteSubStmt(E->getArg(I));
+ Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Code = pch::EXPR_CXX_CONSTRUCT;
}
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri May 14 19:13:29 2010
@@ -441,8 +441,10 @@
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
+ // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p34.
InitializedEntity Entity =
- InitializedEntity::InitializeException(ThrowLoc, E->getType());
+ InitializedEntity::InitializeException(ThrowLoc, E->getType(),
+ /*NRVO=*/false);
OwningExprResult Res = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(E));
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri May 14 19:13:29 2010
@@ -1984,6 +1984,26 @@
return 0;
}
+bool InitializedEntity::allowsNRVO() const {
+ switch (getKind()) {
+ case EK_Result:
+ case EK_Exception:
+ return LocAndNRVO.NRVO;
+
+ case EK_Variable:
+ case EK_Parameter:
+ case EK_Member:
+ case EK_New:
+ case EK_Temporary:
+ case EK_Base:
+ case EK_ArrayElement:
+ case EK_VectorElement:
+ break;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -3242,9 +3262,9 @@
// directly into the target of the omitted copy/move
//
// Note that the other three bullets are handled elsewhere. Copy
- // elision for return statements and throw expressions are (FIXME:
- // not yet) handled as part of constructor initialization, while
- // copy elision for exception handlers is handled by the run-time.
+ // elision for return statements and throw expressions are handled as part
+ // of constructor initialization, while copy elision for exception handlers
+ // is handled by the run-time.
bool Elidable = CurInitExpr->isTemporaryObject() &&
S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType());
SourceLocation Loc;
@@ -3737,7 +3757,7 @@
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step->Function.Function);
-
+
// Build a call to the selected constructor.
ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S);
SourceLocation Loc = Kind.getLocation();
@@ -3774,11 +3794,21 @@
CXXConstructExpr::CK_VirtualBase :
CXXConstructExpr::CK_NonVirtualBase;
}
- CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
- Constructor,
- move_arg(ConstructorArgs),
- ConstructorInitRequiresZeroInit,
- ConstructKind);
+
+ // If the entity allows NRVO, mark the construction as elidable
+ // unconditionally.
+ if (Entity.allowsNRVO())
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor, /*Elidable=*/true,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
+ else
+ CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Constructor,
+ move_arg(ConstructorArgs),
+ ConstructorInitRequiresZeroInit,
+ ConstructKind);
}
if (CurInit.isInvalid())
return S.ExprError();
Modified: cfe/trunk/lib/Sema/SemaInit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.h?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.h (original)
+++ cfe/trunk/lib/Sema/SemaInit.h Fri May 14 19:13:29 2010
@@ -85,11 +85,16 @@
/// the VarDecl, ParmVarDecl, or FieldDecl, respectively.
DeclaratorDecl *VariableOrMember;
- /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
- /// location of the 'return', 'throw', or 'new' keyword,
- /// respectively. When Kind == EK_Temporary, the location where
- /// the temporary is being created.
- unsigned Location;
+ struct {
+ /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
+ unsigned Location;
+
+ /// \brief Whether the
+ bool NRVO;
+ } LocAndNRVO;
/// \brief When Kind == EK_Base, the base specifier that provides the
/// base class. The lower bit specifies whether the base is an inherited
@@ -116,8 +121,13 @@
/// \brief Create the initialization entity for the result of a
/// function, throwing an object, performing an explicit cast, or
/// initializing a parameter for which there is no declaration.
- InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type)
- : Kind(Kind), Parent(0), Type(Type), Location(Loc.getRawEncoding()) { }
+ InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type,
+ bool NRVO = false)
+ : Kind(Kind), Parent(0), Type(Type)
+ {
+ LocAndNRVO.Location = Loc.getRawEncoding();
+ LocAndNRVO.NRVO = NRVO;
+ }
/// \brief Create the initialization entity for a member subobject.
InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent)
@@ -152,14 +162,14 @@
/// \brief Create the initialization entity for the result of a function.
static InitializedEntity InitializeResult(SourceLocation ReturnLoc,
- QualType Type) {
- return InitializedEntity(EK_Result, ReturnLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an exception object.
static InitializedEntity InitializeException(SourceLocation ThrowLoc,
- QualType Type) {
- return InitializedEntity(EK_Exception, ThrowLoc, Type);
+ QualType Type, bool NRVO) {
+ return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO);
}
/// \brief Create the initialization entity for an object allocated via new.
@@ -208,6 +218,10 @@
/// initialized.
DeclaratorDecl *getDecl() const;
+ /// \brief Determine whether this initialization allows the named return
+ /// value optimization, which also applies to thrown objects.
+ bool allowsNRVO() const;
+
/// \brief Retrieve the base specifier.
CXXBaseSpecifier *getBaseSpecifier() const {
assert(getKind() == EK_Base && "Not a base specifier");
@@ -224,14 +238,14 @@
/// the result of a function call.
SourceLocation getReturnLoc() const {
assert(getKind() == EK_Result && "No 'return' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief Determine the location of the 'throw' keyword when initializing
/// an exception object.
SourceLocation getThrowLoc() const {
assert(getKind() == EK_Exception && "No 'throw' location!");
- return SourceLocation::getFromRawEncoding(Location);
+ return SourceLocation::getFromRawEncoding(LocAndNRVO.Location);
}
/// \brief If this is already the initializer for an array or vector
Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri May 14 19:13:29 2010
@@ -445,8 +445,9 @@
SelfExpr, true, true);
OwningExprResult Res =
PerformCopyInitialization(InitializedEntity::InitializeResult(
- SourceLocation(),
- getterMethod->getResultType()),
+ SourceLocation(),
+ getterMethod->getResultType(),
+ /*NRVO=*/false),
SourceLocation(),
Owned(IvarRefExpr));
if (!Res.isInvalid()) {
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=103849&r1=103848&r2=103849&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri May 14 19:13:29 2010
@@ -1058,6 +1058,31 @@
return Owned(new (Context) BreakStmt(BreakLoc));
}
+/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
+/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p34).
+static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
+ Expr *RetExpr) {
+ QualType ExprType = RetExpr->getType();
+ // - in a return statement in a function with ...
+ // ... a class return type ...
+ if (!RetType->isRecordType())
+ return false;
+ // ... the same cv-unqualified type as the function return type ...
+ if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
+ return false;
+ // ... the expression is the name of a non-volatile automatic object ...
+ // We ignore parentheses here.
+ // FIXME: Is this compliant? (Everyone else does it)
+ const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
+ if (!DR)
+ return false;
+ const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
+ if (!VD)
+ return false;
+ return VD->getKind() == Decl::Var && VD->hasLocalStorage() &&
+ !VD->getType()->isReferenceType() && !VD->getType().isVolatileQualified();
+}
+
/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
///
Action::OwningStmtResult
@@ -1115,7 +1140,10 @@
// the C version of which boils down to CheckSingleAssignmentConstraints.
OwningExprResult Res = PerformCopyInitialization(
InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
+ FnRetType,
+ IsReturnCopyElidable(Context,
+ FnRetType,
+ RetValExp)),
SourceLocation(),
Owned(RetValExp));
if (Res.isInvalid()) {
@@ -1131,31 +1159,6 @@
return Owned(new (Context) ReturnStmt(ReturnLoc, RetValExp));
}
-/// IsReturnCopyElidable - Whether returning @p RetExpr from a function that
-/// returns a @p RetType fulfills the criteria for copy elision (C++0x 12.8p15).
-static bool IsReturnCopyElidable(ASTContext &Ctx, QualType RetType,
- Expr *RetExpr) {
- QualType ExprType = RetExpr->getType();
- // - in a return statement in a function with ...
- // ... a class return type ...
- if (!RetType->isRecordType())
- return false;
- // ... the same cv-unqualified type as the function return type ...
- if (!Ctx.hasSameUnqualifiedType(RetType, ExprType))
- return false;
- // ... the expression is the name of a non-volatile automatic object ...
- // We ignore parentheses here.
- // FIXME: Is this compliant?
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetExpr->IgnoreParens());
- if (!DR)
- return false;
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return false;
- return VD->hasLocalStorage() && !VD->getType()->isReferenceType()
- && !VD->getType().isVolatileQualified();
-}
-
Action::OwningStmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
Expr *RetValExp = rex.takeAs<Expr>();
@@ -1214,29 +1217,18 @@
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
- // C++0x 12.8p15: When certain criteria are met, an implementation is
- // allowed to omit the copy construction of a class object, [...]
- // - in a return statement in a function with a class return type, when
- // the expression is the name of a non-volatile automatic object with
- // the same cv-unqualified type as the function return type, the copy
- // operation can be omitted [...]
- // C++0x 12.8p16: When the criteria for elision of a copy operation are met
- // and the object to be copied is designated by an lvalue, overload
- // resolution to select the constructor for the copy is first performed
- // as if the object were designated by an rvalue.
- // Note that we only compute Elidable if we're in C++0x, since we don't
- // care otherwise.
- bool Elidable = getLangOptions().CPlusPlus0x ?
- IsReturnCopyElidable(Context, FnRetType, RetValExp) :
- false;
- // FIXME: Elidable
- (void)Elidable;
-
+ // C++0x [class.copy]p34:
+ //
+
+
// In C++ the return statement is handled via a copy initialization.
// the C version of which boils down to CheckSingleAssignmentConstraints.
OwningExprResult Res = PerformCopyInitialization(
InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType),
+ FnRetType,
+ IsReturnCopyElidable(Context,
+ FnRetType,
+ RetValExp)),
SourceLocation(),
Owned(RetValExp));
if (Res.isInvalid()) {
More information about the cfe-commits
mailing list