[IRBuilder] Add Align argument for CreateMaskedExpandLoad and CreateMaskedCompressSto...
[llvm-project.git] / llvm / test / CodeGen / WebAssembly / lower-em-ehsjlj.ll
blob32942cd92e684f880188fdce1d34e4d854071302
1 ; RUN: opt < %s -wasm-lower-em-ehsjlj -enable-emscripten-cxx-exceptions -enable-emscripten-sjlj -S | FileCheck %s
2 ; RUN: llc < %s -enable-emscripten-cxx-exceptions -enable-emscripten-sjlj -verify-machineinstrs
4 ; Tests for cases when exception handling and setjmp/longjmp handling are mixed.
6 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
7 target triple = "wasm32-unknown-unknown"
9 %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
10 @_ZTIi = external constant ptr
12 ; There is a function call (@foo) that can either throw an exception or longjmp
13 ; and there is also a setjmp call. When @foo throws, we have to check both for
14 ; exception and longjmp and jump to exception or longjmp handling BB depending
15 ; on the result.
16 define void @setjmp_longjmp_exception() personality ptr @__gxx_personality_v0 {
17 ; CHECK-LABEL: @setjmp_longjmp_exception
18 entry:
19   %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
20   %call = call i32 @setjmp(ptr %buf) #0
21   invoke void @foo()
22           to label %try.cont unwind label %lpad
24 ; CHECK:    entry.split.split:
25 ; CHECK:      %[[CMP0:.*]] = icmp ne i32 %__THREW__.val, 0
26 ; CHECK-NEXT: %__threwValue.val = load i32, ptr @__threwValue
27 ; CHECK-NEXT: %[[CMP1:.*]] = icmp ne i32 %__threwValue.val, 0
28 ; CHECK-NEXT: %[[CMP:.*]] = and i1 %[[CMP0]], %[[CMP1]]
29 ; CHECK-NEXT: br i1 %[[CMP]], label %if.then1, label %if.else1
31 ; This is exception checking part. %if.else1 leads here
32 ; CHECK:    entry.split.split.split:
33 ; CHECK-NEXT: %[[CMP:.*]] = icmp eq i32 %__THREW__.val, 1
34 ; CHECK-NEXT: br i1 %[[CMP]], label %lpad, label %try.cont
36 ; CHECK:    lpad:
37 lpad:                                             ; preds = %entry
38   %0 = landingpad { ptr, i32 }
39           catch ptr null
40   %1 = extractvalue { ptr, i32 } %0, 0
41   %2 = extractvalue { ptr, i32 } %0, 1
42 ; CHECK-NOT:  call {{.*}} void @__invoke_void(ptr @__cxa_end_catch)
43   %3 = call ptr @__cxa_begin_catch(ptr %1) #2
44   call void @__cxa_end_catch()
45   br label %try.cont
47 try.cont:                                         ; preds = %lpad, %entry
48   ret void
50 ; longjmp checking part
51 ; CHECK:    if.then1:
52 ; CHECK:      call i32 @__wasm_setjmp_test
55 ; @foo can either throw an exception or longjmp. Because this function doesn't
56 ; have any setjmp calls, we only handle exceptions in this function. But because
57 ; sjlj is enabled, we check if the thrown value is longjmp and if so rethrow it
58 ; by calling @emscripten_longjmp.
59 define void @rethrow_longjmp() personality ptr @__gxx_personality_v0 {
60 ; CHECK-LABEL: @rethrow_longjmp
61 entry:
62   invoke void @foo()
63           to label %try.cont unwind label %lpad
64 ; CHECK:    entry:
65 ; CHECK:      %cmp.eq.one = icmp eq i32 %__THREW__.val, 1
66 ; CHECK-NEXT: %cmp.eq.zero = icmp eq i32 %__THREW__.val, 0
67 ; CHECK-NEXT: %or = or i1 %cmp.eq.zero, %cmp.eq.one
68 ; CHECK-NEXT: br i1 %or, label %tail, label %rethrow.longjmp
70 ; CHECK: try.cont:
71 ; CHECK-NEXT:  %phi = phi i32 [ undef, %tail ], [ undef, %lpad ]
72 ; CHECK-NEXT:  ret void
74 ; CHECK:    rethrow.longjmp:
75 ; CHECK-NEXT: %threw.phi = phi i32 [ %__THREW__.val, %entry ]
76 ; CHECK-NEXT: %__threwValue.val = load i32, ptr @__threwValue, align 4
77 ; CHECK-NEXT: call void @emscripten_longjmp(i32 %threw.phi, i32 %__threwValue.val
78 ; CHECK-NEXT: unreachable
80 ; CHECK:    tail:
81 ; CHECK-NEXT: %cmp = icmp eq i32 %__THREW__.val, 1
82 ; CHECK-NEXT: br i1 %cmp, label %lpad, label %try.cont
84 lpad:                                             ; preds = %entry
85   %0 = landingpad { ptr, i32 }
86           catch ptr null
87   %1 = extractvalue { ptr, i32 } %0, 0
88   %2 = extractvalue { ptr, i32 } %0, 1
89   %3 = call ptr @__cxa_begin_catch(ptr %1) #5
90   call void @__cxa_end_catch()
91   br label %try.cont
93 try.cont:                                         ; preds = %lpad, %entry
94  %phi = phi i32 [ undef, %entry ], [ undef, %lpad ]
95   ret void
98 ; This function contains a setjmp call and no invoke, so we only handle longjmp
99 ; here. But @foo can also throw an exception, so we check if an exception is
100 ; thrown and if so rethrow it by calling @__resumeException. Also we have to
101 ; free the setjmpTable buffer before calling @__resumeException.
102 define void @rethrow_exception() {
103 ; CHECK-LABEL: @rethrow_exception
104 entry:
105   %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
106   %call = call i32 @setjmp(ptr %buf) #0
107   %cmp = icmp ne i32 %call, 0
108   br i1 %cmp, label %return, label %if.end
110 if.end:                                           ; preds = %entry
111   call void @foo()
112   br label %return
114 ; CHECK:    if.end:
115 ; CHECK:      %cmp.eq.one = icmp eq i32 %__THREW__.val, 1
116 ; CHECK-NEXT: br i1 %cmp.eq.one, label %rethrow.exn, label %normal
118 ; CHECK:    rethrow.exn:
119 ; CHECK-NEXT: %exn = call ptr @__cxa_find_matching_catch_2()
120 ; CHECK-NEXT: call void @__resumeException(ptr %exn)
121 ; CHECK-NEXT: unreachable
123 ; CHECK:    normal:
124 ; CHECK-NEXT: icmp ne i32 %__THREW__.val, 0
126 return:                                           ; preds = %if.end, %entry
127   ret void
130 ; The same as 'rethrow_exception' but contains a __cxa_throw call. We have to
131 ; free the setjmpTable buffer before calling __cxa_throw.
132 define void @rethrow_exception2() {
133 ; CHECK-LABEL: @rethrow_exception2
134 entry:
135   %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
136   %call = call i32 @setjmp(ptr %buf) #0
137   %cmp = icmp ne i32 %call, 0
138   br i1 %cmp, label %throw, label %if.end
140 if.end:                                           ; preds = %entry
141   call void @foo()
142   br label %throw
144 throw:                                            ; preds = %if.end, %entry
145   call void @__cxa_throw(ptr null, ptr null, ptr null) #1
146   unreachable
148 ; CHECK:    throw:
149 ; CHECK-NEXT: call void @__cxa_throw(ptr null, ptr null, ptr null)
150 ; CHECK-NEXT: unreachable
153 ; The same case with @rethrow_longjmp, but there are multiple function calls
154 ; that can possibly longjmp (instead of throwing exception) so we have to
155 ; rethrow them. Here we test if we correclty generate only one 'rethrow.longjmp'
156 ; BB and share it for multiple calls.
157 define void @rethrow_longjmp_multi() personality ptr @__gxx_personality_v0 {
158 ; CHECK-LABEL: @rethrow_longjmp_multi
159 entry:
160   invoke void @foo()
161           to label %bb unwind label %lpad
163 bb:                                               ; preds = %entry
164   invoke void @foo()
165           to label %try.cont unwind label %lpad
167 lpad:                                             ; preds = %bb, %entry
168   %0 = landingpad { ptr, i32 }
169           catch ptr null
170   %1 = extractvalue { ptr, i32 } %0, 0
171   %2 = extractvalue { ptr, i32 } %0, 1
172   %3 = call ptr @__cxa_begin_catch(ptr %1) #5
173   call void @__cxa_end_catch()
174   br label %try.cont
176 try.cont:                                         ; preds = %lpad, %bb
177  %phi = phi i32 [ undef, %bb ], [ undef, %lpad ]
178   ret void
180 ; CHECK:    rethrow.longjmp:
181 ; CHECK-NEXT: %threw.phi = phi i32 [ %__THREW__.val, %entry ], [ %__THREW__.val1, %bb ]
182 ; CHECK-NEXT: %__threwValue.val = load i32, ptr @__threwValue, align 4
183 ; CHECK-NEXT: call void @emscripten_longjmp(i32 %threw.phi, i32 %__threwValue.val)
184 ; CHECK-NEXT: unreachable
187 ; The same case with @rethrow_exception, but there are multiple function calls
188 ; that can possibly throw (instead of longjmping) so we have to rethrow them.
189 ; Here we test if correctly we generate only one 'rethrow.exn' BB and share it
190 ; for multiple calls.
191 define void @rethrow_exception_multi() {
192 ; CHECK-LABEL: @rethrow_exception_multi
193 entry:
194   %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
195   %call = call i32 @setjmp(ptr %buf) #0
196   %cmp = icmp ne i32 %call, 0
197   br i1 %cmp, label %return, label %if.end
199 if.end:                                           ; preds = %entry
200   call void @foo()
201   call void @foo()
202   br label %return
204 return:                                           ; preds = %entry, %if.end
205   ret void
207 ; CHECK:    rethrow.exn:
208 ; CHECK-NEXT: %exn = call ptr @__cxa_find_matching_catch_2()
209 ; CHECK-NEXT: call void @__resumeException(ptr %exn)
210 ; CHECK-NEXT: unreachable
213 ; int jmpval = setjmp(buf);
214 ; if (jmpval != 0)
215 ;   return;
216 ; try {
217 ;   throw 3;
218 ; } catch (...) {
219 ; }
220 define void @setjmp_with_throw_try_catch() personality ptr @__gxx_personality_v0 {
221 ; CHECK-LABEL: @setjmp_with_throw_try_catch
222 entry:
223   %buf = alloca [1 x %struct.__jmp_buf_tag], align 16
224   %call = call i32 @setjmp(ptr %buf) #0
225   %cmp = icmp ne i32 %call, 0
226   br i1 %cmp, label %try.cont, label %if.end
228 if.end:                                           ; preds = %entry
229   %exception = call ptr @__cxa_allocate_exception(i32 4) #2
230   store i32 3, ptr %exception, align 16
231   invoke void @__cxa_throw(ptr %exception, ptr @_ZTIi, ptr null) #1
232           to label %unreachable unwind label %lpad
233 ; When invoke @__cxa_throw is converted to a call to the invoke wrapper,
234 ; "noreturn" attribute should be removed, and there should be no 'free' call
235 ; before the call. We insert a 'free' call that frees 'setjmpTable' before every
236 ; function-exiting instruction. And invoke wrapper calls shouldn't be treated as
237 ; noreturn instructions, because they are supposed to return.
238 ; CHECK:   if.end:
239 ; CHECK-NOT: tail call void @free
240 ; CHECK-NOT: call cc99 void @__invoke_void_ptr_ptr_ptr(ptr @__cxa_throw, ptr %exception, ptr @_ZTIi, ptr null) #
241 ; CHECK:     call cc99 void @__invoke_void_ptr_ptr_ptr(ptr @__cxa_throw, ptr %exception, ptr @_ZTIi, ptr null)
243 lpad:                                             ; preds = %if.end
244   %0 = landingpad { ptr, i32 }
245           catch ptr null
246   %1 = extractvalue { ptr, i32 } %0, 0
247   %2 = extractvalue { ptr, i32 } %0, 1
248   %3 = call ptr @__cxa_begin_catch(ptr %1) #2
249   call void @__cxa_end_catch()
250   br label %try.cont
252 try.cont:                                         ; preds = %entry, %lpad
253   ret void
255 unreachable:                                      ; preds = %if.end
256   unreachable
259 declare void @foo()
260 ; Function Attrs: returns_twice
261 declare i32 @setjmp(ptr)
262 ; Function Attrs: noreturn
263 declare void @longjmp(ptr, i32)
264 declare i32 @__gxx_personality_v0(...)
265 declare ptr @__cxa_begin_catch(ptr)
266 declare void @__cxa_end_catch()
267 declare void @__cxa_throw(ptr, ptr, ptr)
268 declare ptr @__cxa_allocate_exception(i32)
270 attributes #0 = { returns_twice }
271 attributes #1 = { noreturn }
272 attributes #2 = { nounwind }