Home | History | Annotate | Download | only in CodeGenObjC
      1 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-fragile-abi -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
      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.
      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 }
     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 {
     28     // CHECK:      call void asm sideeffect "", "*m"
     29     // CHECK-NEXT: call void @foo()
     30       foo();
     31     // CHECK-NEXT: call void @objc_exception_try_exit
     32 
     33     // CHECK:      call void asm sideeffect "", "=*m"
     34     } @finally {
     35       break;
     36     }
     37   }
     38 }
     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
     48   // CHECK:        store i32 5, i32* [[X]]
     49   int x = 0;
     50   x += 5;
     51 
     52   // CHECK:        [[SETJMP:%.*]] = call i32 @_setjmp
     53   // CHECK-NEXT:   [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0
     54   // CHECK-NEXT:   br i1 [[CAUGHT]]
     55   @try {
     56     // If the optimizers ever figure out how to make this store 6,
     57     // that's okay.
     58     // CHECK:      [[T1:%.*]] = load i32* [[X]]
     59     // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], 1
     60     // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
     61     x++;
     62     // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* [[X]]
     63     // CHECK-NEXT: call void @foo()
     64     // CHECK-NEXT: call void @objc_exception_try_exit
     65     // CHECK-NEXT: [[T:%.*]] = load i32* [[X]]
     66     foo();
     67   } @catch (id) {
     68     // Landing pad.  Note that we elide the re-enter.
     69     // CHECK:      call void asm sideeffect "", "=*m,=*m"(i32* [[X]]
     70     // CHECK-NEXT: call i8* @objc_exception_extract
     71     // CHECK-NEXT: [[T1:%.*]] = load i32* [[X]]
     72     // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1
     73 
     74     // This store is dead.
     75     // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
     76     x--;
     77   }
     78 
     79   return x;
     80 }
     81 
     82 // Test that the cleanup destination is saved when entering a finally
     83 // block.  rdar://problem/8293901
     84 // CHECK: define void @f3()
     85 void f3() {
     86   extern void f3_helper(int, int*);
     87 
     88   // CHECK:      [[X:%.*]] = alloca i32
     89   // CHECK:      store i32 0, i32* [[X]]
     90   int x = 0;
     91 
     92   // CHECK:      call void @objc_exception_try_enter(
     93   // CHECK:      call i32 @_setjmp
     94   // CHECK-NEXT: icmp eq
     95   // CHECK-NEXT: br i1
     96 
     97   @try {
     98     // CHECK:    call void @f3_helper(i32 0, i32* [[X]])
     99     // CHECK:    call void @objc_exception_try_exit(
    100     f3_helper(0, &x);
    101   } @finally {
    102     // CHECK:    [[DEST1:%.*]] = phi i32 [ 0, {{%.*}} ], [ 3, {{%.*}} ]
    103     // CHECK:    call void @objc_exception_try_enter
    104     // CHECK:    call i32 @_setjmp
    105     @try {
    106       // CHECK:  call void @f3_helper(i32 1, i32* [[X]])
    107       // CHECK:  call void @objc_exception_try_exit(
    108       f3_helper(1, &x);
    109     } @finally {
    110       // CHECK:  [[DEST2:%.*]] = phi i32 [ 0, {{%.*}} ], [ 5, {{%.*}} ]
    111       // CHECK:  call void @f3_helper(i32 2, i32* [[X]])
    112       f3_helper(2, &x);
    113 
    114       // This loop is large enough to dissuade the optimizer from just
    115       // duplicating the finally block.
    116       while (x) f3_helper(3, &x);
    117 
    118       // This is a switch or maybe some chained branches, but relying
    119       // on a specific result from the optimizer is really unstable.
    120       // CHECK:  [[DEST2]]
    121     }
    122 
    123       // This is a switch or maybe some chained branches, but relying
    124       // on a specific result from the optimizer is really unstable.
    125     // CHECK:    [[DEST1]]
    126   }
    127 
    128   // CHECK:      call void @f3_helper(i32 4, i32* [[X]])
    129   // CHECK-NEXT: ret void
    130   f3_helper(4, &x);
    131 }
    132 
    133 // rdar://problem/8440970
    134 void f4() {
    135   extern void f4_help(int);
    136 
    137   // CHECK: define void @f4()
    138   // CHECK:      [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
    139   // CHECK:      call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
    140   // CHECK:      call i32 @_setjmp
    141   @try {
    142   // CHECK:      call void @f4_help(i32 0)
    143     f4_help(0);
    144 
    145   // The finally cleanup has two threaded entrypoints after optimization:
    146 
    147   // finally.no-call-exit:  Predecessor is when the catch throws.
    148   // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
    149   // CHECK-NEXT: call void @f4_help(i32 2)
    150   // CHECK-NEXT: br label
    151   //   -> rethrow
    152 
    153   // finally.call-exit:  Predecessors are the @try and @catch fallthroughs
    154   // as well as the no-match case in the catch mechanism.  The i1 is whether
    155   // to rethrow and should be true only in the last case.
    156   // CHECK:      phi i1
    157   // CHECK-NEXT: phi i8*
    158   // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* [[EXNDATA]])
    159   // CHECK-NEXT: call void @f4_help(i32 2)
    160   // CHECK-NEXT: br i1
    161   //   -> ret, rethrow
    162 
    163   // ret:
    164   // CHECK:      ret void
    165 
    166   // Catch mechanism:
    167   // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
    168   // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
    169   // CHECK:      call i32 @_setjmp
    170   //   -> next, finally.no-call-exit
    171   // CHECK:      call i32 @objc_exception_match
    172   //   -> finally.call-exit, match
    173   } @catch (NSArray *a) {
    174   // match:
    175   // CHECK:      call void @f4_help(i32 1)
    176   // CHECK-NEXT: br label
    177   //   -> finally.call-exit
    178     f4_help(1);
    179   } @finally {
    180     f4_help(2);
    181   }
    182 
    183   // rethrow:
    184   // CHECK:      phi i8*
    185   // CHECK-NEXT: call void @objc_exception_throw(i8*
    186   // CHECK-NEXT: unreachable
    187 }
    188