[cfe-commits] r103867 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGStmt.cpp lib/Sema/SemaStmt.cpp test/CodeGenCXX/nrvo.cpp

Douglas Gregor dgregor at apple.com
Fri May 14 23:46:45 PDT 2010


Author: dgregor
Date: Sat May 15 01:46:45 2010
New Revision: 103867

URL: http://llvm.org/viewvc/llvm-project?rev=103867&view=rev
Log:
Implement a simple form of the C++ named return value optimization for
return statements. We perform NRVO only when all of the return
statements in the function return the same variable. Fixes some link
failures in Boost.Interprocess (which is relying on NRVO), and
probably improves performance for some C++ applications.

Added:
    cfe/trunk/test/CodeGenCXX/nrvo.cpp   (with props)
Modified:
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=103867&r1=103866&r2=103867&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sat May 15 01:46:45 2010
@@ -398,16 +398,19 @@
   CharUnits Align = CharUnits::Zero();
   bool IsSimpleConstantInitializer = false;
 
+  bool NRVO = false;
   llvm::Value *DeclPtr;
   if (Ty->isConstantSizeType()) {
     if (!Target.useGlobalsForAutomaticVariables()) {
-      
+      NRVO = getContext().getLangOptions().ElideConstructors && 
+             D.isNRVOVariable();
       // If this value is an array or struct, is POD, and if the initializer is
-      // a staticly determinable constant, try to optimize it.
+      // a staticly determinable constant, try to optimize it (unless the NRVO
+      // is already optimizing this).
       if (D.getInit() && !isByRef &&
           (Ty->isArrayType() || Ty->isRecordType()) &&
           Ty->isPODType() &&
-          D.getInit()->isConstantInitializer(getContext())) {
+          D.getInit()->isConstantInitializer(getContext()) && !NRVO) {
         // If this variable is marked 'const', emit the value as a global.
         if (CGM.getCodeGenOpts().MergeAllConstants &&
             Ty.isConstant(getContext())) {
@@ -418,19 +421,29 @@
         IsSimpleConstantInitializer = true;
       }
       
-      // A normal fixed sized variable becomes an alloca in the entry block.
+      // A normal fixed sized variable becomes an alloca in the entry block,
+      // unless it's an NRVO variable.
       const llvm::Type *LTy = ConvertTypeForMem(Ty);
-      if (isByRef)
-        LTy = BuildByRefType(&D);
-      llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
-      Alloc->setName(D.getNameAsString());
-
-      Align = getContext().getDeclAlign(&D);
-      if (isByRef)
-        Align = std::max(Align, 
-            CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
-      Alloc->setAlignment(Align.getQuantity());
-      DeclPtr = Alloc;
+      
+      if (NRVO) {
+        // The named return value optimization: allocate this variable in the
+        // return slot, so that we can elide the copy when returning this
+        // variable (C++0x [class.copy]p34).
+        DeclPtr = ReturnValue;
+      } else {
+        if (isByRef)
+          LTy = BuildByRefType(&D);
+        
+        llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+        Alloc->setName(D.getNameAsString());
+
+        Align = getContext().getDeclAlign(&D);
+        if (isByRef)
+          Align = std::max(Align, 
+              CharUnits::fromQuantity(Target.getPointerAlign(0) / 8));
+        Alloc->setAlignment(Align.getQuantity());
+        DeclPtr = Alloc;
+      }
     } else {
       // Targets that don't support recursion emit locals as globals.
       const char *Class =
@@ -645,13 +658,14 @@
   while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
     DtorTy = getContext().getBaseElementType(Array);
   if (const RecordType *RT = DtorTy->getAs<RecordType>())
-    if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
-      llvm::Value *Loc = DeclPtr;
-      if (isByRef)
-        Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), 
-                                      D.getNameAsString());
-      
-      if (!ClassDecl->hasTrivialDestructor()) {
+    if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {      
+      if (!ClassDecl->hasTrivialDestructor() && !NRVO) {
+        // Note: We suppress the destructor call when this is an NRVO variable.
+        llvm::Value *Loc = DeclPtr;
+        if (isByRef)
+          Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), 
+                                        D.getNameAsString());
+        
         const CXXDestructorDecl *D = ClassDecl->getDestructor(getContext());
         assert(D && "EmitLocalBlockVarDecl - destructor is nul");
         

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=103867&r1=103866&r2=103867&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Sat May 15 01:46:45 2010
@@ -607,7 +607,12 @@
 
   // FIXME: Clean this up by using an LValue for ReturnTemp,
   // EmitStoreThroughLValue, and EmitAnyExpr.
-  if (!ReturnValue) {
+  if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
+      !Target.useGlobalsForAutomaticVariables()) {
+    // Apply the named return value optimization for this return statement,
+    // which means doing nothing: the appropriate result has already been
+    // constructed into the NRVO variable.
+  } else if (!ReturnValue) {
     // Make sure not to return anything, but evaluate the expression
     // for side effects.
     if (RV)

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=103867&r1=103866&r2=103867&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Sat May 15 01:46:45 2010
@@ -1090,7 +1090,8 @@
     return 0;
   
   if (VD->getKind() == Decl::Var && VD->hasLocalStorage() && 
-      !VD->getType()->isReferenceType() && !VD->getType().isVolatileQualified())
+      !VD->getType()->isReferenceType() && !VD->hasAttr<BlocksAttr>() &&
+      !VD->getType().isVolatileQualified())
     return VD;
   
   return 0;

Added: cfe/trunk/test/CodeGenCXX/nrvo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/nrvo.cpp?rev=103867&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/nrvo.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/nrvo.cpp Sat May 15 01:46:45 2010
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// Test code generation for the named return value optimization.
+class X {
+public:
+  X();
+  X(const X&);
+  ~X();
+};
+
+// CHECK: define void @_Z5test0v
+X test0() {
+  X x;
+  // CHECK-NOT: call void @_ZN1XD1Ev
+  // CHECK: ret void
+  return x;
+}
+
+// CHECK: define void @_Z5test1b(
+X test1(bool B) {
+  // CHECK: call void @_ZN1XC1Ev
+  X x;
+  // CHECK-NOT: call void @_ZN1XD1Ev
+  // CHECK: ret void
+  if (B)
+    return (x);
+  return x;
+}
+
+// CHECK: define void @_Z5test2b
+X test2(bool B) {
+  // No NRVO
+  // CHECK: call void @_ZN1XC1Ev
+  X x;
+  // CHECK: call void @_ZN1XC1Ev
+  X y;
+  // CHECK: call void @_ZN1XC1ERKS_
+  if (B)
+    return y;
+  // CHECK: call void @_ZN1XC1ERKS_
+  return x;
+  // CHECK: call void @_ZN1XD1Ev
+  // CHECK: call void @_ZN1XD1Ev
+  // CHECK: ret void
+}
+
+X test3(bool B) {
+  // FIXME: We don't manage to apply NRVO here, although we could.
+  {
+    X y;
+    return y;
+  }
+  X x;
+  return x;
+}

Propchange: cfe/trunk/test/CodeGenCXX/nrvo.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeGenCXX/nrvo.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeGenCXX/nrvo.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list