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