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* [[X]]
     59     // CHECK-NEXT: call void @foo()
     60     // CHECK-NEXT: call void @objc_exception_try_exit
     61     // CHECK-NEXT: [[T:%.*]] = load 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* [[X]]
     66     // CHECK-NEXT: call i8* @objc_exception_extract
     67     // CHECK-NEXT: [[T1:%.*]] = load 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:      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 
    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]]
    117     }
    118 
    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]]
    122   }
    123 
    124   // CHECK:      call void @f3_helper(i32 4, i32* [[X]])
    125   // CHECK-NEXT: ret void
    126   f3_helper(4, &x);
    127 }
    128 
    129 // rdar://problem/8440970
    130 void f4() {
    131   extern void f4_help(int);
    132 
    133   // CHECK-LABEL: 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 i8*
    153   // CHECK-NEXT: phi i1
    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 }
    184