blob: 568cddcc62eea5e73f1bec2bba41d44fcdae076b [file] [log] [blame]
John McCallbd309292010-07-06 01:34:17 +00001// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -O2 -o - %s | FileCheck %s
Daniel Dunbare3883872010-04-23 19:12:32 +00002//
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.
Daniel Dunbare3883872010-04-23 19:12:32 +00006@interface NSArray @end
7void f0() {
8 @try {
9 @try {
10 @throw @"a";
11 } @catch(NSArray *e) {
12 }
13 } @catch (id e) {
14 }
15}
John McCallbd309292010-07-06 01:34:17 +000016
17// CHECK: 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 {
John McCall2dd7d442010-08-04 05:59:32 +000028 // CHECK: call void asm sideeffect "", "*m"
29 // CHECK-NEXT: call void @foo()
John McCallbd309292010-07-06 01:34:17 +000030 foo();
John McCall2dd7d442010-08-04 05:59:32 +000031 // CHECK-NEXT: call void @objc_exception_try_exit
Eric Christopher709e1f32011-01-28 05:13:18 +000032 // CHECK-NEXT: br label %finally.no_call_exit
John McCallbd309292010-07-06 01:34:17 +000033
John McCall2dd7d442010-08-04 05:59:32 +000034 // CHECK: call void asm sideeffect "", "=*m"
Eric Christopher709e1f32011-01-28 05:13:18 +000035 // CHECK-NEXT: br label %finally.no_call_exit
John McCallbd309292010-07-06 01:34:17 +000036 } @finally {
37 break;
38 }
39 }
40}
John McCall42227ed2010-07-31 23:20:56 +000041
42// Test that modifications to local variables are respected under
43// optimization. rdar://problem/8160285
44
45// CHECK: define i32 @f2()
46int f2() {
47 extern void foo(void);
48
49 // CHECK: [[X:%.*]] = alloca i32
John McCall2dd7d442010-08-04 05:59:32 +000050 // CHECK: store i32 5, i32* [[X]]
John McCall42227ed2010-07-31 23:20:56 +000051 int x = 0;
John McCall2dd7d442010-08-04 05:59:32 +000052 x += 5;
John McCall42227ed2010-07-31 23:20:56 +000053
54 // CHECK: [[SETJMP:%.*]] = call i32 @_setjmp
55 // CHECK-NEXT: [[CAUGHT:%.*]] = icmp eq i32 [[SETJMP]], 0
56 // CHECK-NEXT: br i1 [[CAUGHT]]
57 @try {
John McCall2dd7d442010-08-04 05:59:32 +000058 // If the optimizers ever figure out how to make this store 6,
59 // that's okay.
John McCall42227ed2010-07-31 23:20:56 +000060 // CHECK: [[T1:%.*]] = load i32* [[X]]
61 // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], 1
62 // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
63 x++;
John McCall2dd7d442010-08-04 05:59:32 +000064 // CHECK-NEXT: call void asm sideeffect "", "*m,*m"(i32* [[X]]
John McCall42227ed2010-07-31 23:20:56 +000065 // CHECK-NEXT: call void @foo()
John McCall2dd7d442010-08-04 05:59:32 +000066 // CHECK-NEXT: call void @objc_exception_try_exit
67 // CHECK-NEXT: [[T:%.*]] = load i32* [[X]]
Eric Christopher709e1f32011-01-28 05:13:18 +000068 // CHECK-NEXT: br label %finally.no_call_exit
John McCall42227ed2010-07-31 23:20:56 +000069 foo();
Eric Christopher709e1f32011-01-28 05:13:18 +000070
71 // CHECK: %tmp4 = phi i32
72 // CHECK-NEXT: ret i32 %tmp4
John McCall42227ed2010-07-31 23:20:56 +000073 } @catch (id) {
John McCall2dd7d442010-08-04 05:59:32 +000074 // Landing pad. Note that we elide the re-enter.
75 // CHECK: call void asm sideeffect "", "=*m,=*m"(i32* [[X]]
John McCall42227ed2010-07-31 23:20:56 +000076 // CHECK-NEXT: call i8* @objc_exception_extract
John McCall2dd7d442010-08-04 05:59:32 +000077 // CHECK-NEXT: [[T1:%.*]] = load i32* [[X]]
John McCall42227ed2010-07-31 23:20:56 +000078 // CHECK-NEXT: [[T2:%.*]] = add nsw i32 [[T1]], -1
John McCall2dd7d442010-08-04 05:59:32 +000079
80 // This store is dead.
John McCall42227ed2010-07-31 23:20:56 +000081 // CHECK-NEXT: store i32 [[T2]], i32* [[X]]
John McCall2dd7d442010-08-04 05:59:32 +000082
Eric Christopher709e1f32011-01-28 05:13:18 +000083 // CHECK-NEXT: br label %finally.no_call_exit
John McCall42227ed2010-07-31 23:20:56 +000084 x--;
85 }
John McCall42227ed2010-07-31 23:20:56 +000086 return x;
87}
John McCallcebe0ca2010-08-11 00:16:14 +000088
89// Test that the cleanup destination is saved when entering a finally
90// block. rdar://problem/8293901
91// CHECK: define void @f3()
92void f3() {
93 extern void f3_helper(int, int*);
94
95 // CHECK: [[X:%.*]] = alloca i32
96 // CHECK: store i32 0, i32* [[X]]
97 int x = 0;
98
99 // CHECK: call void @objc_exception_try_enter(
100 // CHECK: call i32 @_setjmp
101 // CHECK-NEXT: icmp eq
102 // CHECK-NEXT: br i1
103
104 @try {
105 // CHECK: call void @f3_helper(i32 0, i32* [[X]])
106 // CHECK: call void @objc_exception_try_exit(
107 f3_helper(0, &x);
108 } @finally {
109 // CHECK: [[DEST1:%.*]] = phi i32 [ 0, {{%.*}} ], [ 3, {{%.*}} ]
110 // CHECK: call void @objc_exception_try_enter
111 // CHECK: call i32 @_setjmp
112 @try {
113 // CHECK: call void @f3_helper(i32 1, i32* [[X]])
114 // CHECK: call void @objc_exception_try_exit(
115 f3_helper(1, &x);
116 } @finally {
117 // CHECK: [[DEST2:%.*]] = phi i32 [ 0, {{%.*}} ], [ 5, {{%.*}} ]
118 // CHECK: call void @f3_helper(i32 2, i32* [[X]])
119 f3_helper(2, &x);
120
121 // This loop is large enough to dissuade the optimizer from just
122 // duplicating the finally block.
123 while (x) f3_helper(3, &x);
124
John McCallca7993f2010-08-11 02:06:44 +0000125 // This is a switch or maybe some chained branches, but relying
126 // on a specific result from the optimizer is really unstable.
127 // CHECK: [[DEST2]]
John McCallcebe0ca2010-08-11 00:16:14 +0000128 }
129
John McCallca7993f2010-08-11 02:06:44 +0000130 // This is a switch or maybe some chained branches, but relying
131 // on a specific result from the optimizer is really unstable.
132 // CHECK: [[DEST1]]
John McCallcebe0ca2010-08-11 00:16:14 +0000133 }
134
135 // CHECK: call void @f3_helper(i32 4, i32* [[X]])
136 // CHECK-NEXT: ret void
137 f3_helper(4, &x);
138}
John McCall9916e3f2010-10-04 23:42:51 +0000139
140// rdar://problem/8440970
141void f4() {
142 extern void f4_help(int);
143
144 // CHECK: define void @f4()
145 // CHECK: [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
146 // CHECK: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
147 // CHECK: call i32 @_setjmp
148 @try {
149 // CHECK: call void @f4_help(i32 0)
150 f4_help(0);
151
152 // The finally cleanup has two threaded entrypoints after optimization:
153
154 // finally.no-call-exit: Predecessor is when the catch throws.
155 // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
156 // CHECK-NEXT: call void @f4_help(i32 2)
157 // CHECK-NEXT: br label
158 // -> rethrow
159
160 // finally.call-exit: Predecessors are the @try and @catch fallthroughs
161 // as well as the no-match case in the catch mechanism. The i1 is whether
162 // to rethrow and should be true only in the last case.
163 // CHECK: phi i1
164 // CHECK-NEXT: phi i8*
165 // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* [[EXNDATA]])
166 // CHECK-NEXT: call void @f4_help(i32 2)
167 // CHECK-NEXT: br i1
168 // -> ret, rethrow
169
170 // ret:
171 // CHECK: ret void
172
173 // Catch mechanism:
174 // CHECK: call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
175 // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
176 // CHECK: call i32 @_setjmp
177 // -> next, finally.no-call-exit
178 // CHECK: call i32 @objc_exception_match
179 // -> finally.call-exit, match
180 } @catch (NSArray *a) {
181 // match:
182 // CHECK: call void @f4_help(i32 1)
183 // CHECK-NEXT: br label
184 // -> finally.call-exit
185 f4_help(1);
186 } @finally {
187 f4_help(2);
188 }
189
190 // rethrow:
191 // CHECK: phi i8*
192 // CHECK-NEXT: call void @objc_exception_throw(i8*
193 // CHECK-NEXT: unreachable
194}