1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -mllvm -simplifycfg-sink-common=false -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
7void 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()
18void 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:      call void asm sideeffect "", "*m"
30    // CHECK-NEXT: call void @foo()
31      foo();
32    // CHECK:      call void @objc_exception_try_exit
33
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()
44int 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    // Landing pad.  Note that we elide the re-enter.
57    // CHECK:      call void asm sideeffect "", "=*m,=*m"(i32* nonnull [[X]]
58    // CHECK-NEXT: call i8* @objc_exception_extract
59    // CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[X]]
60    // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1
61
62    // CHECK: store i32 6, i32* [[X]]
63    x++;
64    // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* nonnull [[X]]
65    // CHECK-NEXT: call void @foo()
66    // CHECK-NEXT: call void @objc_exception_try_exit
67    // CHECK-NEXT: [[T:%.*]] = load i32, i32* [[X]]
68    foo();
69  } @catch (id) {
70    x--;
71  }
72
73  return x;
74}
75
76// Test that the cleanup destination is saved when entering a finally
77// block.  rdar://problem/8293901
78// CHECK-LABEL: define{{.*}} void @f3()
79void f3() {
80  extern void f3_helper(int, int*);
81
82  // CHECK:      [[X:%.*]] = alloca i32
83  // CHECK:      [[XPTR:%.*]] = bitcast i32* [[X]] to i8*
84  // CHECK:      call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull [[XPTR]])
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: [[DEST1:%.*]] = icmp eq
91  // CHECK-NEXT: br i1 [[DEST1]]
92
93  @try {
94    // CHECK:    call void @f3_helper(i32 0, i32* nonnull [[X]])
95    // CHECK:    call void @objc_exception_try_exit(
96    f3_helper(0, &x);
97  } @finally {
98    // CHECK:    call void @objc_exception_try_enter
99    // CHECK:    call i32 @_setjmp
100    // CHECK-NEXT: [[DEST2:%.*]] = icmp eq
101    // CHECK-NEXT: br i1 [[DEST2]]
102    @try {
103      // CHECK:  call void @f3_helper(i32 1, i32* nonnull [[X]])
104      // CHECK:  call void @objc_exception_try_exit(
105      f3_helper(1, &x);
106    } @finally {
107      // CHECK:  call void @f3_helper(i32 2, i32* nonnull [[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* nonnull [[X]])
125  // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 4, i8* nonnull [[XPTR]])
126  // CHECK-NEXT: ret void
127  f3_helper(4, &x);
128}
129
130// rdar://problem/8440970
131void f4() {
132  extern void f4_help(int);
133
134  // CHECK-LABEL: define{{.*}} void @f4()
135  // CHECK:      [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
136  // CHECK:      call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]])
137  // CHECK:      call i32 @_setjmp
138  @try {
139  // CHECK:      call void @f4_help(i32 0)
140    f4_help(0);
141
142  // The finally cleanup has two threaded entrypoints after optimization:
143
144  // finally.no-call-exit:  Predecessor is when the catch throws.
145  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]])
146  // CHECK-NEXT: call void @f4_help(i32 2)
147  // CHECK-NEXT: br label
148  //   -> rethrow
149
150  // finally.call-exit:  Predecessors are the @try and @catch fallthroughs
151  // as well as the no-match case in the catch mechanism.  The i1 is whether
152  // to rethrow and should be true only in the last case.
153  // CHECK:      phi i8*
154  // CHECK-NEXT: phi i1
155  // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* nonnull [[EXNDATA]])
156  // CHECK-NEXT: call void @f4_help(i32 2)
157  // CHECK-NEXT: br i1
158  //   -> ret, rethrow
159
160  // ret:
161  // CHECK:      ret void
162
163  // Catch mechanism:
164  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* nonnull [[EXNDATA]])
165  // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* nonnull [[EXNDATA]])
166  // CHECK:      call i32 @_setjmp
167  //   -> next, finally.no-call-exit
168  // CHECK:      call i32 @objc_exception_match
169  //   -> finally.call-exit, match
170  } @catch (NSArray *a) {
171  // match:
172  // CHECK:      call void @f4_help(i32 1)
173  // CHECK-NEXT: br label
174  //   -> finally.call-exit
175    f4_help(1);
176  } @finally {
177    f4_help(2);
178  }
179
180  // rethrow:
181  // CHECK:      phi i8*
182  // CHECK-NEXT: call void @objc_exception_throw(i8*
183  // CHECK-NEXT: unreachable
184}
185