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