1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+nontrapping-fptoint | FileCheck %s
2
3; Test that basic conversion operations assemble as expected.
4
5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6target triple = "wasm32-unknown-unknown"
7
8; CHECK-LABEL: i32_wrap_i64:
9; CHECK-NEXT: .param i64{{$}}
10; CHECK-NEXT: .result i32{{$}}
11; CHECK-NEXT: i32.wrap/i64 $push[[NUM:[0-9]+]]=, $0{{$}}
12; CHECK-NEXT: return $pop[[NUM]]{{$}}
13define i32 @i32_wrap_i64(i64 %x) {
14  %a = trunc i64 %x to i32
15  ret i32 %a
16}
17
18; CHECK-LABEL: i64_extend_s_i32:
19; CHECK-NEXT: .param i32{{$}}
20; CHECK-NEXT: .result i64{{$}}
21; CHECK-NEXT: i64.extend_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
22; CHECK-NEXT: return $pop[[NUM]]{{$}}
23define i64 @i64_extend_s_i32(i32 %x) {
24  %a = sext i32 %x to i64
25  ret i64 %a
26}
27
28; CHECK-LABEL: i64_extend_u_i32:
29; CHECK-NEXT: .param i32{{$}}
30; CHECK-NEXT: .result i64{{$}}
31; CHECK-NEXT: i64.extend_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
32; CHECK-NEXT: return $pop[[NUM]]{{$}}
33define i64 @i64_extend_u_i32(i32 %x) {
34  %a = zext i32 %x to i64
35  ret i64 %a
36}
37
38; CHECK-LABEL: i32_trunc_s_f32:
39; CHECK-NEXT: .param f32{{$}}
40; CHECK-NEXT: .result i32{{$}}
41; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
42; CHECK-NEXT: return $pop[[NUM]]{{$}}
43define i32 @i32_trunc_s_f32(float %x) {
44  %a = fptosi float %x to i32
45  ret i32 %a
46}
47
48; CHECK-LABEL: i32_trunc_sat_s_f32:
49; CHECK-NEXT: .param f32{{$}}
50; CHECK-NEXT: .result i32{{$}}
51; CHECK-NEXT: i32.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
52; CHECK-NEXT: return $pop[[NUM]]{{$}}
53declare i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float)
54define i32 @i32_trunc_sat_s_f32(float %x) {
55  %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f32(float %x)
56  ret i32 %a
57}
58
59; CHECK-LABEL: i32_trunc_u_f32:
60; CHECK-NEXT: .param f32{{$}}
61; CHECK-NEXT: .result i32{{$}}
62; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
63; CHECK-NEXT: return $pop[[NUM]]{{$}}
64define i32 @i32_trunc_u_f32(float %x) {
65  %a = fptoui float %x to i32
66  ret i32 %a
67}
68
69; CHECK-LABEL: i32_trunc_sat_u_f32:
70; CHECK-NEXT: .param f32{{$}}
71; CHECK-NEXT: .result i32{{$}}
72; CHECK-NEXT: i32.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
73; CHECK-NEXT: return $pop[[NUM]]{{$}}
74declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float)
75define i32 @i32_trunc_sat_u_f32(float %x) {
76  %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f32(float %x)
77  ret i32 %a
78}
79
80; CHECK-LABEL: i32_trunc_s_f64:
81; CHECK-NEXT: .param f64{{$}}
82; CHECK-NEXT: .result i32{{$}}
83; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
84; CHECK-NEXT: return $pop[[NUM]]{{$}}
85define i32 @i32_trunc_s_f64(double %x) {
86  %a = fptosi double %x to i32
87  ret i32 %a
88}
89
90; CHECK-LABEL: i32_trunc_sat_s_f64:
91; CHECK-NEXT: .param f64{{$}}
92; CHECK-NEXT: .result i32{{$}}
93; CHECK-NEXT: i32.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
94; CHECK-NEXT: return $pop[[NUM]]{{$}}
95declare i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double)
96define i32 @i32_trunc_sat_s_f64(double %x) {
97  %a = call i32 @llvm.wasm.trunc.saturate.signed.i32.f64(double %x)
98  ret i32 %a
99}
100
101; CHECK-LABEL: i32_trunc_u_f64:
102; CHECK-NEXT: .param f64{{$}}
103; CHECK-NEXT: .result i32{{$}}
104; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
105; CHECK-NEXT: return $pop[[NUM]]{{$}}
106define i32 @i32_trunc_u_f64(double %x) {
107  %a = fptoui double %x to i32
108  ret i32 %a
109}
110
111; CHECK-LABEL: i32_trunc_sat_u_f64:
112; CHECK-NEXT: .param f64{{$}}
113; CHECK-NEXT: .result i32{{$}}
114; CHECK-NEXT: i32.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
115; CHECK-NEXT: return $pop[[NUM]]{{$}}
116declare i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double)
117define i32 @i32_trunc_sat_u_f64(double %x) {
118  %a = call i32 @llvm.wasm.trunc.saturate.unsigned.i32.f64(double %x)
119  ret i32 %a
120}
121
122; CHECK-LABEL: i64_trunc_s_f32:
123; CHECK-NEXT: .param f32{{$}}
124; CHECK-NEXT: .result i64{{$}}
125; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
126; CHECK-NEXT: return $pop[[NUM]]{{$}}
127define i64 @i64_trunc_s_f32(float %x) {
128  %a = fptosi float %x to i64
129  ret i64 %a
130}
131
132; CHECK-LABEL: i64_trunc_sat_s_f32:
133; CHECK-NEXT: .param f32{{$}}
134; CHECK-NEXT: .result i64{{$}}
135; CHECK-NEXT: i64.trunc_s:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
136; CHECK-NEXT: return $pop[[NUM]]{{$}}
137declare i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float)
138define i64 @i64_trunc_sat_s_f32(float %x) {
139  %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f32(float %x)
140  ret i64 %a
141}
142
143; CHECK-LABEL: i64_trunc_u_f32:
144; CHECK-NEXT: .param f32{{$}}
145; CHECK-NEXT: .result i64{{$}}
146; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
147; CHECK-NEXT: return $pop[[NUM]]{{$}}
148define i64 @i64_trunc_u_f32(float %x) {
149  %a = fptoui float %x to i64
150  ret i64 %a
151}
152
153; CHECK-LABEL: i64_trunc_sat_u_f32:
154; CHECK-NEXT: .param f32{{$}}
155; CHECK-NEXT: .result i64{{$}}
156; CHECK-NEXT: i64.trunc_u:sat/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
157; CHECK-NEXT: return $pop[[NUM]]{{$}}
158declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float)
159define i64 @i64_trunc_sat_u_f32(float %x) {
160  %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f32(float %x)
161  ret i64 %a
162}
163
164; CHECK-LABEL: i64_trunc_s_f64:
165; CHECK-NEXT: .param f64{{$}}
166; CHECK-NEXT: .result i64{{$}}
167; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
168; CHECK-NEXT: return $pop[[NUM]]{{$}}
169define i64 @i64_trunc_s_f64(double %x) {
170  %a = fptosi double %x to i64
171  ret i64 %a
172}
173
174; CHECK-LABEL: i64_trunc_sat_s_f64:
175; CHECK-NEXT: .param f64{{$}}
176; CHECK-NEXT: .result i64{{$}}
177; CHECK-NEXT: i64.trunc_s:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
178; CHECK-NEXT: return $pop[[NUM]]{{$}}
179declare i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double)
180define i64 @i64_trunc_sat_s_f64(double %x) {
181  %a = call i64 @llvm.wasm.trunc.saturate.signed.i64.f64(double %x)
182  ret i64 %a
183}
184
185; CHECK-LABEL: i64_trunc_u_f64:
186; CHECK-NEXT: .param f64{{$}}
187; CHECK-NEXT: .result i64{{$}}
188; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
189; CHECK-NEXT: return $pop[[NUM]]{{$}}
190define i64 @i64_trunc_u_f64(double %x) {
191  %a = fptoui double %x to i64
192  ret i64 %a
193}
194
195; CHECK-LABEL: i64_trunc_sat_u_f64:
196; CHECK-NEXT: .param f64{{$}}
197; CHECK-NEXT: .result i64{{$}}
198; CHECK-NEXT: i64.trunc_u:sat/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
199; CHECK-NEXT: return $pop[[NUM]]{{$}}
200declare i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double)
201define i64 @i64_trunc_sat_u_f64(double %x) {
202  %a = call i64 @llvm.wasm.trunc.saturate.unsigned.i64.f64(double %x)
203  ret i64 %a
204}
205
206; CHECK-LABEL: f32_convert_s_i32:
207; CHECK-NEXT: .param i32{{$}}
208; CHECK-NEXT: .result f32{{$}}
209; CHECK-NEXT: f32.convert_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
210; CHECK-NEXT: return $pop[[NUM]]{{$}}
211define float @f32_convert_s_i32(i32 %x) {
212  %a = sitofp i32 %x to float
213  ret float %a
214}
215
216; CHECK-LABEL: f32_convert_u_i32:
217; CHECK-NEXT: .param i32{{$}}
218; CHECK-NEXT: .result f32{{$}}
219; CHECK-NEXT: f32.convert_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
220; CHECK-NEXT: return $pop[[NUM]]{{$}}
221define float @f32_convert_u_i32(i32 %x) {
222  %a = uitofp i32 %x to float
223  ret float %a
224}
225
226; CHECK-LABEL: f64_convert_s_i32:
227; CHECK-NEXT: .param i32{{$}}
228; CHECK-NEXT: .result f64{{$}}
229; CHECK-NEXT: f64.convert_s/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
230; CHECK-NEXT: return $pop[[NUM]]{{$}}
231define double @f64_convert_s_i32(i32 %x) {
232  %a = sitofp i32 %x to double
233  ret double %a
234}
235
236; CHECK-LABEL: f64_convert_u_i32:
237; CHECK-NEXT: .param i32{{$}}
238; CHECK-NEXT: .result f64{{$}}
239; CHECK-NEXT: f64.convert_u/i32 $push[[NUM:[0-9]+]]=, $0{{$}}
240; CHECK-NEXT: return $pop[[NUM]]{{$}}
241define double @f64_convert_u_i32(i32 %x) {
242  %a = uitofp i32 %x to double
243  ret double %a
244}
245
246; CHECK-LABEL: f32_convert_s_i64:
247; CHECK-NEXT: .param i64{{$}}
248; CHECK-NEXT: .result f32{{$}}
249; CHECK-NEXT: f32.convert_s/i64 $push[[NUM:[0-9]+]]=, $0{{$}}
250; CHECK-NEXT: return $pop[[NUM]]{{$}}
251define float @f32_convert_s_i64(i64 %x) {
252  %a = sitofp i64 %x to float
253  ret float %a
254}
255
256; CHECK-LABEL: f32_convert_u_i64:
257; CHECK-NEXT: .param i64{{$}}
258; CHECK-NEXT: .result f32{{$}}
259; CHECK-NEXT: f32.convert_u/i64 $push[[NUM:[0-9]+]]=, $0{{$}}
260; CHECK-NEXT: return $pop[[NUM]]{{$}}
261define float @f32_convert_u_i64(i64 %x) {
262  %a = uitofp i64 %x to float
263  ret float %a
264}
265
266; CHECK-LABEL: f64_convert_s_i64:
267; CHECK-NEXT: .param i64{{$}}
268; CHECK-NEXT: .result f64{{$}}
269; CHECK-NEXT: f64.convert_s/i64 $push[[NUM:[0-9]+]]=, $0{{$}}
270; CHECK-NEXT: return $pop[[NUM]]{{$}}
271define double @f64_convert_s_i64(i64 %x) {
272  %a = sitofp i64 %x to double
273  ret double %a
274}
275
276; CHECK-LABEL: f64_convert_u_i64:
277; CHECK-NEXT: .param i64{{$}}
278; CHECK-NEXT: .result f64{{$}}
279; CHECK-NEXT: f64.convert_u/i64 $push[[NUM:[0-9]+]]=, $0{{$}}
280; CHECK-NEXT: return $pop[[NUM]]{{$}}
281define double @f64_convert_u_i64(i64 %x) {
282  %a = uitofp i64 %x to double
283  ret double %a
284}
285
286; CHECK-LABEL: f64_promote_f32:
287; CHECK-NEXT: .param f32{{$}}
288; CHECK-NEXT: .result f64{{$}}
289; CHECK-NEXT: f64.promote/f32 $push[[NUM:[0-9]+]]=, $0{{$}}
290; CHECK-NEXT: return $pop[[NUM]]{{$}}
291define double @f64_promote_f32(float %x) {
292  %a = fpext float %x to double
293  ret double %a
294}
295
296; CHECK-LABEL: f32_demote_f64:
297; CHECK-NEXT: .param f64{{$}}
298; CHECK-NEXT: .result f32{{$}}
299; CHECK-NEXT: f32.demote/f64 $push[[NUM:[0-9]+]]=, $0{{$}}
300; CHECK-NEXT: return $pop[[NUM]]{{$}}
301define float @f32_demote_f64(double %x) {
302  %a = fptrunc double %x to float
303  ret float %a
304}
305
306; If the high its are unused, LLVM will optimize sext/zext into anyext, which
307; we need to patterm-match back to a specific instruction.
308
309; CHECK-LABEL: anyext:
310; CHECK: i64.extend_u/i32 $push0=, $0{{$}}
311define i64 @anyext(i32 %x) {
312    %y = sext i32 %x to i64
313    %w = shl i64 %y, 32
314    ret i64 %w
315}
316
317; CHECK-LABEL: bitcast_i32_to_float:
318; CHECK: f32.reinterpret/i32   $push0=, $0{{$}}
319define float @bitcast_i32_to_float(i32 %a) {
320  %t = bitcast i32 %a to float
321  ret float %t
322}
323
324; CHECK-LABEL: bitcast_float_to_i32:
325; CHECK: i32.reinterpret/f32   $push0=, $0{{$}}
326define i32 @bitcast_float_to_i32(float %a) {
327  %t = bitcast float %a to i32
328  ret i32 %t
329}
330
331; CHECK-LABEL: bitcast_i64_to_double:
332; CHECK: f64.reinterpret/i64   $push0=, $0{{$}}
333define double @bitcast_i64_to_double(i64 %a) {
334  %t = bitcast i64 %a to double
335  ret double %t
336}
337
338; CHECK-LABEL: bitcast_double_to_i64:
339; CHECK: i64.reinterpret/f64   $push0=, $0{{$}}
340define i64 @bitcast_double_to_i64(double %a) {
341  %t = bitcast double %a to i64
342  ret i64 %t
343}
344