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