[cfe-commits] r103941 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGStmt.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/nrvo.cpp
Douglas Gregor
dgregor at apple.com
Mon May 17 08:52:46 PDT 2010
Author: dgregor
Date: Mon May 17 10:52:46 2010
New Revision: 103941
URL: http://llvm.org/viewvc/llvm-project?rev=103941&view=rev
Log:
Ensure that destructors are called for NRVO'd objects when the
function does not return. Thanks to Eli for pointing out this corner
case.
Modified:
cfe/trunk/lib/CodeGen/CGDecl.cpp
cfe/trunk/lib/CodeGen/CGStmt.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/nrvo.cpp
Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon May 17 10:52:46 2010
@@ -399,6 +399,7 @@
bool IsSimpleConstantInitializer = false;
bool NRVO = false;
+ llvm::Value *NRVOFlag = 0;
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
if (!Target.useGlobalsForAutomaticVariables()) {
@@ -430,6 +431,21 @@
// return slot, so that we can elide the copy when returning this
// variable (C++0x [class.copy]p34).
DeclPtr = ReturnValue;
+
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
+ // Create a flag that is used to indicate when the NRVO was applied
+ // to this variable. Set it to zero to indicate that NRVO was not
+ // applied.
+ const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+ llvm::Value *Zero = llvm::ConstantInt::get(BoolTy, 0);
+ NRVOFlag = CreateTempAlloca(BoolTy, "nrvo");
+ Builder.CreateStore(Zero, NRVOFlag);
+
+ // Record the NRVO flag for this variable.
+ NRVOFlags[&D] = NRVOFlag;
+ }
+ }
} else {
if (isByRef)
LTy = BuildByRefType(&D);
@@ -660,7 +676,8 @@
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!ClassDecl->hasTrivialDestructor()) {
- // Note: We suppress the destructor call when this is an NRVO variable.
+ // Note: We suppress the destructor call when the corresponding NRVO
+ // flag has been set.
llvm::Value *Loc = DeclPtr;
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
@@ -693,10 +710,21 @@
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
- if (!NRVO) {
+ {
+ // Normal destruction.
+ DelayedCleanupBlock Scope(*this);
+
+ if (NRVO) {
+ // If we exited via NRVO, we skip the destructor call.
+ llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
+ Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
+ Scope.getCleanupExitBlock(),
+ NoNRVO);
+ EmitBlock(NoNRVO);
+ }
+
// We don't call the destructor along the normal edge if we're
// applying the NRVO.
- DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
Loc);
Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Mon May 17 10:52:46 2010
@@ -612,6 +612,14 @@
// 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.
+
+ // If there is an NRVO flag for this variable, set it to 1 into indicate
+ // that the cleanup code should not destroy the variable.
+ if (llvm::Value *NRVOFlag = NRVOFlags[S.getNRVOCandidate()]) {
+ const llvm::Type *BoolTy = llvm::Type::getInt1Ty(VMContext);
+ llvm::Value *One = llvm::ConstantInt::get(BoolTy, 1);
+ Builder.CreateStore(One, NRVOFlag);
+ }
} else if (!ReturnValue) {
// Make sure not to return anything, but evaluate the expression
// for side effects.
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon May 17 10:52:46 2010
@@ -107,6 +107,11 @@
bool Exceptions;
bool CatchUndefined;
+
+ /// \brief A mapping from NRVO variables to the flags used to indicate
+ /// when the NRVO has been applied to this variable.
+ llvm::DenseMap<const VarDecl *, llvm::Value *> NRVOFlags;
+
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
Modified: cfe/trunk/test/CodeGenCXX/nrvo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/nrvo.cpp?rev=103941&r1=103940&r2=103941&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/nrvo.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/nrvo.cpp Mon May 17 10:52:46 2010
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
// Test code generation for the named return value optimization.
@@ -15,9 +15,12 @@
X x;
// CHECK-NOT: call void @_ZN1XD1Ev
// CHECK: ret void
+ // CHECK-EH: br label
+ // CHECK-EH: call void @_ZN1XD1Ev
+ // CHECK-EH: br label
+ // CHECK-EH: invoke void @_ZN1XD1Ev
// CHECK-EH: ret void
return x;
- // CHECK-EH: invoke void @_ZN1XD1Ev
}
// CHECK: define void @_Z5test1b(
@@ -63,3 +66,19 @@
X x;
return x;
}
+
+extern "C" void exit(int) throw();
+
+// CHECK: define void @_Z5test4b
+X test4(bool B) {
+ {
+ // CHECK: tail call void @_ZN1XC1Ev
+ X x;
+ // CHECK: br i1
+ if (B)
+ return x;
+ }
+ // CHECK: tail call void @_ZN1XD1Ev
+ // CHECK: tail call void @exit(i32 1)
+ exit(1);
+}
More information about the cfe-commits
mailing list