r333500 - Update NRVO logic to support early return

2018-05-29 Thread Taiju Tsuiki via cfe-commits
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)

2018-06-18 Thread Taiju Tsuiki via cfe-commits
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)"

2018-06-18 Thread Taiju Tsuiki via cfe-commits
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