blob: 13f9c18dade88bd528b1ba80be7b9b027f03ba6c [file] [log] [blame]
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +00001; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm
Heejin Ahnd6f48782019-01-30 03:21:57 +00002; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck -allow-deprecated-dag-overlap %s
Heejin Ahn5b023e02018-11-02 18:38:52 +00003; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -exception-model=wasm -mattr=+exception-handling
Heejin Ahnac62b052017-06-30 00:43:15 +00004
5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
Sam Clegga5908002018-05-10 17:49:11 +00006target triple = "wasm32-unknown-unknown"
Heejin Ahnac62b052017-06-30 00:43:15 +00007
Heejin Ahn78297632019-02-26 03:29:59 +00008%struct.Temp = type { i8 }
Heejin Ahnac62b052017-06-30 00:43:15 +00009
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +000010@_ZTIi = external constant i8*
11
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +000012; CHECK-LABEL: test_throw:
Heejin Ahn78297632019-02-26 03:29:59 +000013; CHECK: throw __cpp_exception, $0
14; CHECK-NOT: unreachable
Heejin Ahn095796a2018-11-16 00:47:18 +000015define void @test_throw(i8* %p) {
16 call void @llvm.wasm.throw(i32 0, i8* %p)
Heejin Ahnac62b052017-06-30 00:43:15 +000017 ret void
18}
19
Heejin Ahnd6f48782019-01-30 03:21:57 +000020; CHECK-LABEL: test_rethrow:
Heejin Ahn78297632019-02-26 03:29:59 +000021; CHECK: rethrow
22; CHECK-NOT: unreachable
Heejin Ahnd6f48782019-01-30 03:21:57 +000023define void @test_rethrow(i8* %p) {
24 call void @llvm.wasm.rethrow()
25 ret void
26}
27
Heejin Ahn78297632019-02-26 03:29:59 +000028; Simple test with a try-catch
29;
30; void foo();
31; void test_catch() {
32; try {
33; foo();
34; } catch (int) {
35; }
36; }
37
38; CHECK-LABEL: test_catch:
39; CHECK: global.get ${{.+}}=, __stack_pointer
40; CHECK: block
41; CHECK: try
42; CHECK: call foo
43; CHECK: br 0
44; CHECK: catch $[[EXCEPT_REF:[0-9]+]]=
45; CHECK: global.set __stack_pointer
46; CHECK: block i32
47; CHECK: br_on_exn 0, __cpp_exception, $[[EXCEPT_REF]]
48; CHECK: rethrow
49; CHECK: end_block
50; CHECK: extract_exception $[[EXN:[0-9]+]]=
51; CHECK-DAG: i32.store __wasm_lpad_context
52; CHECK-DAG: i32.store __wasm_lpad_context+4
53; CHECK: i32.call $drop=, _Unwind_CallPersonality, $[[EXN]]
54; CHECK: block
55; CHECK: br_if 0
56; CHECK: i32.call $drop=, __cxa_begin_catch
57; CHECK: call __cxa_end_catch
58; CHECK: br 1
59; CHECK: end_block
60; CHECK: call __cxa_rethrow
61; CHECK: end_try
62; CHECK: end_block
63define void @test_catch() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +000064entry:
65 invoke void @foo()
66 to label %try.cont unwind label %catch.dispatch
67
68catch.dispatch: ; preds = %entry
69 %0 = catchswitch within none [label %catch.start] unwind to caller
70
71catch.start: ; preds = %catch.dispatch
72 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
73 %2 = call i8* @llvm.wasm.get.exception(token %1)
74 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
75 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
76 %matches = icmp eq i32 %3, %4
77 br i1 %matches, label %catch, label %rethrow
78
79catch: ; preds = %catch.start
80 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
81 call void @__cxa_end_catch() [ "funclet"(token %1) ]
82 catchret from %1 to label %try.cont
83
84rethrow: ; preds = %catch.start
85 call void @__cxa_rethrow() [ "funclet"(token %1) ]
86 unreachable
87
88try.cont: ; preds = %entry, %catch
Heejin Ahnac62b052017-06-30 00:43:15 +000089 ret void
90}
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +000091
Heejin Ahn78297632019-02-26 03:29:59 +000092; Destructor (cleanup) test
93;
94; void foo();
95; struct Temp {
96; ~Temp() {}
97; };
98; void test_cleanup() {
99; Temp t;
100; foo();
101; }
102
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000103; CHECK-LABEL: test_cleanup:
Heejin Ahn78297632019-02-26 03:29:59 +0000104; CHECK: block
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000105; CHECK: try
Heejin Ahn78297632019-02-26 03:29:59 +0000106; CHECK: call foo
107; CHECK: br 0
Heejin Ahnd6f48782019-01-30 03:21:57 +0000108; CHECK: catch
Heejin Ahn78297632019-02-26 03:29:59 +0000109; CHECK: global.set __stack_pointer
110; CHECK: i32.call $drop=, _ZN4TempD2Ev
111; CHECK: rethrow
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000112; CHECK: end_try
Heejin Ahn78297632019-02-26 03:29:59 +0000113; CHECK: end_block
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000114define void @test_cleanup() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
115entry:
Heejin Ahn78297632019-02-26 03:29:59 +0000116 %t = alloca %struct.Temp, align 1
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000117 invoke void @foo()
118 to label %invoke.cont unwind label %ehcleanup
119
120invoke.cont: ; preds = %entry
Heejin Ahn78297632019-02-26 03:29:59 +0000121 %call = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t)
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000122 ret void
123
124ehcleanup: ; preds = %entry
125 %0 = cleanuppad within none []
Heejin Ahn78297632019-02-26 03:29:59 +0000126 %call1 = call %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* %t) [ "funclet"(token %0) ]
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000127 cleanupret from %0 unwind to caller
128}
129
Heejin Ahn78297632019-02-26 03:29:59 +0000130; Calling a function that may throw within a 'catch (...)' generates a
131; temrinatepad, because __cxa_end_catch() also can throw within 'catch (...)'.
132;
133; void foo();
134; void test_terminatepad() {
135; try {
136; foo();
137; } catch (...) {
138; foo();
139; }
140; }
141
Heejin Ahn4934f762018-06-25 01:07:11 +0000142; CHECK-LABEL: test_terminatepad
Heejin Ahn78297632019-02-26 03:29:59 +0000143; CHECK: block
144; CHECK: try
145; CHECK: call foo
146; CHECK: br 0
Heejin Ahnd6f48782019-01-30 03:21:57 +0000147; CHECK: catch
Heejin Ahn78297632019-02-26 03:29:59 +0000148; CHECK: i32.call $drop=, __cxa_begin_catch
149; CHECK: block
150; CHECK: try
151; CHECK: call foo
152; CHECK: br 0
153; CHECK: catch
154; CHECK: block
155; CHECK: try
156; CHECK: call __cxa_end_catch
157; CHECK: br 0
158; CHECK: catch
159; CHECK: block i32
160; CHECK: br_on_exn 0, __cpp_exception
161; CHECK: call __clang_call_terminate, 0
162; CHECK: unreachable
163; CHECK: end_block
164; CHECK: call __clang_call_terminate
165; CHECK: unreachable
166; CHECK: end_try
167; CHECK: end_block
168; CHECK: rethrow
169; CHECK: end_try
170; CHECK: end_block
171; CHECK: call __cxa_end_catch
172; CHECK: end_try
173; CHECK: end_block
Heejin Ahnd6f48782019-01-30 03:21:57 +0000174define void @test_terminatepad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
Heejin Ahn4934f762018-06-25 01:07:11 +0000175entry:
Heejin Ahn4934f762018-06-25 01:07:11 +0000176 invoke void @foo()
Heejin Ahn4934f762018-06-25 01:07:11 +0000177 to label %try.cont unwind label %catch.dispatch
178
Heejin Ahnd6f48782019-01-30 03:21:57 +0000179catch.dispatch: ; preds = %entry
180 %0 = catchswitch within none [label %catch.start] unwind to caller
Heejin Ahn4934f762018-06-25 01:07:11 +0000181
182catch.start: ; preds = %catch.dispatch
Heejin Ahnd6f48782019-01-30 03:21:57 +0000183 %1 = catchpad within %0 [i8* null]
184 %2 = call i8* @llvm.wasm.get.exception(token %1)
185 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
186 %4 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
187 invoke void @foo() [ "funclet"(token %1) ]
188 to label %invoke.cont1 unwind label %ehcleanup
Heejin Ahn4934f762018-06-25 01:07:11 +0000189
Heejin Ahnd6f48782019-01-30 03:21:57 +0000190invoke.cont1: ; preds = %catch.start
191 call void @__cxa_end_catch() [ "funclet"(token %1) ]
192 catchret from %1 to label %try.cont
Heejin Ahn4934f762018-06-25 01:07:11 +0000193
Heejin Ahnd6f48782019-01-30 03:21:57 +0000194try.cont: ; preds = %entry, %invoke.cont1
195 ret void
Heejin Ahn4934f762018-06-25 01:07:11 +0000196
Heejin Ahnd6f48782019-01-30 03:21:57 +0000197ehcleanup: ; preds = %catch.start
198 %5 = cleanuppad within %1 []
199 invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
200 to label %invoke.cont2 unwind label %terminate
Heejin Ahn4934f762018-06-25 01:07:11 +0000201
Heejin Ahnd6f48782019-01-30 03:21:57 +0000202invoke.cont2: ; preds = %ehcleanup
203 cleanupret from %5 unwind to caller
Heejin Ahn4934f762018-06-25 01:07:11 +0000204
205terminate: ; preds = %ehcleanup
Heejin Ahnd6f48782019-01-30 03:21:57 +0000206 %6 = cleanuppad within %5 []
207 %7 = call i8* @llvm.wasm.get.exception(token %6)
208 call void @__clang_call_terminate(i8* %7) [ "funclet"(token %6) ]
Heejin Ahn4934f762018-06-25 01:07:11 +0000209 unreachable
210}
211
Heejin Ahned5e06b2018-08-21 19:44:11 +0000212; Tests prologues and epilogues are not generated within EH scopes.
213; They should not be treated as funclets; BBs starting with a catch instruction
214; should not have a prologue, and BBs ending with a catchret/cleanupret should
215; not have an epilogue. This is separate from __stack_pointer restoring
216; instructions after a catch instruction.
Heejin Ahn78297632019-02-26 03:29:59 +0000217;
218; void bar(int) noexcept;
219; void test_no_prolog_epilog_in_ehpad() {
220; int stack_var = 0;
221; bar(stack_var);
222; try {
223; foo();
224; } catch (int) {
225; foo();
226; }
227; }
Heejin Ahned5e06b2018-08-21 19:44:11 +0000228
229; CHECK-LABEL: test_no_prolog_epilog_in_ehpad
Heejin Ahn78297632019-02-26 03:29:59 +0000230; CHECK: block
231; CHECK: try
232; CHECK: call foo
233; CHECK: br 0
234; CHECK: catch
235; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer
236; CHECK: global.set __stack_pointer
237; CHECK: block
238; CHECK: block
239; CHECK: br_if 0
240; CHECK: i32.call $drop=, __cxa_begin_catch
241; CHECK: try
242; CHECK: call foo
243; CHECK: br 2
244; CHECK: catch
245; CHECK-NOT: global.get $push{{.+}}=, __stack_pointer
246; CHECK: global.set __stack_pointer
247; CHECK: call __cxa_end_catch
248; CHECK: rethrow
249; CHECK-NOT: global.set __stack_pointer, $pop{{.+}}
250; CHECK: end_try
251; CHECK: end_block
252; CHECK: call __cxa_rethrow
253; CHECK: end_block
254; CHECK-NOT: global.set __stack_pointer, $pop{{.+}}
255; CHECK: call __cxa_end_catch
256; CHECK: end_try
257; CHECK: end_block
Heejin Ahned5e06b2018-08-21 19:44:11 +0000258define void @test_no_prolog_epilog_in_ehpad() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
259entry:
260 %stack_var = alloca i32, align 4
261 call void @bar(i32* %stack_var)
262 invoke void @foo()
263 to label %try.cont unwind label %catch.dispatch
264
265catch.dispatch: ; preds = %entry
266 %0 = catchswitch within none [label %catch.start] unwind to caller
267
268catch.start: ; preds = %catch.dispatch
269 %1 = catchpad within %0 [i8* bitcast (i8** @_ZTIi to i8*)]
270 %2 = call i8* @llvm.wasm.get.exception(token %1)
271 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
272 %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
273 %matches = icmp eq i32 %3, %4
274 br i1 %matches, label %catch, label %rethrow
275
276catch: ; preds = %catch.start
277 %5 = call i8* @__cxa_begin_catch(i8* %2) [ "funclet"(token %1) ]
278 %6 = bitcast i8* %5 to float*
279 %7 = load float, float* %6, align 4
280 invoke void @foo() [ "funclet"(token %1) ]
281 to label %invoke.cont1 unwind label %ehcleanup
282
283invoke.cont1: ; preds = %catch
284 call void @__cxa_end_catch() [ "funclet"(token %1) ]
285 catchret from %1 to label %try.cont
286
287rethrow: ; preds = %catch.start
288 call void @__cxa_rethrow() [ "funclet"(token %1) ]
289 unreachable
290
291try.cont: ; preds = %entry, %invoke.cont1
292 ret void
293
294ehcleanup: ; preds = %catch
295 %8 = cleanuppad within %1 []
296 call void @__cxa_end_catch() [ "funclet"(token %8) ]
297 cleanupret from %8 unwind to caller
298}
299
Heejin Ahn972fc352018-08-22 21:13:49 +0000300; When a function does not have stack-allocated objects, it does not need to
301; store SP back to __stack_pointer global at the epilog.
Heejin Ahn78297632019-02-26 03:29:59 +0000302;
303; void foo();
304; void test_no_sp_writeback() {
305; try {
306; foo();
307; } catch (...) {
308; }
309; }
Heejin Ahn972fc352018-08-22 21:13:49 +0000310
Heejin Ahn78297632019-02-26 03:29:59 +0000311; CHECK-LABEL: test_no_sp_writeback
312; CHECK: block
313; CHECK: try
314; CHECK: call foo
315; CHECK: br 0
316; CHECK: catch
317; CHECK: i32.call $drop=, __cxa_begin_catch
318; CHECK: call __cxa_end_catch
319; CHECK: end_try
320; CHECK: end_block
321; CHECK-NOT: global.set __stack_pointer
322; CHECK: return
323define void @test_no_sp_writeback() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
Heejin Ahn972fc352018-08-22 21:13:49 +0000324entry:
325 invoke void @foo()
326 to label %try.cont unwind label %catch.dispatch
327
328catch.dispatch: ; preds = %entry
329 %0 = catchswitch within none [label %catch.start] unwind to caller
330
331catch.start: ; preds = %catch.dispatch
332 %1 = catchpad within %0 [i8* null]
333 %2 = call i8* @llvm.wasm.get.exception(token %1)
334 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
335 %4 = call i8* @__cxa_begin_catch(i8* %2) #2 [ "funclet"(token %1) ]
336 call void @__cxa_end_catch() [ "funclet"(token %1) ]
337 catchret from %1 to label %try.cont
338
339try.cont: ; preds = %entry, %catch.start
340 ret void
341}
342
Heejin Ahnd2a56ac2019-02-26 04:08:49 +0000343; When the result of @llvm.wasm.get.exception is not used. This is created to
344; fix a bug in LateEHPrepare and this should not crash.
345define void @test_get_exception_wo_use() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
346entry:
347 invoke void @foo()
348 to label %try.cont unwind label %catch.dispatch
349
350catch.dispatch: ; preds = %entry
351 %0 = catchswitch within none [label %catch.start] unwind to caller
352
353catch.start: ; preds = %catch.dispatch
354 %1 = catchpad within %0 [i8* null]
355 %2 = call i8* @llvm.wasm.get.exception(token %1)
356 %3 = call i32 @llvm.wasm.get.ehselector(token %1)
357 catchret from %1 to label %try.cont
358
359try.cont: ; preds = %entry, %catch.start
360 ret void
361}
362
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000363declare void @foo()
Heejin Ahned5e06b2018-08-21 19:44:11 +0000364declare void @bar(i32*)
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000365declare i32 @__gxx_wasm_personality_v0(...)
Heejin Ahnd6f48782019-01-30 03:21:57 +0000366declare void @llvm.wasm.throw(i32, i8*)
367declare void @llvm.wasm.rethrow()
Heejin Ahn5ef4d5f2018-05-31 22:25:54 +0000368declare i8* @llvm.wasm.get.exception(token)
369declare i32 @llvm.wasm.get.ehselector(token)
370declare i32 @llvm.eh.typeid.for(i8*)
371declare i8* @__cxa_begin_catch(i8*)
372declare void @__cxa_end_catch()
373declare void @__cxa_rethrow()
374declare void @__clang_call_terminate(i8*)
Heejin Ahn78297632019-02-26 03:29:59 +0000375declare %struct.Temp* @_ZN4TempD2Ev(%struct.Temp* returned)
Heejin Ahnda419bd2018-11-14 02:46:21 +0000376
377; CHECK: __cpp_exception:
Heejin Ahnbe5e5872018-12-11 01:11:04 +0000378; CHECK: .eventtype __cpp_exception i32