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