diff options
author | Tim Shen <timshen91@gmail.com> | 2016-07-01 21:08:47 +0000 |
---|---|---|
committer | Tim Shen <timshen91@gmail.com> | 2016-07-01 21:08:47 +0000 |
commit | 421119fd891cc68d76f28bd0d9afa78e222e3a04 (patch) | |
tree | 302448290d3e873dde526799aa6ea76c20f0e689 /clang/test | |
parent | 1bba89612b1a03bf3f35455e2ae1e2fb3af7849a (diff) | |
download | bcm5719-llvm-421119fd891cc68d76f28bd0d9afa78e222e3a04.tar.gz bcm5719-llvm-421119fd891cc68d76f28bd0d9afa78e222e3a04.zip |
[Temporary, Lifetime] Add lifetime marks for temporaries
With all MaterializeTemporaryExprs coming with a ExprWithCleanups, it's
easy to add correct lifetime.end marks into the right RunCleanupsScope.
Differential Revision: http://reviews.llvm.org/D20499
llvm-svn: 274385
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CodeGen/temporary-lifetime-exceptions.cpp | 24 | ||||
-rw-r--r-- | clang/test/CodeGen/temporary-lifetime.cpp | 165 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp | 98 |
3 files changed, 257 insertions, 30 deletions
diff --git a/clang/test/CodeGen/temporary-lifetime-exceptions.cpp b/clang/test/CodeGen/temporary-lifetime-exceptions.cpp new file mode 100644 index 00000000000..17e21683f22 --- /dev/null +++ b/clang/test/CodeGen/temporary-lifetime-exceptions.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -fexceptions -fcxx-exceptions -std=c++11 -O1 -triple x86_64 -emit-llvm -o - | FileCheck %s + +// lifetime.end should be invoked even if the destructor doesn't run due to an +// exception thrown from previous ctor call. + +struct A { A(); ~A(); }; +A Baz(const A&); + +void Test1() { + // CHECK-LABEL: @_Z5Test1v( + // CHECK: getelementptr + // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[TMP:[^ ]+]]) + // CHECK-NEXT: getelementptr + // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[TMP1:[^ ]+]]) + + // Normal exit + // CHECK: call void @llvm.lifetime.end(i64 1, i8* [[TMP1]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[TMP]]) + + // Exception exit + // CHECK: call void @llvm.lifetime.end(i64 1, i8* [[TMP1]]) + // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[TMP]]) + Baz(Baz(A())); +} diff --git a/clang/test/CodeGen/temporary-lifetime.cpp b/clang/test/CodeGen/temporary-lifetime.cpp new file mode 100644 index 00000000000..e760cfc10a7 --- /dev/null +++ b/clang/test/CodeGen/temporary-lifetime.cpp @@ -0,0 +1,165 @@ +// RUN: %clang_cc1 %s -std=c++11 -O1 -DWITH_DTOR -triple x86_64 -emit-llvm -o - | FileCheck -check-prefix=CHECK-DTOR %s +// RUN: %clang_cc1 %s -std=c++11 -O1 -triple x86_64 -emit-llvm -o - | FileCheck -check-prefix=CHECK-NO-DTOR %s + +struct A { + A(); +#ifdef WITH_DTOR + ~A(); +#endif + char a[1024]; + operator bool() const; +}; + +template <typename T> +void Foo(T &&); + +template <typename T> +void Bar(T &&); + +template <typename T> +T Baz(); + +void Test1() { + // CHECK-DTOR-LABEL: Test1 + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-DTOR: } + + // CHECK-NO-DTOR-LABEL: Test1 + // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]]) + // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]]) + // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-NO-DTOR: } + { + const A &a = A{}; + Foo(a); + } + { + const A &a = A{}; + Foo(a); + } +} + +void Test2() { + // CHECK-DTOR-LABEL: Test2 + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR1:[0-9]+]]) + // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR2:[0-9]+]]) + // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR2]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR2]]) + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR1]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR1]]) + // CHECK-DTOR: } + + // CHECK-NO-DTOR-LABEL: Test2 + // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR1:[0-9]+]]) + // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]]) + // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR2:[0-9]+]]) + // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]]) + // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_ + // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR2]]) + // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR1]]) + // CHECK-NO-DTOR: } + const A &a = A{}; + Foo(a); + const A &b = A{}; + Foo(b); +} + +void Test3() { + // CHECK-DTOR-LABEL: Test3 + // CHECK-DTOR: entry: + // CHECK-DTOR: call void @llvm.lifetime.start + // CHECK-DTOR: call void @llvm.lifetime.start + // CHECK-DTOR: if.then: + // CHECK-DTOR: call void @llvm.lifetime.end + // CHECK-DTOR: cleanup{{.*}}: + // CHECK-DTOR: call void @llvm.lifetime.end + // CHECK-DTOR: cleanup{{.*}}: + // CHECK-DTOR: call void @llvm.lifetime.end + // CHECK-DTOR: } + const A &a = A{}; + if (const A &b = A(a)) { + Foo(b); + return; + } + Bar(a); +} + +void Test4() { + // CHECK-DTOR-LABEL: Test4 + // CHECK-DTOR: entry: + // CHECK-DTOR: call void @llvm.lifetime.start + // CHECK-DTOR: for.cond.cleanup: + // CHECK-DTOR: call void @llvm.lifetime.end + // CHECK-DTOR: for.body: + // CHECK-DTOR: } + for (const A &a = A{}; a;) { + Foo(a); + } +} + +int Test5() { + // CHECK-DTOR-LABEL: Test5 + // CHECK-DTOR: call void @llvm.lifetime.start + // CHECK-DTOR: call i32 @_Z3BazIiET_v() + // CHECK-DTOR: store + // CHECK-DTOR: call void @_Z3FooIRKiEvOT_ + // CHECK-DTOR: load + // CHECK-DTOR: call void @llvm.lifetime.end + // CHECK-DTOR: } + const int &a = Baz<int>(); + Foo(a); + return a; +} + +void Test6() { + // CHECK-DTOR-LABEL: Test6 + // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call i32 @_Z3BazIiET_v() + // CHECK-DTOR: store + // CHECK-DTOR: call void @_Z3FooIiEvOT_ + // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* %[[ADDR]]) + // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call i32 @_Z3BazIiET_v() + // CHECK-DTOR: store + // CHECK-DTOR: call void @_Z3FooIiEvOT_ + // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* %[[ADDR]]) + // CHECK-DTOR: } + Foo(Baz<int>()); + Foo(Baz<int>()); +} + +void Test7() { + // CHECK-DTOR-LABEL: Test7 + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]]) + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]]) + // CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]]) + // CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]]) + // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]]) + // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]]) + // CHECK-DTOR: } + Foo(Baz<A>()); + Foo(Baz<A>()); +} diff --git a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp index 298e70e7712..004dc45652e 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp @@ -1,5 +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 +// 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 -check-prefix WIN32-O0 %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-O3 -check-prefix WIN32-LIFETIME %s struct A { A(); @@ -95,40 +95,78 @@ int HasConditionalDeactivatedCleanups(bool cond) { return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow()); } -// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { -// WIN32: alloca i1 -// WIN32: %[[arg1_cond:.*]] = alloca i1 +// WIN32-O0-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { +// WIN32-O0: alloca i1 +// WIN32-O0: %[[arg1_cond:.*]] = alloca i1 // Start all four cleanups as deactivated. -// WIN32: store i1 false -// WIN32: store i1 false -// WIN32: store i1 false -// WIN32: store i1 false -// WIN32: br i1 +// WIN32-O0: store i1 false +// WIN32-O0: store i1 false +// WIN32-O0: store i1 false +// WIN32-O0: store i1 false +// WIN32-O0: br i1 // True condition. -// WIN32: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" -// WIN32: store i1 true -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" -// WIN32: store i1 true, i1* %[[arg1_cond]] -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" -// WIN32: store i1 true -// WIN32: invoke void @"\01?TakeRef@@YAXABUA@@@Z" -// WIN32: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" -// WIN32: store i1 true -// WIN32: store i1 false, i1* %[[arg1_cond]] -// WIN32: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// WIN32-O0: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O0: store i1 true +// WIN32-O0: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32-O0: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O0: store i1 true, i1* %[[arg1_cond]] +// WIN32-O0: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O0: store i1 true +// WIN32-O0: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32-O0: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O0: store i1 true +// WIN32-O0: store i1 false, i1* %[[arg1_cond]] +// WIN32-O0: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" // False condition. -// WIN32: invoke i32 @"\01?CouldThrow@@YAHXZ"() +// WIN32-O0: invoke i32 @"\01?CouldThrow@@YAHXZ"() // Two normal cleanups for TakeRef args. -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) -// WIN32-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" -// WIN32: ret i32 +// WIN32-O0: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-O0-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32-O0: ret i32 // // Somewhere in the landing pad soup, we conditionally destroy arg1. -// WIN32: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]] -// WIN32: br i1 %[[isactive]] -// WIN32: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) -// WIN32: } +// WIN32-O0: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]] +// WIN32-O0: br i1 %[[isactive]] +// WIN32-O0: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-O0: } + +// WIN32-O3-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N@Z"{{.*}} { +// WIN32-O3: alloca i1 +// WIN32-O3: alloca i1 +// WIN32-O3: %[[arg1_cond:.*]] = alloca i1 +// Start all four cleanups as deactivated. +// WIN32-O3: store i1 false +// WIN32-O3: store i1 false +// WIN32-O3: store i1 false +// WIN32-O3: store i1 false +// WIN32-O3: store i1 false +// WIN32-O3: store i1 false +// WIN32-O3: br i1 +// True condition. +// WIN32-O3: call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O3: store i1 true +// WIN32-O3: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32-O3: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O3: store i1 true, i1* %[[arg1_cond]] +// WIN32-O3: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O3: store i1 true +// WIN32-O3: invoke void @"\01?TakeRef@@YAXABUA@@@Z" +// WIN32-O3: invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ" +// WIN32-O3: store i1 true +// WIN32-O3: store i1 false, i1* %[[arg1_cond]] +// WIN32-O3: invoke i32 @"\01?TakesTwo@@YAHUA@@0@Z" +// False condition. +// WIN32-O3: invoke i32 @"\01?CouldThrow@@YAHXZ"() +// Two normal cleanups for TakeRef args. +// WIN32-O3: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-O3-NOT: invoke x86_thiscallcc void @"\01??1A@@QAE@XZ" +// WIN32-O3: ret i32 +// +// Somewhere in the landing pad soup, we conditionally destroy arg1. +// WIN32-O3: %[[isactive:.*]] = load i1, i1* %[[arg1_cond]] +// WIN32-O3: br i1 %[[isactive]] +// WIN32-O3: call x86_thiscallcc void @"\01??1A@@QAE@XZ"({{.*}}) +// WIN32-O3: } namespace crash_on_partial_destroy { struct A { |