[CodeGen] Emit lifetime.end intrinsic after objects are destructed in

landing pads.

Previously, lifetime.end intrinsics were inserted only on normal control
flows. This prevented StackColoring from merging stack slots for objects
that were destroyed on the exception handling control flow since it
couldn't tell their lifetime ranges were disjoint. This patch fixes
code-gen to emit the intrinsic on both control flows.

rdar://problem/22181976

Differential Revision: http://reviews.llvm.org/D18196

llvm-svn: 265197
This commit is contained in:
Akira Hatanaka 2016-04-01 22:58:55 +00:00
parent 58a15d5a23
commit 8af7bb28aa
5 changed files with 114 additions and 4 deletions

View File

@ -157,6 +157,20 @@ bool EHScopeStack::containsOnlyLifetimeMarkers(
return true;
}
bool EHScopeStack::requiresLandingPad() const {
for (stable_iterator si = getInnermostEHScope(); si != stable_end(); ) {
// Skip lifetime markers.
if (auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si)))
if (cleanup->isLifetimeMarker()) {
si = cleanup->getEnclosingEHScope();
continue;
}
return true;
}
return false;
}
EHScopeStack::stable_iterator
EHScopeStack::getInnermostActiveNormalCleanup() const {
for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end();

View File

@ -1388,7 +1388,7 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
// Make sure we call @llvm.lifetime.end. This needs to happen
// *last*, so the cleanup needs to be pushed *first*.
if (emission.useLifetimeMarkers()) {
EHStack.pushCleanup<CallLifetimeEnd>(NormalCleanup,
EHStack.pushCleanup<CallLifetimeEnd>(NormalAndEHCleanup,
emission.getAllocatedAddress(),
emission.getSizeForLifetimeMarkers());
EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());

View File

@ -341,9 +341,7 @@ public:
/// Determines whether the exception-scopes stack is empty.
bool empty() const { return StartOfData == EndOfBuffer; }
bool requiresLandingPad() const {
return InnermostEHScope != stable_end();
}
bool requiresLandingPad() const;
/// Determines whether there are any normal cleanups on the stack.
bool hasNormalCleanups() const {

View File

@ -4,6 +4,9 @@
// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t %s
// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t %s
// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t %s
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions -O1 -disable-llvm-optzns -std=c++11 > %t2
// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t2 %s
// REQUIRES: asserts
struct A {
int a;
@ -428,3 +431,64 @@ namespace test10 {
return true;
}
}
#if __cplusplus >= 201103L
namespace test11 {
// Check that lifetime.end is emitted in the landing pad.
// CHECK6-LABEL: define void @_ZN6test1115testLifetimeEndEi(
// CHECK6: entry:
// CHECK6: [[T1:%[a-z0-9]+]] = alloca %"struct.test11::S1"
// CHECK6: [[T2:%[a-z0-9]+]] = alloca %"struct.test11::S1"
// CHECK6: [[T3:%[a-z0-9]+]] = alloca %"struct.test11::S1"
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T1]])
// CHECK6: [[BC1:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T1]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC1]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T1]])
// CHECK6: [[BC2:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T1]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC2]])
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T2]])
// CHECK6: [[BC3:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T2]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC3]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T2]])
// CHECK6: [[BC4:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T2]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC4]])
// CHECK6: {{^}}invoke.cont
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T3]])
// CHECK6: [[BC5:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T3]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC5]])
// CHECK6: {{^}}lpad
// CHECK6: call void @_ZN6test112S1D1Ev(%"struct.test11::S1"* [[T3]])
// CHECK6: [[BC6:%[a-z0-9]+]] = bitcast %"struct.test11::S1"* [[T3]] to i8*
// CHECK6: call void @llvm.lifetime.end(i64 32, i8* [[BC6]])
struct S1 {
~S1();
int a[8];
};
void func1(S1 &) noexcept(false);
void testLifetimeEnd(int n) {
if (n < 10) {
S1 t1;
func1(t1);
} else if (n < 100) {
S1 t2;
func1(t2);
} else if (n < 1000) {
S1 t3;
func1(t3);
}
}
}
#endif

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
// RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-optzns %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-LIFETIME %s
struct A {
A();
@ -206,3 +207,36 @@ void f() {
// WIN32: cleanuppad
// WIN32: call x86_thiscallcc void @"\01??1D@noexcept_false_dtor@@QAE@XZ"(%"struct.noexcept_false_dtor::D"* %{{.*}})
// WIN32: cleanupret
namespace lifetime_marker {
struct C {
~C();
};
void g();
void f() {
C c;
g();
}
// WIN32-LIFETIME-LABEL: define void @"\01?f@lifetime_marker@@YAXXZ"()
// WIN32-LIFETIME: %[[c:.*]] = alloca %"struct.lifetime_marker::C"
// WIN32-LIFETIME: %[[bc0:.*]] = bitcast %"struct.lifetime_marker::C"* %c to i8*
// WIN32-LIFETIME: call void @llvm.lifetime.start(i64 1, i8* %[[bc0]])
// WIN32-LIFETIME: invoke void @"\01?g@lifetime_marker@@YAXXZ"()
// WIN32-LIFETIME-NEXT: to label %[[cont:[^ ]*]] unwind label %[[lpad0:[^ ]*]]
//
// WIN32-LIFETIME: [[cont]]:
// WIN32-LIFETIME: call x86_thiscallcc void @"\01??1C@lifetime_marker@@QAE@XZ"({{.*}})
// WIN32-LIFETIME: %[[bc1:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
// WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc1]])
//
// WIN32-LIFETIME: [[lpad0]]:
// WIN32-LIFETIME-NEXT: cleanuppad
// WIN32-LIFETIME: call x86_thiscallcc void @"\01??1C@lifetime_marker@@QAE@XZ"({{.*}})
// WIN32-LIFETIME: cleanupret {{.*}} unwind label %[[lpad1:[^ ]*]]
//
// WIN32-LIFETIME: [[lpad1]]:
// WIN32-LIFETIME-NEXT: cleanuppad
// WIN32-LIFETIME: %[[bc2:.*]] = bitcast %"struct.lifetime_marker::C"* %[[c]] to i8*
// WIN32-LIFETIME: call void @llvm.lifetime.end(i64 1, i8* %[[bc2]])
}