1*67e74705SXin Li// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -O2 -o - %s | FileCheck %s 2*67e74705SXin Li// 3*67e74705SXin Li// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes 4*67e74705SXin Li 5*67e74705SXin Li// Just check that we don't emit any dead blocks. 6*67e74705SXin Li@interface NSArray @end 7*67e74705SXin Livoid f0() { 8*67e74705SXin Li @try { 9*67e74705SXin Li @try { 10*67e74705SXin Li @throw @"a"; 11*67e74705SXin Li } @catch(NSArray *e) { 12*67e74705SXin Li } 13*67e74705SXin Li } @catch (id e) { 14*67e74705SXin Li } 15*67e74705SXin Li} 16*67e74705SXin Li 17*67e74705SXin Li// CHECK-LABEL: define void @f1() 18*67e74705SXin Livoid f1() { 19*67e74705SXin Li extern void foo(void); 20*67e74705SXin Li 21*67e74705SXin Li while (1) { 22*67e74705SXin Li // CHECK: call void @objc_exception_try_enter 23*67e74705SXin Li // CHECK-NEXT: getelementptr 24*67e74705SXin Li // CHECK-NEXT: call i32 @_setjmp( 25*67e74705SXin Li // CHECK-NEXT: icmp 26*67e74705SXin Li // CHECK-NEXT: br i1 27*67e74705SXin Li @try { 28*67e74705SXin Li // CHECK: call void asm sideeffect "", "*m" 29*67e74705SXin Li // CHECK-NEXT: call void @foo() 30*67e74705SXin Li foo(); 31*67e74705SXin Li // CHECK: call void @objc_exception_try_exit 32*67e74705SXin Li 33*67e74705SXin Li // CHECK: call void asm sideeffect "", "=*m" 34*67e74705SXin Li } @finally { 35*67e74705SXin Li break; 36*67e74705SXin Li } 37*67e74705SXin Li } 38*67e74705SXin Li} 39*67e74705SXin Li 40*67e74705SXin Li// Test that modifications to local variables are respected under 41*67e74705SXin Li// optimization. rdar://problem/8160285 42*67e74705SXin Li 43*67e74705SXin Li// CHECK-LABEL: define i32 @f2() 44*67e74705SXin Liint f2() { 45*67e74705SXin Li extern void foo(void); 46*67e74705SXin Li 47*67e74705SXin Li // CHECK: [[X:%.*]] = alloca i32 48*67e74705SXin Li // CHECK: store i32 5, i32* [[X]] 49*67e74705SXin Li int x = 0; 50*67e74705SXin Li x += 5; 51*67e74705SXin Li 52*67e74705SXin Li // CHECK: [[SETJMP:%.*]] = call i32 @_setjmp 53*67e74705SXin Li // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0 54*67e74705SXin Li // CHECK-NEXT: br i1 [[CAUGHT]] 55*67e74705SXin Li @try { 56*67e74705SXin Li // CHECK: store i32 6, i32* [[X]] 57*67e74705SXin Li x++; 58*67e74705SXin Li // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* nonnull [[X]] 59*67e74705SXin Li // CHECK-NEXT: call void @foo() 60*67e74705SXin Li // CHECK-NEXT: call void @objc_exception_try_exit 61*67e74705SXin Li // CHECK-NEXT: [[T:%.*]] = load i32, i32* [[X]] 62*67e74705SXin Li foo(); 63*67e74705SXin Li } @catch (id) { 64*67e74705SXin Li // Landing pad. Note that we elide the re-enter. 65*67e74705SXin Li // CHECK: call void asm sideeffect "", "=*m,=*m"(i32* nonnull [[X]] 66*67e74705SXin Li // CHECK-NEXT: call i8* @objc_exception_extract 67*67e74705SXin Li // CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[X]] 68*67e74705SXin Li // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1 69*67e74705SXin Li 70*67e74705SXin Li // This store is dead. 71*67e74705SXin Li // CHECK-NEXT: store i32 [[T2]], i32* [[X]] 72*67e74705SXin Li x--; 73*67e74705SXin Li } 74*67e74705SXin Li 75*67e74705SXin Li return x; 76*67e74705SXin Li} 77*67e74705SXin Li 78*67e74705SXin Li// Test that the cleanup destination is saved when entering a finally 79*67e74705SXin Li// block. rdar://problem/8293901 80*67e74705SXin Li// CHECK-LABEL: define void @f3() 81*67e74705SXin Livoid f3() { 82*67e74705SXin Li extern void f3_helper(int, int*); 83*67e74705SXin Li 84*67e74705SXin Li // CHECK: [[X:%.*]] = alloca i32 85*67e74705SXin Li // CHECK: [[XPTR:%.*]] = bitcast i32* [[X]] to i8* 86*67e74705SXin Li // CHECK: call void @llvm.lifetime.start(i64 4, i8* [[XPTR]]) 87*67e74705SXin Li // CHECK: store i32 0, i32* [[X]] 88*67e74705SXin Li int x = 0; 89*67e74705SXin Li 90*67e74705SXin Li // CHECK: call void @objc_exception_try_enter( 91*67e74705SXin Li // CHECK: call i32 @_setjmp 92*67e74705SXin Li // CHECK-NEXT: icmp eq 93*67e74705SXin Li // CHECK-NEXT: br i1 94*67e74705SXin Li 95*67e74705SXin Li @try { 96*67e74705SXin Li // CHECK: call void @f3_helper(i32 0, i32* nonnull [[X]]) 97*67e74705SXin Li // CHECK: call void @objc_exception_try_exit( 98*67e74705SXin Li f3_helper(0, &x); 99*67e74705SXin Li } @finally { 100*67e74705SXin Li // CHECK: [[DEST1:%.*]] = phi i32 [ 0, {{%.*}} ], [ 3, {{%.*}} ] 101*67e74705SXin Li // CHECK: call void @objc_exception_try_enter 102*67e74705SXin Li // CHECK: call i32 @_setjmp 103*67e74705SXin Li @try { 104*67e74705SXin Li // CHECK: call void @f3_helper(i32 1, i32* nonnull [[X]]) 105*67e74705SXin Li // CHECK: call void @objc_exception_try_exit( 106*67e74705SXin Li f3_helper(1, &x); 107*67e74705SXin Li } @finally { 108*67e74705SXin Li // CHECK: [[DEST2:%.*]] = phi i32 [ 0, {{%.*}} ], [ 5, {{%.*}} ] 109*67e74705SXin Li // CHECK: call void @f3_helper(i32 2, i32* nonnull [[X]]) 110*67e74705SXin Li f3_helper(2, &x); 111*67e74705SXin Li 112*67e74705SXin Li // This loop is large enough to dissuade the optimizer from just 113*67e74705SXin Li // duplicating the finally block. 114*67e74705SXin Li while (x) f3_helper(3, &x); 115*67e74705SXin Li 116*67e74705SXin Li // This is a switch or maybe some chained branches, but relying 117*67e74705SXin Li // on a specific result from the optimizer is really unstable. 118*67e74705SXin Li // CHECK: [[DEST2]] 119*67e74705SXin Li } 120*67e74705SXin Li 121*67e74705SXin Li // This is a switch or maybe some chained branches, but relying 122*67e74705SXin Li // on a specific result from the optimizer is really unstable. 123*67e74705SXin Li // CHECK: [[DEST1]] 124*67e74705SXin Li } 125*67e74705SXin Li 126*67e74705SXin Li // CHECK: call void @f3_helper(i32 4, i32* nonnull [[X]]) 127*67e74705SXin Li // CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* nonnull [[XPTR]]) 128*67e74705SXin Li // CHECK-NEXT: ret void 129*67e74705SXin Li f3_helper(4, &x); 130*67e74705SXin Li} 131*67e74705SXin Li 132*67e74705SXin Li// rdar://problem/8440970 133*67e74705SXin Livoid f4() { 134*67e74705SXin Li extern void f4_help(int); 135*67e74705SXin Li 136*67e74705SXin Li // CHECK-LABEL: define void @f4() 137*67e74705SXin Li // CHECK: [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align 138*67e74705SXin Li // CHECK: call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]]) 139*67e74705SXin Li // CHECK: call i32 @_setjmp 140*67e74705SXin Li @try { 141*67e74705SXin Li // CHECK: call void @f4_help(i32 0) 142*67e74705SXin Li f4_help(0); 143*67e74705SXin Li 144*67e74705SXin Li // The finally cleanup has two threaded entrypoints after optimization: 145*67e74705SXin Li 146*67e74705SXin Li // finally.no-call-exit: Predecessor is when the catch throws. 147*67e74705SXin Li // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]]) 148*67e74705SXin Li // CHECK-NEXT: call void @f4_help(i32 2) 149*67e74705SXin Li // CHECK-NEXT: br label 150*67e74705SXin Li // -> rethrow 151*67e74705SXin Li 152*67e74705SXin Li // finally.call-exit: Predecessors are the @try and @catch fallthroughs 153*67e74705SXin Li // as well as the no-match case in the catch mechanism. The i1 is whether 154*67e74705SXin Li // to rethrow and should be true only in the last case. 155*67e74705SXin Li // CHECK: phi i8* 156*67e74705SXin Li // CHECK-NEXT: phi i1 157*67e74705SXin Li // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* nonnull [[EXNDATA]]) 158*67e74705SXin Li // CHECK-NEXT: call void @f4_help(i32 2) 159*67e74705SXin Li // CHECK-NEXT: br i1 160*67e74705SXin Li // -> ret, rethrow 161*67e74705SXin Li 162*67e74705SXin Li // ret: 163*67e74705SXin Li // CHECK: ret void 164*67e74705SXin Li 165*67e74705SXin Li // Catch mechanism: 166*67e74705SXin Li // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]]) 167*67e74705SXin Li // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]]) 168*67e74705SXin Li // CHECK: call i32 @_setjmp 169*67e74705SXin Li // -> next, finally.no-call-exit 170*67e74705SXin Li // CHECK: call i32 @objc_exception_match 171*67e74705SXin Li // -> finally.call-exit, match 172*67e74705SXin Li } @catch (NSArray *a) { 173*67e74705SXin Li // match: 174*67e74705SXin Li // CHECK: call void @f4_help(i32 1) 175*67e74705SXin Li // CHECK-NEXT: br label 176*67e74705SXin Li // -> finally.call-exit 177*67e74705SXin Li f4_help(1); 178*67e74705SXin Li } @finally { 179*67e74705SXin Li f4_help(2); 180*67e74705SXin Li } 181*67e74705SXin Li 182*67e74705SXin Li // rethrow: 183*67e74705SXin Li // CHECK: phi i8* 184*67e74705SXin Li // CHECK-NEXT: call void @objc_exception_throw(i8* 185*67e74705SXin Li // CHECK-NEXT: unreachable 186*67e74705SXin Li} 187