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