diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 58 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 3 |
3 files changed, 44 insertions, 24 deletions
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 48198ff576..c93d9ba33d 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -398,16 +398,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { 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 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { 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 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) { 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"); diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 772f640ed0..f51a899e7f 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -607,7 +607,12 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // 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) diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index f8fe4fe21c..d904907e97 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1090,7 +1090,8 @@ static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, 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; |