summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGExprAgg.cpp
diff options
context:
space:
mode:
authorGeorge Burgess IV <george.burgess.iv@gmail.com>2018-03-10 23:06:31 +0000
committerGeorge Burgess IV <george.burgess.iv@gmail.com>2018-03-10 23:06:31 +0000
commit4deb75d2e8578f75bfbce8328323620222377335 (patch)
tree7ff8fed2259905a4d63c8637c4c417ab6f84f93a /clang/lib/CodeGen/CGExprAgg.cpp
parent4fb6f8189f5283d450c2fbab35a3878961f84965 (diff)
downloadbcm5719-llvm-4deb75d2e8578f75bfbce8328323620222377335.tar.gz
bcm5719-llvm-4deb75d2e8578f75bfbce8328323620222377335.zip
[CodeGen] Eagerly emit lifetime.end markers for calls
In C, we'll wait until the end of the scope to clean up aggregate temporaries used for returns from calls. This means in cases like: { // Assuming that `Bar` is large enough to warrant indirect returns struct Bar b = {}; b = foo(&b); b = foo(&b); b = foo(&b); b = foo(&b); } ...We'll allocate space for 5 Bars on the stack (`b`, and 4 temporaries). This becomes painful in things like large switch statements. If cleaning up sooner is trivial, we should do it. llvm-svn: 327229
Diffstat (limited to 'clang/lib/CodeGen/CGExprAgg.cpp')
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp34
1 files changed, 28 insertions, 6 deletions
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 5613f8d9700..371c14cde01 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -23,6 +23,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/IntrinsicInst.h"
using namespace clang;
using namespace CodeGen;
@@ -48,7 +49,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
// Calls `Fn` with a valid return value slot, potentially creating a temporary
// to do so. If a temporary is created, an appropriate copy into `Dest` will
- // be emitted.
+ // be emitted, as will lifetime markers.
//
// The given function should take a ReturnValueSlot, and return an RValue that
// points to said slot.
@@ -250,16 +251,28 @@ void AggExprEmitter::withReturnValueSlot(
(RequiresDestruction && !Dest.getAddress().isValid());
Address RetAddr = Address::invalid();
+
+ EHScopeStack::stable_iterator LifetimeEndBlock;
+ llvm::Value *LifetimeSizePtr = nullptr;
+ llvm::IntrinsicInst *LifetimeStartInst = nullptr;
if (!UseTemp) {
RetAddr = Dest.getAddress();
} else {
RetAddr = CGF.CreateMemTemp(RetTy);
uint64_t Size =
CGF.CGM.getDataLayout().getTypeAllocSize(CGF.ConvertTypeForMem(RetTy));
- if (llvm::Value *LifetimeSizePtr =
- CGF.EmitLifetimeStart(Size, RetAddr.getPointer()))
+ LifetimeSizePtr = CGF.EmitLifetimeStart(Size, RetAddr.getPointer());
+ if (LifetimeSizePtr) {
+ LifetimeStartInst =
+ cast<llvm::IntrinsicInst>(std::prev(Builder.GetInsertPoint()));
+ assert(LifetimeStartInst->getIntrinsicID() ==
+ llvm::Intrinsic::lifetime_start &&
+ "Last insertion wasn't a lifetime.start?");
+
CGF.pushFullExprCleanup<CodeGenFunction::CallLifetimeEnd>(
NormalEHLifetimeMarker, RetAddr, LifetimeSizePtr);
+ LifetimeEndBlock = CGF.EHStack.stable_begin();
+ }
}
RValue Src =
@@ -268,9 +281,18 @@ void AggExprEmitter::withReturnValueSlot(
if (RequiresDestruction)
CGF.pushDestroy(RetTy.isDestructedType(), Src.getAggregateAddress(), RetTy);
- if (UseTemp) {
- assert(Dest.getPointer() != Src.getAggregatePointer());
- EmitFinalDestCopy(E->getType(), Src);
+ if (!UseTemp)
+ return;
+
+ assert(Dest.getPointer() != Src.getAggregatePointer());
+ EmitFinalDestCopy(E->getType(), Src);
+
+ if (!RequiresDestruction && LifetimeStartInst) {
+ // If there's no dtor to run, the copy was the last use of our temporary.
+ // Since we're not guaranteed to be in an ExprWithCleanups, clean up
+ // eagerly.
+ CGF.DeactivateCleanupBlock(LifetimeEndBlock, LifetimeStartInst);
+ CGF.EmitLifetimeEnd(LifetimeSizePtr, RetAddr.getPointer());
}
}
OpenPOWER on IntegriCloud