[IRGen] Emit lifetime intrinsics around temporary aggregate argument allocas
These temporaries are only used in the callee, and their memory can be reused
after the call is complete.
rdar://58552124
Differential revision: https://reviews.llvm.org/D74094
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index b55d585..3edcfb2 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3689,7 +3689,22 @@
return;
}
- args.add(EmitAnyExprToTemp(E), type);
+ AggValueSlot ArgSlot = AggValueSlot::ignored();
+ if (hasAggregateEvaluationKind(E->getType())) {
+ ArgSlot = CreateAggTemp(E->getType(), "agg.tmp");
+
+ // Emit a lifetime start/end for this temporary. If the type has a
+ // destructor, then we need to keep it alive. FIXME: We should still be able
+ // to end the lifetime after the destructor returns.
+ if (!E->getType().isDestructedType()) {
+ uint64_t size =
+ CGM.getDataLayout().getTypeAllocSize(ConvertTypeForMem(E->getType()));
+ if (auto *lifetimeSize = EmitLifetimeStart(size, ArgSlot.getPointer()))
+ args.addLifetimeCleanup({ArgSlot.getPointer(), lifetimeSize});
+ }
+ }
+
+ args.add(EmitAnyExpr(E, ArgSlot), type);
}
QualType CodeGenFunction::getVarArgType(const Expr *Arg) {
@@ -4769,6 +4784,9 @@
for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall)
LifetimeEnd.Emit(*this, /*Flags=*/{});
+ for (auto < : CallArgs.getLifetimeCleanups())
+ EmitLifetimeEnd(LT.Size, LT.Addr);
+
return Ret;
}