diff options
Diffstat (limited to 'clang/test/CodeGenCXX')
-rw-r--r-- | clang/test/CodeGenCXX/condition.cpp | 122 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/destructors.cpp | 58 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/eh.cpp | 89 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/nrvo.cpp | 87 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp | 11 |
5 files changed, 313 insertions, 54 deletions
diff --git a/clang/test/CodeGenCXX/condition.cpp b/clang/test/CodeGenCXX/condition.cpp index f5b43d2ef49..b1fa9f1c80a 100644 --- a/clang/test/CodeGenCXX/condition.cpp +++ b/clang/test/CodeGenCXX/condition.cpp @@ -96,66 +96,132 @@ void switch_destruct(int z) { int foo(); +// CHECK: define void @_Z14while_destructi void while_destruct(int z) { - // CHECK: define void @_Z14while_destructi - // CHECK: {{while.cond:|:3}} + // CHECK: [[Z:%.*]] = alloca i32 + // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 while (X x = X()) { // CHECK: call void @_ZN1XC1Ev + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: br i1 [[COND]] - // CHECK: {{while.body:|:5}} - // CHECK: store i32 21 + // Loop-exit staging block. + // CHECK: store i32 1, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br + + // While body. + // CHECK: store i32 21, i32* [[Z]] + // CHECK: store i32 2, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br z = 21; - // CHECK: {{while.cleanup:|:6}} + // Cleanup. // CHECK: call void @_ZN1XD1Ev + // CHECK-NEXT: [[DEST:%.*]] = load i32* [[CLEANUPDEST]] + // CHECK-NEXT: switch i32 [[DEST]] } - // CHECK: {{while.end|:8}} - // CHECK: store i32 22 + + // CHECK: store i32 22, i32* [[Z]] z = 22; // CHECK: call void @_Z4getXv - // CHECK: call zeroext i1 @_ZN1XcvbEv - // CHECK: call void @_ZN1XD1Ev - // CHECK: br + // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br while(getX()) { } - // CHECK: store i32 25 + // CHECK: store i32 25, i32* [[Z]] z = 25; // CHECK: ret } +// CHECK: define void @_Z12for_destructi( void for_destruct(int z) { - // CHECK: define void @_Z12for_destruct + // CHECK: [[Z:%.*]] = alloca i32 + // CHECK: [[XDEST:%.*]] = alloca i32 + // CHECK: [[I:%.*]] = alloca i32 // CHECK: call void @_ZN1YC1Ev - for(Y y = Y(); X x = X(); ++z) - // CHECK: {{for.cond:|:4}} + // CHECK-NEXT: br + // -> %for.cond + + for(Y y = Y(); X x = X(); ++z) { + // %for.cond: The loop condition. // CHECK: call void @_ZN1XC1Ev - // CHECK: {{for.body:|:6}} - // CHECK: store i32 23 + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv( + // CHECK-NEXT: br i1 [[COND]] + // -> %for.body, %for.cond.cleanup + + // %for.cond.cleanup: Exit cleanup staging. + // CHECK: store i32 1, i32* [[XDEST]] + // CHECK-NEXT: br + // -> %cleanup + + // %for.body: + // CHECK: store i32 23, i32* [[Z]] + // CHECK-NEXT: br + // -> %for.inc z = 23; - // CHECK: {{for.inc:|:7}} - // CHECK: br label %{{for.cond.cleanup|10}} - // CHECK: {{for.cond.cleanup:|:10}} + + // %for.inc: + // CHECK: [[TMP:%.*]] = load i32* [[Z]] + // CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1 + // CHECK-NEXT: store i32 [[INC]], i32* [[Z]] + // CHECK-NEXT: store i32 2, i32* [[XDEST]] + // CHECK-NEXT: br + // -> %cleanup + + // %cleanup: Destroys X. // CHECK: call void @_ZN1XD1Ev - // CHECK: {{for.end:|:12}} - // CHECK: call void @_ZN1YD1Ev + // CHECK-NEXT: [[YDESTTMP:%.*]] = load i32* [[XDEST]] + // CHECK-NEXT: switch i32 [[YDESTTMP]] + // 1 -> %cleanup4, 2 -> %cleanup.cont + + // %cleanup.cont: (eliminable) + // CHECK: br + // -> %for.cond + + // %cleanup4: Destroys Y. + // CHECK: call void @_ZN1YD1Ev( + // CHECK-NEXT: br + // -> %for.end + } + + // %for.end: // CHECK: store i32 24 z = 24; + // CHECK-NEXT: store i32 0, i32* [[I]] + // CHECK-NEXT: br + // -> %for.cond6 + + // %for.cond6: // CHECK: call void @_Z4getXv - // CHECK: call zeroext i1 @_ZN1XcvbEv - // CHECK: call void @_ZN1XD1Ev + // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br + // -> %for.body10, %for.end16 + + // %for.body10: // CHECK: br + // -> %for.inc11 + + // %for.inc11: // CHECK: call void @_Z4getXv - // CHECK: load - // CHECK: add - // CHECK: call void @_ZN1XD1Ev + // CHECK-NEXT: load i32* [[I]] + // CHECK-NEXT: add + // CHECK-NEXT: store + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br + // -> %for.cond6 int i = 0; for(; getX(); getX(), ++i) { } - z = 26; + + // %for.end16 // CHECK: store i32 26 - // CHECK: ret + z = 26; + + // CHECK-NEXT: ret void } void do_destruct(int z) { diff --git a/clang/test/CodeGenCXX/destructors.cpp b/clang/test/CodeGenCXX/destructors.cpp index ef3d4b9cb1a..ee8f1a5f543 100644 --- a/clang/test/CodeGenCXX/destructors.cpp +++ b/clang/test/CodeGenCXX/destructors.cpp @@ -187,15 +187,63 @@ namespace test3 { // Checked at top of file: // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + // More checks at end of file. + +} + +namespace test4 { + struct A { ~A(); }; + + // CHECK: define void @_ZN5test43fooEv() + // CHECK: call void @_ZN5test41AD1Ev + // CHECK: ret void + void foo() { + { + A a; + goto failure; + } + + failure: + return; + } + + // CHECK: define void @_ZN5test43barEi( + // CHECK: [[X:%.*]] = alloca i32 + // CHECK-NEXT: [[A:%.*]] = alloca + // CHECK: br label + // CHECK: [[TMP:%.*]] = load i32* [[X]] + // CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0 + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN5test41AD1Ev( + // CHECK: br label + // CHECK: [[TMP:%.*]] = load i32* [[X]] + // CHECK: [[TMP2:%.*]] = add nsw i32 [[TMP]], -1 + // CHECK: store i32 [[TMP2]], i32* [[X]] + // CHECK: br label + // CHECK: ret void + void bar(int x) { + for (A a; x; ) { + x--; + } + } +} + +// Checks from test3: + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev( // CHECK: call void @_ZN5test31BD2Ev( // CHECK: call void @_ZN5test31AD2Ev( // CHECK: ret void // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev( - // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev( // CHECK: call void @_ZdlPv( // CHECK: ret void + // CHECK: call i8* @llvm.eh.exception( + // CHECK: invoke void @_ZdlPv + // CHECK: call void @_Unwind_Resume_or_Rethrow + // CHECK: call i8* @llvm.eh.exception( + // CHECK: call void @_ZSt9terminatev( // Checked at top of file: // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev @@ -215,9 +263,14 @@ namespace test3 { // CHECK: declare void @_ZN5test31AD2Ev( // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev( - // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev( // CHECK: call void @_ZdlPv( // CHECK: ret void + // CHECK: call i8* @llvm.eh.exception() + // CHECK: invoke void @_ZdlPv( + // CHECK: call void @_Unwind_Resume_or_Rethrow( + // CHECK: call i8* @llvm.eh.exception() + // CHECK: call void @_ZSt9terminatev() // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 @@ -228,4 +281,3 @@ namespace test3 { // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev( // CHECK: ret void -} diff --git a/clang/test/CodeGenCXX/eh.cpp b/clang/test/CodeGenCXX/eh.cpp index f2629d19d90..4d0955877d2 100644 --- a/clang/test/CodeGenCXX/eh.cpp +++ b/clang/test/CodeGenCXX/eh.cpp @@ -38,6 +38,7 @@ void test2() { // CHECK: define void @_Z5test2v() // CHECK: [[FREEVAR:%.*]] = alloca i1 // CHECK-NEXT: [[EXNOBJVAR:%.*]] = alloca i8* +// CHECK-NEXT: [[EXNSLOTVAR:%.*]] = alloca i8* // CHECK-NEXT: store i1 false, i1* [[FREEVAR]] // CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16) // CHECK-NEXT: store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]] @@ -104,3 +105,91 @@ namespace test5 { // : [[HANDLER]]: (can't check this in Release-Asserts builds) // CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*)) } + +namespace test6 { + template <class T> struct allocator { + ~allocator() throw() { } + }; + + void foo() { + allocator<int> a; + } +} + +// PR7127 +namespace test7 { +// CHECK: define i32 @_ZN5test73fooEv() + int foo() { +// CHECK: [[FREEEXNOBJ:%.*]] = alloca i1 +// CHECK-NEXT: [[EXNALLOCVAR:%.*]] = alloca i8* +// CHECK-NEXT: [[CAUGHTEXNVAR:%.*]] = alloca i8* +// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32 +// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]] + try { + try { +// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception +// CHECK-NEXT: store i8* [[EXNALLOC]], i8** [[EXNALLOCVAR]] +// CHECK-NEXT: store i1 true, i1* [[FREEEXNOBJ]] +// CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32* +// CHECK-NEXT: store i32 1, i32* +// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]] +// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null + throw 1; + } +// This cleanup ends up here for no good reason. It's actually unused. +// CHECK: load i8** [[EXNALLOCVAR]] +// CHECK-NEXT: call void @__cxa_free_exception( + +// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception() +// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null) +// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) +// CHECK-NEXT: icmp eq +// CHECK-NEXT: br i1 +// CHECK: load i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: call i8* @__cxa_begin_catch +// CHECK: invoke void @__cxa_rethrow + catch (int) { + throw; + } + } +// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception() +// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null) +// CHECK-NEXT: call void @__cxa_end_catch() +// CHECK-NEXT: br label +// CHECK: load i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: call i8* @__cxa_begin_catch +// CHECK-NEXT: call void @__cxa_end_catch + catch (...) { + } +// CHECK: ret i32 0 + return 0; + } +} + +// Ordering of destructors in a catch handler. +namespace test8 { + struct A { A(const A&); ~A(); }; + void bar(); + + // CHECK: define void @_ZN5test83fooEv() + void foo() { + try { + // CHECK: invoke void @_ZN5test83barEv() + bar(); + } catch (A a) { + // CHECK: call i8* @__cxa_get_exception_ptr + // CHECK-NEXT: bitcast + // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_( + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: invoke void @_ZN5test81AD1Ev( + + // CHECK: call void @__cxa_end_catch() + // CHECK-NEXT: load + // CHECK-NEXT: switch + + // CHECK: ret void + } + } +} diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp index 9ee553673f1..6181f0eee13 100644 --- a/clang/test/CodeGenCXX/nrvo.cpp +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s -// RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s +// RUN: %clang_cc1 -emit-llvm -O1 -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s // Test code generation for the named return value optimization. class X { @@ -13,48 +13,97 @@ public: // CHECK-EH: define void @_Z5test0v X test0() { X x; - // CHECK-NOT: call void @_ZN1XD1Ev - // CHECK: ret void - // CHECK-EH: br label - // CHECK-EH: call void @_ZN1XD1Ev - // CHECK-EH: br label - // CHECK-EH: invoke void @_ZN1XD1Ev - // CHECK-EH: ret void + // CHECK: call void @_ZN1XC1Ev + // CHECK-NEXT: ret void + + // CHECK-EH: call void @_ZN1XC1Ev + // CHECK-EH-NEXT: ret void return x; } // CHECK: define void @_Z5test1b( +// CHECK-EH: define void @_Z5test1b( X test1(bool B) { - // CHECK: call void @_ZN1XC1Ev + // CHECK: tail call void @_ZN1XC1Ev + // CHECK-NEXT: ret void X x; - // CHECK-NOT: call void @_ZN1XD1Ev - // CHECK: ret void if (B) return (x); return x; - // CHECK-EH: invoke void @_ZN1XD1Ev + // CHECK-EH: tail call void @_ZN1XC1Ev + // CHECK-EH-NEXT: ret void } // CHECK: define void @_Z5test2b // CHECK-EH: define void @_Z5test2b X test2(bool B) { - // No NRVO - // CHECK: call void @_ZN1XC1Ev + // No NRVO. + X x; - // CHECK: call void @_ZN1XC1Ev X y; - // CHECK: call void @_ZN1XC1ERKS_ - // CHECK-EH: invoke void @_ZN1XC1ERKS_ if (B) return y; - // CHECK: call void @_ZN1XC1ERKS_ - // CHECK-EH: invoke void @_ZN1XC1ERKS_ return x; + + // CHECK: call void @_ZN1XC1Ev + // CHECK-NEXT: call void @_ZN1XC1Ev + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call void @_ZN1XC1ERKS_ // CHECK: call void @_ZN1XD1Ev // CHECK: call void @_ZN1XD1Ev // CHECK: ret void + + // The block ordering in the -fexceptions IR is unfortunate. + + // CHECK-EH: call void @_ZN1XC1Ev + // CHECK-EH-NEXT: invoke void @_ZN1XC1Ev + // -> %invoke.cont1, %lpad + + // %invoke.cont1: + // CHECK-EH: br i1 + // -> %if.then, %if.end + + // %if.then: returning 'x' + // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // -> %cleanup, %lpad5 + + // %invoke.cont: rethrow block for %eh.cleanup. + // This really should be elsewhere in the function. + // CHECK-EH: call void @_Unwind_Resume_or_Rethrow + // CHECK-EH-NEXT: unreachable + + // %lpad: landing pad for ctor of 'y', dtor of 'y' + // CHECK-EH: call i8* @llvm.eh.exception() + // CHECK-EH: call i32 (i8*, i8*, ...)* @llvm.eh.selector + // CHECK-EH-NEXT: br label + // -> %eh.cleanup + + // %invoke.cont2: normal cleanup for 'x' + // CHECK-EH: call void @_ZN1XD1Ev + // CHECK-EH-NEXT: ret void + + // %lpad5: landing pad for return copy ctors, EH cleanup for 'y' + // CHECK-EH: invoke void @_ZN1XD1Ev + // -> %eh.cleanup, %terminate.lpad + + // %if.end: returning 'y' + // CHECK-EH: invoke void @_ZN1XC1ERKS_ + // -> %cleanup, %lpad5 + + // %cleanup: normal cleanup for 'y' // CHECK-EH: invoke void @_ZN1XD1Ev + // -> %invoke.cont2, %lpad + + // %eh.cleanup: EH cleanup for 'x' // CHECK-EH: invoke void @_ZN1XD1Ev + // -> %invoke.cont, %terminate.lpad + + // %terminate.lpad: terminate landing pad. + // CHECK-EH: call i8* @llvm.eh.exception() + // CHECK-EH-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector + // CHECK-EH-NEXT: call void @_ZSt9terminatev() + // CHECK-EH-NEXT: unreachable + } X test3(bool B) { diff --git a/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp index 9347cc9616a..17c10301d4f 100644 --- a/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp +++ b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp @@ -12,15 +12,18 @@ void f() { // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x) // CHECK: invoke void @_ZN1XC1Ev // CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x) - // CHECK: call i32 @__cxa_atexit + // CHECK-NEXT: call i32 @__cxa_atexit // CHECK: br static X x; + + // CHECK: call i8* @__cxa_allocate_exception + // CHECK: invoke void @__cxa_throw + throw Y(); + + // Finally, the landing pad. // CHECK: call i8* @llvm.eh.exception() // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x) // CHECK: call void @_Unwind_Resume_or_Rethrow // CHECK: unreachable - - // CHECK: call i8* @__cxa_allocate_exception - throw Y(); } |