xref: /llvm-project/llvm/test/CodeGen/WebAssembly/exception-legacy.ll (revision a8e1135baa9074f7c088c8e1999561f88699b56e)
1*a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s
2*a8e1135bSHeejin Ahn; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling -verify-machineinstrs -O0
3*a8e1135bSHeejin Ahn; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -wasm-enable-eh -wasm-use-legacy-eh -exception-model=wasm -mattr=+exception-handling
4c108c1e9SHeejin Ahn
5c108c1e9SHeejin Ahntarget triple = "wasm32-unknown-unknown"
6c108c1e9SHeejin Ahn
7c108c1e9SHeejin Ahn%struct.Temp = type { i8 }
8c108c1e9SHeejin Ahn
9c108c1e9SHeejin Ahn@_ZTIi = external dso_local constant ptr
10c108c1e9SHeejin Ahn
11c108c1e9SHeejin Ahn; CHECK: .tagtype  __cpp_exception i32
12c108c1e9SHeejin Ahn
138b28e2ebSHeejin Ahn; CHECK-LABEL: throw:
14c108c1e9SHeejin Ahn; CHECK:     throw __cpp_exception, $0
15c108c1e9SHeejin Ahn; CHECK-NOT: unreachable
168b28e2ebSHeejin Ahndefine void @throw(ptr %p) {
17c108c1e9SHeejin Ahn  call void @llvm.wasm.throw(i32 0, ptr %p)
18c108c1e9SHeejin Ahn  ret void
19c108c1e9SHeejin Ahn}
20c108c1e9SHeejin Ahn
21c108c1e9SHeejin Ahn; Simple test with a try-catch
22c108c1e9SHeejin Ahn;
23c108c1e9SHeejin Ahn; void foo();
248b28e2ebSHeejin Ahn; void catch() {
25c108c1e9SHeejin Ahn;   try {
26c108c1e9SHeejin Ahn;     foo();
27c108c1e9SHeejin Ahn;   } catch (int) {
28c108c1e9SHeejin Ahn;   }
29c108c1e9SHeejin Ahn; }
30c108c1e9SHeejin Ahn
318b28e2ebSHeejin Ahn; CHECK-LABEL: catch:
32c108c1e9SHeejin Ahn; CHECK:     global.get  ${{.+}}=, __stack_pointer
33c108c1e9SHeejin Ahn; CHECK:     try
34c108c1e9SHeejin Ahn; CHECK:       call      foo
35c108c1e9SHeejin Ahn; CHECK:     catch     $[[EXN:[0-9]+]]=, __cpp_exception
36c108c1e9SHeejin Ahn; CHECK:       global.set  __stack_pointer
37c108c1e9SHeejin Ahn; CHECK:       i32.{{store|const}} {{.*}} __wasm_lpad_context
38c108c1e9SHeejin Ahn; CHECK:       call       $drop=, _Unwind_CallPersonality, $[[EXN]]
39c108c1e9SHeejin Ahn; CHECK:       block
40c108c1e9SHeejin Ahn; CHECK:         br_if     0
41c108c1e9SHeejin Ahn; CHECK:         call      $drop=, __cxa_begin_catch
42c108c1e9SHeejin Ahn; CHECK:         call      __cxa_end_catch
43c108c1e9SHeejin Ahn; CHECK:         br        1
44c108c1e9SHeejin Ahn; CHECK:       end_block
45c108c1e9SHeejin Ahn; CHECK:       rethrow   0
46c108c1e9SHeejin Ahn; CHECK:     end_try
478b28e2ebSHeejin Ahndefine void @catch() personality ptr @__gxx_wasm_personality_v0 {
48c108c1e9SHeejin Ahnentry:
49c108c1e9SHeejin Ahn  invoke void @foo()
50c108c1e9SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
51c108c1e9SHeejin Ahn
52c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %entry
53c108c1e9SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
54c108c1e9SHeejin Ahn
55c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
56c108c1e9SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
57c108c1e9SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
58c108c1e9SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
59c108c1e9SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)
60c108c1e9SHeejin Ahn  %matches = icmp eq i32 %3, %4
61c108c1e9SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
62c108c1e9SHeejin Ahn
63c108c1e9SHeejin Ahncatch:                                            ; preds = %catch.start
64c108c1e9SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
65c108c1e9SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
66c108c1e9SHeejin Ahn  catchret from %1 to label %try.cont
67c108c1e9SHeejin Ahn
68c108c1e9SHeejin Ahnrethrow:                                          ; preds = %catch.start
69c108c1e9SHeejin Ahn  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
70c108c1e9SHeejin Ahn  unreachable
71c108c1e9SHeejin Ahn
72c108c1e9SHeejin Ahntry.cont:                                         ; preds = %catch, %entry
73c108c1e9SHeejin Ahn  ret void
74c108c1e9SHeejin Ahn}
75c108c1e9SHeejin Ahn
76c108c1e9SHeejin Ahn; Destructor (cleanup) test
77c108c1e9SHeejin Ahn;
78c108c1e9SHeejin Ahn; void foo();
79c108c1e9SHeejin Ahn; struct Temp {
80c108c1e9SHeejin Ahn;   ~Temp() {}
81c108c1e9SHeejin Ahn; };
828b28e2ebSHeejin Ahn; void cleanup() {
83c108c1e9SHeejin Ahn;   Temp t;
84c108c1e9SHeejin Ahn;   foo();
85c108c1e9SHeejin Ahn; }
86c108c1e9SHeejin Ahn
878b28e2ebSHeejin Ahn; CHECK-LABEL: cleanup:
88c108c1e9SHeejin Ahn; CHECK: try
89c108c1e9SHeejin Ahn; CHECK:   call      foo
90c108c1e9SHeejin Ahn; CHECK: catch_all
91c108c1e9SHeejin Ahn; CHECK:   global.set  __stack_pointer
92c108c1e9SHeejin Ahn; CHECK:   call      $drop=, _ZN4TempD2Ev
93c108c1e9SHeejin Ahn; CHECK:   rethrow   0
94c108c1e9SHeejin Ahn; CHECK: end_try
958b28e2ebSHeejin Ahndefine void @cleanup() personality ptr @__gxx_wasm_personality_v0 {
96c108c1e9SHeejin Ahnentry:
97c108c1e9SHeejin Ahn  %t = alloca %struct.Temp, align 1
98c108c1e9SHeejin Ahn  invoke void @foo()
99c108c1e9SHeejin Ahn          to label %invoke.cont unwind label %ehcleanup
100c108c1e9SHeejin Ahn
101c108c1e9SHeejin Ahninvoke.cont:                                      ; preds = %entry
102c108c1e9SHeejin Ahn  %call = call ptr @_ZN4TempD2Ev(ptr %t)
103c108c1e9SHeejin Ahn  ret void
104c108c1e9SHeejin Ahn
105c108c1e9SHeejin Ahnehcleanup:                                        ; preds = %entry
106c108c1e9SHeejin Ahn  %0 = cleanuppad within none []
107c108c1e9SHeejin Ahn  %call1 = call ptr @_ZN4TempD2Ev(ptr %t) [ "funclet"(token %0) ]
108c108c1e9SHeejin Ahn  cleanupret from %0 unwind to caller
109c108c1e9SHeejin Ahn}
110c108c1e9SHeejin Ahn
111c108c1e9SHeejin Ahn; Calling a function that may throw within a 'catch (...)' generates a
1126bbf7f06SHeejin Ahn; terminatepad, because __cxa_end_catch() also can throw within 'catch (...)'.
113c108c1e9SHeejin Ahn;
114c108c1e9SHeejin Ahn; void foo();
1158b28e2ebSHeejin Ahn; void terminatepad() {
116c108c1e9SHeejin Ahn;   try {
117c108c1e9SHeejin Ahn;     foo();
118c108c1e9SHeejin Ahn;   } catch (...) {
119c108c1e9SHeejin Ahn;     foo();
120c108c1e9SHeejin Ahn;   }
121c108c1e9SHeejin Ahn; }
122c108c1e9SHeejin Ahn
1238b28e2ebSHeejin Ahn; CHECK-LABEL: terminatepad
124c108c1e9SHeejin Ahn; CHECK: try
125c108c1e9SHeejin Ahn; CHECK:   call      foo
126c108c1e9SHeejin Ahn; CHECK: catch
127c108c1e9SHeejin Ahn; CHECK:   call      $drop=, __cxa_begin_catch
128c108c1e9SHeejin Ahn; CHECK:   try
129c108c1e9SHeejin Ahn; CHECK:     call      foo
130c108c1e9SHeejin Ahn; CHECK:   catch_all
131c108c1e9SHeejin Ahn; CHECK:     try
132c108c1e9SHeejin Ahn; CHECK:       call      __cxa_end_catch
133c108c1e9SHeejin Ahn; CHECK:     catch_all
134c108c1e9SHeejin Ahn; CHECK:       call      _ZSt9terminatev
135c108c1e9SHeejin Ahn; CHECK:       unreachable
136c108c1e9SHeejin Ahn; CHECK:     end_try
137c108c1e9SHeejin Ahn; CHECK:     rethrow
138c108c1e9SHeejin Ahn; CHECK:   end_try
139c108c1e9SHeejin Ahn; CHECK:   call      __cxa_end_catch
140c108c1e9SHeejin Ahn; CHECK: end_try
1418b28e2ebSHeejin Ahndefine void @terminatepad() personality ptr @__gxx_wasm_personality_v0 {
142c108c1e9SHeejin Ahnentry:
143c108c1e9SHeejin Ahn  invoke void @foo()
144c108c1e9SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
145c108c1e9SHeejin Ahn
146c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %entry
147c108c1e9SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
148c108c1e9SHeejin Ahn
149c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
150c108c1e9SHeejin Ahn  %1 = catchpad within %0 [ptr null]
151c108c1e9SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
152c108c1e9SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
153c108c1e9SHeejin Ahn  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
154c108c1e9SHeejin Ahn  invoke void @foo() [ "funclet"(token %1) ]
155c108c1e9SHeejin Ahn          to label %invoke.cont1 unwind label %ehcleanup
156c108c1e9SHeejin Ahn
157c108c1e9SHeejin Ahninvoke.cont1:                                     ; preds = %catch.start
158c108c1e9SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
159c108c1e9SHeejin Ahn  catchret from %1 to label %try.cont
160c108c1e9SHeejin Ahn
161c108c1e9SHeejin Ahntry.cont:                                         ; preds = %invoke.cont1, %entry
162c108c1e9SHeejin Ahn  ret void
163c108c1e9SHeejin Ahn
164c108c1e9SHeejin Ahnehcleanup:                                        ; preds = %catch.start
165c108c1e9SHeejin Ahn  %5 = cleanuppad within %1 []
166c108c1e9SHeejin Ahn  invoke void @__cxa_end_catch() [ "funclet"(token %5) ]
167c108c1e9SHeejin Ahn          to label %invoke.cont2 unwind label %terminate
168c108c1e9SHeejin Ahn
169c108c1e9SHeejin Ahninvoke.cont2:                                     ; preds = %ehcleanup
170c108c1e9SHeejin Ahn  cleanupret from %5 unwind to caller
171c108c1e9SHeejin Ahn
172c108c1e9SHeejin Ahnterminate:                                        ; preds = %ehcleanup
173c108c1e9SHeejin Ahn  %6 = cleanuppad within %5 []
174c108c1e9SHeejin Ahn  call void @_ZSt9terminatev() [ "funclet"(token %6) ]
175c108c1e9SHeejin Ahn  unreachable
176c108c1e9SHeejin Ahn}
177c108c1e9SHeejin Ahn
178c108c1e9SHeejin Ahn; Tests prologues and epilogues are not generated within EH scopes.
179c108c1e9SHeejin Ahn; They should not be treated as funclets; BBs starting with a catch instruction
180c108c1e9SHeejin Ahn; should not have a prologue, and BBs ending with a catchret/cleanupret should
181c108c1e9SHeejin Ahn; not have an epilogue. This is separate from __stack_pointer restoring
182c108c1e9SHeejin Ahn; instructions after a catch instruction.
183c108c1e9SHeejin Ahn;
184c108c1e9SHeejin Ahn; void bar(int) noexcept;
1858b28e2ebSHeejin Ahn; void no_prolog_epilog_in_ehpad() {
186c108c1e9SHeejin Ahn;   int stack_var = 0;
187c108c1e9SHeejin Ahn;   bar(stack_var);
188c108c1e9SHeejin Ahn;   try {
189c108c1e9SHeejin Ahn;     foo();
190c108c1e9SHeejin Ahn;   } catch (int) {
191c108c1e9SHeejin Ahn;     foo();
192c108c1e9SHeejin Ahn;   }
193c108c1e9SHeejin Ahn; }
194c108c1e9SHeejin Ahn
1958b28e2ebSHeejin Ahn; CHECK-LABEL: no_prolog_epilog_in_ehpad
196c108c1e9SHeejin Ahn; CHECK:     try
197c108c1e9SHeejin Ahn; CHECK:       call      foo
198c108c1e9SHeejin Ahn; CHECK:     catch
199c108c1e9SHeejin Ahn; CHECK-NOT:   global.get  $push{{.+}}=, __stack_pointer
200c108c1e9SHeejin Ahn; CHECK:       global.set  __stack_pointer
201c108c1e9SHeejin Ahn; CHECK:       block
202c108c1e9SHeejin Ahn; CHECK:         block
203c108c1e9SHeejin Ahn; CHECK:           br_if     0
204c108c1e9SHeejin Ahn; CHECK:           call      $drop=, __cxa_begin_catch
205c108c1e9SHeejin Ahn; CHECK:           try
206c108c1e9SHeejin Ahn; CHECK:             call      foo
207c108c1e9SHeejin Ahn; CHECK:           catch
208c108c1e9SHeejin Ahn; CHECK-NOT:         global.get  $push{{.+}}=, __stack_pointer
209c108c1e9SHeejin Ahn; CHECK:             global.set  __stack_pointer
210c108c1e9SHeejin Ahn; CHECK:             call      __cxa_end_catch
211c108c1e9SHeejin Ahn; CHECK:             rethrow
212c108c1e9SHeejin Ahn; CHECK-NOT:         global.set  __stack_pointer, $pop{{.+}}
213c108c1e9SHeejin Ahn; CHECK:           end_try
214c108c1e9SHeejin Ahn; CHECK:         end_block
215c108c1e9SHeejin Ahn; CHECK:         rethrow
216c108c1e9SHeejin Ahn; CHECK:       end_block
217c108c1e9SHeejin Ahn; CHECK-NOT:   global.set  __stack_pointer, $pop{{.+}}
218c108c1e9SHeejin Ahn; CHECK:       call      __cxa_end_catch
219c108c1e9SHeejin Ahn; CHECK:     end_try
2208b28e2ebSHeejin Ahndefine void @no_prolog_epilog_in_ehpad() personality ptr @__gxx_wasm_personality_v0 {
221c108c1e9SHeejin Ahnentry:
222c108c1e9SHeejin Ahn  %stack_var = alloca i32, align 4
223c108c1e9SHeejin Ahn  call void @bar(ptr %stack_var)
224c108c1e9SHeejin Ahn  invoke void @foo()
225c108c1e9SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
226c108c1e9SHeejin Ahn
227c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %entry
228c108c1e9SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
229c108c1e9SHeejin Ahn
230c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
231c108c1e9SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
232c108c1e9SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
233c108c1e9SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
234c108c1e9SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for(ptr @_ZTIi)
235c108c1e9SHeejin Ahn  %matches = icmp eq i32 %3, %4
236c108c1e9SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
237c108c1e9SHeejin Ahn
238c108c1e9SHeejin Ahncatch:                                            ; preds = %catch.start
239c108c1e9SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
240c108c1e9SHeejin Ahn  %6 = load float, ptr %5, align 4
241c108c1e9SHeejin Ahn  invoke void @foo() [ "funclet"(token %1) ]
242c108c1e9SHeejin Ahn          to label %invoke.cont1 unwind label %ehcleanup
243c108c1e9SHeejin Ahn
244c108c1e9SHeejin Ahninvoke.cont1:                                     ; preds = %catch
245c108c1e9SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
246c108c1e9SHeejin Ahn  catchret from %1 to label %try.cont
247c108c1e9SHeejin Ahn
248c108c1e9SHeejin Ahnrethrow:                                          ; preds = %catch.start
249c108c1e9SHeejin Ahn  call void @llvm.wasm.rethrow() [ "funclet"(token %1) ]
250c108c1e9SHeejin Ahn  unreachable
251c108c1e9SHeejin Ahn
252c108c1e9SHeejin Ahntry.cont:                                         ; preds = %invoke.cont1, %entry
253c108c1e9SHeejin Ahn  ret void
254c108c1e9SHeejin Ahn
255c108c1e9SHeejin Ahnehcleanup:                                        ; preds = %catch
256c108c1e9SHeejin Ahn  %7 = cleanuppad within %1 []
257c108c1e9SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %7) ]
258c108c1e9SHeejin Ahn  cleanupret from %7 unwind to caller
259c108c1e9SHeejin Ahn}
260c108c1e9SHeejin Ahn
261c108c1e9SHeejin Ahn; When a function does not have stack-allocated objects, it does not need to
262c108c1e9SHeejin Ahn; store SP back to __stack_pointer global at the epilog.
263c108c1e9SHeejin Ahn;
264c108c1e9SHeejin Ahn; void foo();
2658b28e2ebSHeejin Ahn; void no_sp_writeback() {
266c108c1e9SHeejin Ahn;   try {
267c108c1e9SHeejin Ahn;     foo();
268c108c1e9SHeejin Ahn;   } catch (...) {
269c108c1e9SHeejin Ahn;   }
270c108c1e9SHeejin Ahn; }
271c108c1e9SHeejin Ahn
2728b28e2ebSHeejin Ahn; CHECK-LABEL: no_sp_writeback
273c108c1e9SHeejin Ahn; CHECK:     try
274c108c1e9SHeejin Ahn; CHECK:       call      foo
275c108c1e9SHeejin Ahn; CHECK:     catch
276c108c1e9SHeejin Ahn; CHECK:       call      $drop=, __cxa_begin_catch
277c108c1e9SHeejin Ahn; CHECK:       call      __cxa_end_catch
278c108c1e9SHeejin Ahn; CHECK:     end_try
279c108c1e9SHeejin Ahn; CHECK-NOT: global.set  __stack_pointer
280c108c1e9SHeejin Ahn; CHECK:     return
2818b28e2ebSHeejin Ahndefine void @no_sp_writeback() personality ptr @__gxx_wasm_personality_v0 {
282c108c1e9SHeejin Ahnentry:
283c108c1e9SHeejin Ahn  invoke void @foo()
284c108c1e9SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
285c108c1e9SHeejin Ahn
286c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %entry
287c108c1e9SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
288c108c1e9SHeejin Ahn
289c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
290c108c1e9SHeejin Ahn  %1 = catchpad within %0 [ptr null]
291c108c1e9SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
292c108c1e9SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
293c108c1e9SHeejin Ahn  %4 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
294c108c1e9SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
295c108c1e9SHeejin Ahn  catchret from %1 to label %try.cont
296c108c1e9SHeejin Ahn
297c108c1e9SHeejin Ahntry.cont:                                         ; preds = %catch.start, %entry
298c108c1e9SHeejin Ahn  ret void
299c108c1e9SHeejin Ahn}
300c108c1e9SHeejin Ahn
301c108c1e9SHeejin Ahn; When the result of @llvm.wasm.get.exception is not used. This is created to
302c108c1e9SHeejin Ahn; fix a bug in LateEHPrepare and this should not crash.
3038b28e2ebSHeejin Ahndefine void @get_exception_wo_use() personality ptr @__gxx_wasm_personality_v0 {
304c108c1e9SHeejin Ahnentry:
305c108c1e9SHeejin Ahn  invoke void @foo()
306c108c1e9SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
307c108c1e9SHeejin Ahn
308c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %entry
309c108c1e9SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind to caller
310c108c1e9SHeejin Ahn
311c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
312c108c1e9SHeejin Ahn  %1 = catchpad within %0 [ptr null]
313c108c1e9SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
314c108c1e9SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
315c108c1e9SHeejin Ahn  catchret from %1 to label %try.cont
316c108c1e9SHeejin Ahn
317c108c1e9SHeejin Ahntry.cont:                                         ; preds = %catch.start, %entry
318c108c1e9SHeejin Ahn  ret void
319c108c1e9SHeejin Ahn}
320c108c1e9SHeejin Ahn
321c108c1e9SHeejin Ahn; Tests a case when a cleanup region (cleanuppad ~ clanupret) contains another
322c108c1e9SHeejin Ahn; catchpad
3238b28e2ebSHeejin Ahndefine void @complex_cleanup_region() personality ptr @__gxx_wasm_personality_v0 {
324c108c1e9SHeejin Ahnentry:
325c108c1e9SHeejin Ahn  invoke void @foo()
326c108c1e9SHeejin Ahn          to label %invoke.cont unwind label %ehcleanup
327c108c1e9SHeejin Ahn
328c108c1e9SHeejin Ahninvoke.cont:                                      ; preds = %entry
329c108c1e9SHeejin Ahn  ret void
330c108c1e9SHeejin Ahn
331c108c1e9SHeejin Ahnehcleanup:                                        ; preds = %entry
332c108c1e9SHeejin Ahn  %0 = cleanuppad within none []
333c108c1e9SHeejin Ahn  invoke void @foo() [ "funclet"(token %0) ]
334c108c1e9SHeejin Ahn          to label %ehcleanupret unwind label %catch.dispatch
335c108c1e9SHeejin Ahn
336c108c1e9SHeejin Ahncatch.dispatch:                                   ; preds = %ehcleanup
337c108c1e9SHeejin Ahn  %1 = catchswitch within %0 [label %catch.start] unwind label %ehcleanup.1
338c108c1e9SHeejin Ahn
339c108c1e9SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
340c108c1e9SHeejin Ahn  %2 = catchpad within %1 [ptr null]
341c108c1e9SHeejin Ahn  %3 = call ptr @llvm.wasm.get.exception(token %2)
342c108c1e9SHeejin Ahn  %4 = call i32 @llvm.wasm.get.ehselector(token %2)
343c108c1e9SHeejin Ahn  catchret from %2 to label %ehcleanupret
344c108c1e9SHeejin Ahn
345c108c1e9SHeejin Ahnehcleanup.1:                                      ; preds = %catch.dispatch
346c108c1e9SHeejin Ahn  %5 = cleanuppad within %0 []
347c108c1e9SHeejin Ahn  unreachable
348c108c1e9SHeejin Ahn
349c108c1e9SHeejin Ahnehcleanupret:                                     ; preds = %catch.start, %ehcleanup
350c108c1e9SHeejin Ahn  cleanupret from %0 unwind to caller
351c108c1e9SHeejin Ahn}
352c108c1e9SHeejin Ahn
3533c8f3b91SHeejin Ahn; Regression test for the bug that 'rethrow' was not treated correctly as a
3543c8f3b91SHeejin Ahn; terminator in isel.
3558b28e2ebSHeejin Ahndefine void @rethrow_terminator() personality ptr @__gxx_wasm_personality_v0 {
3563c8f3b91SHeejin Ahnentry:
3573c8f3b91SHeejin Ahn  invoke void @foo()
3583c8f3b91SHeejin Ahn          to label %try.cont unwind label %catch.dispatch
3593c8f3b91SHeejin Ahn
3603c8f3b91SHeejin Ahncatch.dispatch:                                   ; preds = %entry
3613c8f3b91SHeejin Ahn  %0 = catchswitch within none [label %catch.start] unwind label %ehcleanup
3623c8f3b91SHeejin Ahn
3633c8f3b91SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
3643c8f3b91SHeejin Ahn  %1 = catchpad within %0 [ptr @_ZTIi]
3653c8f3b91SHeejin Ahn  %2 = call ptr @llvm.wasm.get.exception(token %1)
3663c8f3b91SHeejin Ahn  %3 = call i32 @llvm.wasm.get.ehselector(token %1)
3673c8f3b91SHeejin Ahn  %4 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
3683c8f3b91SHeejin Ahn  %matches = icmp eq i32 %3, %4
3693c8f3b91SHeejin Ahn  br i1 %matches, label %catch, label %rethrow
3703c8f3b91SHeejin Ahn
3713c8f3b91SHeejin Ahncatch:                                            ; preds = %catch.start
3723c8f3b91SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %2) [ "funclet"(token %1) ]
3733c8f3b91SHeejin Ahn  %6 = load i32, ptr %5, align 4
3743c8f3b91SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %1) ]
3753c8f3b91SHeejin Ahn  catchret from %1 to label %try.cont
3763c8f3b91SHeejin Ahn
3773c8f3b91SHeejin Ahnrethrow:                                          ; preds = %catch.start
3783c8f3b91SHeejin Ahn  invoke void @llvm.wasm.rethrow() #1 [ "funclet"(token %1) ]
3793c8f3b91SHeejin Ahn          to label %unreachable unwind label %ehcleanup
3803c8f3b91SHeejin Ahn
3813c8f3b91SHeejin Ahntry.cont:                                         ; preds = %entry, %catch
3823c8f3b91SHeejin Ahn  ret void
3833c8f3b91SHeejin Ahn
3843c8f3b91SHeejin Ahnehcleanup:                                        ; preds = %rethrow, %catch.dispatch
3853c8f3b91SHeejin Ahn  ; 'rethrow' BB is this BB's predecessor, and its
3863c8f3b91SHeejin Ahn  ; 'invoke void @llvm.wasm.rethrow()' is lowered down to a 'RETHROW' in Wasm
3873c8f3b91SHeejin Ahn  ; MIR. And this 'phi' creates 'CONST_I32' instruction in the predecessor
3883c8f3b91SHeejin Ahn  ; 'rethrow' BB. If 'RETHROW' is not treated correctly as a terminator, it can
3893c8f3b91SHeejin Ahn  ; create a BB like
3903c8f3b91SHeejin Ahn  ; bb.3.rethrow:
3913c8f3b91SHeejin Ahn  ;   RETHROW 0
3923c8f3b91SHeejin Ahn  ;   %0 = CONST_I32 20
3933c8f3b91SHeejin Ahn  ;   BR ...
3943c8f3b91SHeejin Ahn  %tmp = phi i32 [ 10, %catch.dispatch ], [ 20, %rethrow ]
3953c8f3b91SHeejin Ahn  %7 = cleanuppad within none []
3963c8f3b91SHeejin Ahn  call void @take_i32(i32 %tmp) [ "funclet"(token %7) ]
3973c8f3b91SHeejin Ahn  cleanupret from %7 unwind to caller
3983c8f3b91SHeejin Ahn
3993c8f3b91SHeejin Ahnunreachable:                                      ; preds = %rethrow
4003c8f3b91SHeejin Ahn  unreachable
4013c8f3b91SHeejin Ahn}
4023c8f3b91SHeejin Ahn
403492812f6SHeejin Ahn; The bitcode below is generated when the code below is compiled and
404492812f6SHeejin Ahn; Temp::~Temp() is inlined into inlined_cleanupret():
405492812f6SHeejin Ahn;
406492812f6SHeejin Ahn; void inlined_cleanupret() {
407492812f6SHeejin Ahn; try {
408492812f6SHeejin Ahn;   Temp t;
409492812f6SHeejin Ahn;   throw 2;
410492812f6SHeejin Ahn; } catch (...)
411492812f6SHeejin Ahn; }
412492812f6SHeejin Ahn;
413492812f6SHeejin Ahn; Temp::~Temp() {
414492812f6SHeejin Ahn;   try {
415492812f6SHeejin Ahn;     throw 1;
416492812f6SHeejin Ahn;   } catch (...) {
417492812f6SHeejin Ahn;   }
418492812f6SHeejin Ahn; }
419492812f6SHeejin Ahn;
420492812f6SHeejin Ahn; ~Temp() generates cleanupret, which is lowered to a 'rethrow' later. That
421492812f6SHeejin Ahn; rethrow's immediate argument should correctly target the top-level cleanuppad
422492812f6SHeejin Ahn; (catch_all). This is a regression test for the bug where we did not compute
423492812f6SHeejin Ahn; rethrow's argument correctly.
424492812f6SHeejin Ahn
425492812f6SHeejin Ahn; CHECK-LABEL: inlined_cleanupret:
426492812f6SHeejin Ahn; CHECK: try
427492812f6SHeejin Ahn; CHECK:   call  __cxa_throw
428492812f6SHeejin Ahn; CHECK: catch_all
429492812f6SHeejin Ahn; CHECK:   try
430492812f6SHeejin Ahn; CHECK:     try
431492812f6SHeejin Ahn; CHECK:       call  __cxa_throw
432492812f6SHeejin Ahn; CHECK:       catch
433492812f6SHeejin Ahn; CHECK:       call  __cxa_end_catch
434492812f6SHeejin Ahn; CHECK:       try
435492812f6SHeejin Ahn; CHECK:         try
436492812f6SHeejin Ahn; Note that this rethrow targets the top-level catch_all
437492812f6SHeejin Ahn; CHECK:           rethrow   4
438492812f6SHeejin Ahn; CHECK:         catch
439492812f6SHeejin Ahn; CHECK:           try
440492812f6SHeejin Ahn; CHECK:             call  __cxa_end_catch
441492812f6SHeejin Ahn; CHECK:           delegate    5
442492812f6SHeejin Ahn; CHECK:           return
443492812f6SHeejin Ahn; CHECK:         end_try
444492812f6SHeejin Ahn; CHECK:       delegate    3
445492812f6SHeejin Ahn; CHECK:     end_try
446492812f6SHeejin Ahn; CHECK:   catch_all
447492812f6SHeejin Ahn; CHECK:     call  _ZSt9terminatev
448492812f6SHeejin Ahn; CHECK:   end_try
449492812f6SHeejin Ahn; CHECK: end_try
450492812f6SHeejin Ahndefine void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {
451492812f6SHeejin Ahnentry:
452492812f6SHeejin Ahn  %exception = tail call ptr @__cxa_allocate_exception(i32 4)
453492812f6SHeejin Ahn  store i32 2, ptr %exception, align 16
454492812f6SHeejin Ahn  invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null)
455492812f6SHeejin Ahn          to label %unreachable unwind label %ehcleanup
456492812f6SHeejin Ahn
457492812f6SHeejin Ahnehcleanup:                                        ; preds = %entry
458492812f6SHeejin Ahn  %0 = cleanuppad within none []
459492812f6SHeejin Ahn  %exception.i = call ptr @__cxa_allocate_exception(i32 4) [ "funclet"(token %0) ]
460492812f6SHeejin Ahn  store i32 1, ptr %exception.i, align 16
461492812f6SHeejin Ahn  invoke void @__cxa_throw(ptr nonnull %exception.i, ptr nonnull @_ZTIi, ptr null) [ "funclet"(token %0) ]
462492812f6SHeejin Ahn          to label %unreachable unwind label %catch.dispatch.i
463492812f6SHeejin Ahn
464492812f6SHeejin Ahncatch.dispatch.i:                                 ; preds = %ehcleanup
465492812f6SHeejin Ahn  %1 = catchswitch within %0 [label %catch.start.i] unwind label %terminate.i
466492812f6SHeejin Ahn
467492812f6SHeejin Ahncatch.start.i:                                    ; preds = %catch.dispatch.i
468492812f6SHeejin Ahn  %2 = catchpad within %1 [ptr null]
469492812f6SHeejin Ahn  %3 = tail call ptr @llvm.wasm.get.exception(token %2)
470492812f6SHeejin Ahn  %4 = tail call i32 @llvm.wasm.get.ehselector(token %2)
471492812f6SHeejin Ahn  %5 = call ptr @__cxa_begin_catch(ptr %3) [ "funclet"(token %2) ]
472492812f6SHeejin Ahn  invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
473492812f6SHeejin Ahn          to label %invoke.cont.i unwind label %terminate.i
474492812f6SHeejin Ahn
475492812f6SHeejin Ahninvoke.cont.i:                                    ; preds = %catch.start.i
476492812f6SHeejin Ahn  catchret from %2 to label %_ZN4TempD2Ev.exit
477492812f6SHeejin Ahn
478492812f6SHeejin Ahnterminate.i:                                      ; preds = %catch.start.i, %catch.dispatch.i
479492812f6SHeejin Ahn  %6 = cleanuppad within %0 []
480492812f6SHeejin Ahn  call void @_ZSt9terminatev() [ "funclet"(token %6) ]
481492812f6SHeejin Ahn  unreachable
482492812f6SHeejin Ahn
483492812f6SHeejin Ahn_ZN4TempD2Ev.exit:                                ; preds = %invoke.cont.i
484492812f6SHeejin Ahn  cleanupret from %0 unwind label %catch.dispatch
485492812f6SHeejin Ahn
486492812f6SHeejin Ahncatch.dispatch:                                   ; preds = %_ZN4TempD2Ev.exit
487492812f6SHeejin Ahn  %7 = catchswitch within none [label %catch.start] unwind to caller
488492812f6SHeejin Ahn
489492812f6SHeejin Ahncatch.start:                                      ; preds = %catch.dispatch
490492812f6SHeejin Ahn  %8 = catchpad within %7 [ptr null]
491492812f6SHeejin Ahn  %9 = tail call ptr @llvm.wasm.get.exception(token %8)
492492812f6SHeejin Ahn  %10 = tail call i32 @llvm.wasm.get.ehselector(token %8)
493492812f6SHeejin Ahn  %11 = call ptr @__cxa_begin_catch(ptr %9) #8 [ "funclet"(token %8) ]
494492812f6SHeejin Ahn  call void @__cxa_end_catch() [ "funclet"(token %8) ]
495492812f6SHeejin Ahn  catchret from %8 to label %try.cont
496492812f6SHeejin Ahn
497492812f6SHeejin Ahntry.cont:                                         ; preds = %catch.start
498492812f6SHeejin Ahn  ret void
499492812f6SHeejin Ahn
500492812f6SHeejin Ahnunreachable:                                      ; preds = %entry
501492812f6SHeejin Ahn  unreachable
502492812f6SHeejin Ahn}
503492812f6SHeejin Ahn
5043c8f3b91SHeejin Ahn
505c108c1e9SHeejin Ahndeclare void @foo()
506c108c1e9SHeejin Ahndeclare void @bar(ptr)
5073c8f3b91SHeejin Ahndeclare void @take_i32(i32)
508c108c1e9SHeejin Ahndeclare i32 @__gxx_wasm_personality_v0(...)
509c108c1e9SHeejin Ahn; Function Attrs: noreturn
510c108c1e9SHeejin Ahndeclare void @llvm.wasm.throw(i32, ptr) #1
511c108c1e9SHeejin Ahn; Function Attrs: nounwind
512c108c1e9SHeejin Ahndeclare ptr @llvm.wasm.get.exception(token) #0
513c108c1e9SHeejin Ahn; Function Attrs: nounwind
514c108c1e9SHeejin Ahndeclare i32 @llvm.wasm.get.ehselector(token) #0
515c108c1e9SHeejin Ahn; Function Attrs: noreturn
516c108c1e9SHeejin Ahndeclare void @llvm.wasm.rethrow() #1
517c108c1e9SHeejin Ahn; Function Attrs: nounwind
518c108c1e9SHeejin Ahndeclare i32 @llvm.eh.typeid.for(ptr) #0
519492812f6SHeejin Ahn; Function Attrs: nounwind
520492812f6SHeejin Ahndeclare ptr @__cxa_allocate_exception(i32) #0
521c108c1e9SHeejin Ahndeclare ptr @__cxa_begin_catch(ptr)
522c108c1e9SHeejin Ahndeclare void @__cxa_end_catch()
523492812f6SHeejin Ahn; Function Attrs: noreturn
524492812f6SHeejin Ahndeclare void @__cxa_throw(ptr, ptr, ptr) #1
525c108c1e9SHeejin Ahndeclare void @_ZSt9terminatev()
526c108c1e9SHeejin Ahndeclare ptr @_ZN4TempD2Ev(ptr returned)
527c108c1e9SHeejin Ahn
528c108c1e9SHeejin Ahnattributes #0 = { nounwind }
529c108c1e9SHeejin Ahnattributes #1 = { noreturn }
530c108c1e9SHeejin Ahn
531c108c1e9SHeejin Ahn; CHECK: __cpp_exception:
532