r333500 - Update NRVO logic to support early return
Author: tzik Date: Tue May 29 20:53:16 2018 New Revision: 333500 URL: http://llvm.org/viewvc/llvm-project?rev=333500&view=rev Log: Update NRVO logic to support early return Summary: The previous implementation misses an opportunity to apply NRVO (Named Return Value Optimization) below. That discourages user to write early return code. ``` struct Foo {}; Foo f(bool b) { if (b) return Foo(); Foo oo; return oo; } ``` That is, we can/should apply RVO for a local variable if: * It's directly returned by at least one return statement. * And, all reachable return statements in its scope returns the variable directly. While, the previous implementation disables the RVO in a scope if there are multiple return statements that refers different variables. On the new algorithm, local variables are in NRVO_Candidate state at first, and a return statement changes it to NRVO_Disabled for all visible variables but the return statement refers. Then, at the end of the function AST traversal, NRVO is enabled for variables in NRVO_Candidate state and refers from at least one return statement. Reviewers: rsmith Reviewed By: rsmith Subscribers: xbolva00, Quuxplusone, arthur.j.odwyer, cfe-commits Differential Revision: https://reviews.llvm.org/D47067 Added: cfe/trunk/test/CodeGenCXX/nrvo-noopt.cpp cfe/trunk/test/SemaCXX/nrvo-ast.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/Sema/Scope.h cfe/trunk/lib/Sema/Scope.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CodeGenCXX/nrvo.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=333500&r1=333499&r2=333500&view=diff == --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Tue May 29 20:53:16 2018 @@ -879,6 +879,12 @@ protected: DAK_Normal }; + enum NRVOMode { +NRVO_Candidate, +NRVO_Disabled, +NRVO_Enabled, + }; + class ParmVarDeclBitfields { friend class ASTDeclReader; friend class ParmVarDecl; @@ -931,7 +937,7 @@ protected: /// Whether this local variable could be allocated in the return /// slot of its function, enabling the named return value optimization /// (NRVO). -unsigned NRVOVariable : 1; +unsigned NRVOMode : 2; /// Whether this variable is the for-range-declaration in a C++0x /// for-range statement. @@ -1319,12 +1325,20 @@ public: /// return slot when returning from the function. Within the function body, /// each return that returns the NRVO object will have this variable as its /// NRVO candidate. + NRVOMode getNRVOMode() const { +if (isa(this)) + return NRVO_Disabled; +return static_cast(NonParmVarDeclBits.NRVOMode); + } + bool isNRVOCandidate() const { +return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Candidate; + } bool isNRVOVariable() const { -return isa(this) ? false : NonParmVarDeclBits.NRVOVariable; +return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Enabled; } void setNRVOVariable(bool NRVO) { assert(!isa(this)); -NonParmVarDeclBits.NRVOVariable = NRVO; +NonParmVarDeclBits.NRVOMode = NRVO ? NRVO_Enabled : NRVO_Disabled; } /// Determine whether this variable is the for-range-declaration in Modified: cfe/trunk/include/clang/Sema/Scope.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=333500&r1=333499&r2=333500&view=diff == --- cfe/trunk/include/clang/Sema/Scope.h (original) +++ cfe/trunk/include/clang/Sema/Scope.h Tue May 29 20:53:16 2018 @@ -201,10 +201,6 @@ private: /// Used to determine if errors occurred in this scope. DiagnosticErrorTrap ErrorTrap; - /// A lattice consisting of undefined, a single NRVO candidate variable in - /// this scope, or over-defined. The bit is true when over-defined. - llvm::PointerIntPair NRVO; - void setFlags(Scope *Parent, unsigned F); public: @@ -466,23 +462,7 @@ public: UsingDirectives.end()); } - void addNRVOCandidate(VarDecl *VD) { -if (NRVO.getInt()) - return; -if (NRVO.getPointer() == nullptr) { - NRVO.setPointer(VD); - return; -} -if (NRVO.getPointer() != VD) - setNoNRVO(); - } - - void setNoNRVO() { -NRVO.setInt(true); -NRVO.setPointer(nullptr); - } - - void mergeNRVOIntoParent(); + void setNRVOCandidate(VarDecl *Candidate); /// Init - This is used by the parser to implement scope caching. void Init(Scope *parent, unsigned flags); Modified: cfe/trunk/lib/Sema/Scope.cpp URL: http://llvm.org/viewv
r335019 - Update NRVO logic to support early return (Attempt 2)
Author: tzik Date: Mon Jun 18 21:39:07 2018 New Revision: 335019 URL: http://llvm.org/viewvc/llvm-project?rev=335019&view=rev Log: Update NRVO logic to support early return (Attempt 2) Summary: This is the second attempt of r333500 (Update NRVO logic to support early return). The previous one was reverted for a miscompilation for an incorrect NRVO set up on templates such as: ``` struct Foo {}; template T bar() { T t; if (false) return T(); return t; } ``` Where, `t` is marked as non-NRVO variable before its instantiation. However, while its instantiation, it's left an NRVO candidate, turned into an NRVO variable later. Reviewers: rsmith Reviewed By: rsmith Subscribers: cfe-commits Differential Revision: https://reviews.llvm.org/D47586 Added: cfe/trunk/test/CodeGenCXX/nrvo-noopt.cpp cfe/trunk/test/SemaCXX/nrvo-ast.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/Sema/Scope.h cfe/trunk/lib/Sema/Scope.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CodeGenCXX/nrvo.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=335019&r1=335018&r2=335019&view=diff == --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Jun 18 21:39:07 2018 @@ -879,6 +879,12 @@ protected: DAK_Normal }; + enum NRVOMode { +NRVO_Candidate, +NRVO_Disabled, +NRVO_Enabled, + }; + class ParmVarDeclBitfields { friend class ASTDeclReader; friend class ParmVarDecl; @@ -931,7 +937,7 @@ protected: /// Whether this local variable could be allocated in the return /// slot of its function, enabling the named return value optimization /// (NRVO). -unsigned NRVOVariable : 1; +unsigned NRVOMode : 2; /// Whether this variable is the for-range-declaration in a C++0x /// for-range statement. @@ -1319,12 +1325,20 @@ public: /// return slot when returning from the function. Within the function body, /// each return that returns the NRVO object will have this variable as its /// NRVO candidate. + NRVOMode getNRVOMode() const { +if (isa(this)) + return NRVO_Disabled; +return static_cast(NonParmVarDeclBits.NRVOMode); + } + bool isNRVOCandidate() const { +return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Candidate; + } bool isNRVOVariable() const { -return isa(this) ? false : NonParmVarDeclBits.NRVOVariable; +return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Enabled; } void setNRVOVariable(bool NRVO) { assert(!isa(this)); -NonParmVarDeclBits.NRVOVariable = NRVO; +NonParmVarDeclBits.NRVOMode = NRVO ? NRVO_Enabled : NRVO_Disabled; } /// Determine whether this variable is the for-range-declaration in Modified: cfe/trunk/include/clang/Sema/Scope.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=335019&r1=335018&r2=335019&view=diff == --- cfe/trunk/include/clang/Sema/Scope.h (original) +++ cfe/trunk/include/clang/Sema/Scope.h Mon Jun 18 21:39:07 2018 @@ -201,10 +201,6 @@ private: /// Used to determine if errors occurred in this scope. DiagnosticErrorTrap ErrorTrap; - /// A lattice consisting of undefined, a single NRVO candidate variable in - /// this scope, or over-defined. The bit is true when over-defined. - llvm::PointerIntPair NRVO; - void setFlags(Scope *Parent, unsigned F); public: @@ -466,23 +462,7 @@ public: UsingDirectives.end()); } - void addNRVOCandidate(VarDecl *VD) { -if (NRVO.getInt()) - return; -if (NRVO.getPointer() == nullptr) { - NRVO.setPointer(VD); - return; -} -if (NRVO.getPointer() != VD) - setNoNRVO(); - } - - void setNoNRVO() { -NRVO.setInt(true); -NRVO.setPointer(nullptr); - } - - void mergeNRVOIntoParent(); + void setNRVOCandidate(VarDecl *Candidate); /// Init - This is used by the parser to implement scope caching. void Init(Scope *parent, unsigned flags); Modified: cfe/trunk/lib/Sema/Scope.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Scope.cpp?rev=335019&r1=335018&r2=335019&view=diff == --- cfe/trunk/lib/Sema/Scope.cpp (original) +++ cfe/trunk/lib/Sema/Scope.cpp Mon Jun 18 21:39:07 2018 @@ -92,7 +92,6 @@ void Scope::Init(Scope *parent, unsigned UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); - NRVO.setPointerAndInt(nullptr, 0); } bool Scope
r335022 - Revert r335019 "Update NRVO logic to support early return (Attempt 2)"
Author: tzik Date: Mon Jun 18 22:35:30 2018 New Revision: 335022 URL: http://llvm.org/viewvc/llvm-project?rev=335022&view=rev Log: Revert r335019 "Update NRVO logic to support early return (Attempt 2)" Removed: cfe/trunk/test/CodeGenCXX/nrvo-noopt.cpp cfe/trunk/test/SemaCXX/nrvo-ast.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/Sema/Scope.h cfe/trunk/lib/Sema/Scope.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/CodeGenCXX/nrvo.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=335022&r1=335021&r2=335022&view=diff == --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Jun 18 22:35:30 2018 @@ -879,12 +879,6 @@ protected: DAK_Normal }; - enum NRVOMode { -NRVO_Candidate, -NRVO_Disabled, -NRVO_Enabled, - }; - class ParmVarDeclBitfields { friend class ASTDeclReader; friend class ParmVarDecl; @@ -937,7 +931,7 @@ protected: /// Whether this local variable could be allocated in the return /// slot of its function, enabling the named return value optimization /// (NRVO). -unsigned NRVOMode : 2; +unsigned NRVOVariable : 1; /// Whether this variable is the for-range-declaration in a C++0x /// for-range statement. @@ -1325,20 +1319,12 @@ public: /// return slot when returning from the function. Within the function body, /// each return that returns the NRVO object will have this variable as its /// NRVO candidate. - NRVOMode getNRVOMode() const { -if (isa(this)) - return NRVO_Disabled; -return static_cast(NonParmVarDeclBits.NRVOMode); - } - bool isNRVOCandidate() const { -return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Candidate; - } bool isNRVOVariable() const { -return isa(this) ? false : NonParmVarDeclBits.NRVOMode == NRVO_Enabled; +return isa(this) ? false : NonParmVarDeclBits.NRVOVariable; } void setNRVOVariable(bool NRVO) { assert(!isa(this)); -NonParmVarDeclBits.NRVOMode = NRVO ? NRVO_Enabled : NRVO_Disabled; +NonParmVarDeclBits.NRVOVariable = NRVO; } /// Determine whether this variable is the for-range-declaration in Modified: cfe/trunk/include/clang/Sema/Scope.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Scope.h?rev=335022&r1=335021&r2=335022&view=diff == --- cfe/trunk/include/clang/Sema/Scope.h (original) +++ cfe/trunk/include/clang/Sema/Scope.h Mon Jun 18 22:35:30 2018 @@ -201,6 +201,10 @@ private: /// Used to determine if errors occurred in this scope. DiagnosticErrorTrap ErrorTrap; + /// A lattice consisting of undefined, a single NRVO candidate variable in + /// this scope, or over-defined. The bit is true when over-defined. + llvm::PointerIntPair NRVO; + void setFlags(Scope *Parent, unsigned F); public: @@ -462,7 +466,23 @@ public: UsingDirectives.end()); } - void setNRVOCandidate(VarDecl *Candidate); + void addNRVOCandidate(VarDecl *VD) { +if (NRVO.getInt()) + return; +if (NRVO.getPointer() == nullptr) { + NRVO.setPointer(VD); + return; +} +if (NRVO.getPointer() != VD) + setNoNRVO(); + } + + void setNoNRVO() { +NRVO.setInt(true); +NRVO.setPointer(nullptr); + } + + void mergeNRVOIntoParent(); /// Init - This is used by the parser to implement scope caching. void Init(Scope *parent, unsigned flags); Modified: cfe/trunk/lib/Sema/Scope.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Scope.cpp?rev=335022&r1=335021&r2=335022&view=diff == --- cfe/trunk/lib/Sema/Scope.cpp (original) +++ cfe/trunk/lib/Sema/Scope.cpp Mon Jun 18 22:35:30 2018 @@ -92,6 +92,7 @@ void Scope::Init(Scope *parent, unsigned UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); + NRVO.setPointerAndInt(nullptr, 0); } bool Scope::containedInPrototypeScope() const { @@ -118,15 +119,19 @@ void Scope::AddFlags(unsigned FlagsToSet Flags |= FlagsToSet; } -void Scope::setNRVOCandidate(VarDecl *Candidate) { - for (Decl *D : DeclsInScope) { -VarDecl *VD = dyn_cast(D); -if (VD && VD != Candidate && VD->isNRVOCandidate()) - VD->setNRVOVariable(false); +void Scope::mergeNRVOIntoParent() { + if (VarDecl *Candidate = NRVO.getPointer()) { +if (isDeclScope(Candidate)) + Candidate->setNRVOVariable(true); } - if (Scope *parent = getParent()) -parent->setNRVOC