xref: /llvm-project/llvm/test/CodeGen/WebAssembly/half-precision.ll (revision c076638c702b1d43e8f1c4a813deb3c09b748abb)
1; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+fp16,+simd128 | FileCheck %s
2
3declare float @llvm.wasm.loadf32.f16(ptr)
4declare void @llvm.wasm.storef16.f32(float, ptr)
5
6; CHECK-LABEL: ldf16_32:
7; CHECK:      f32.load_f16 $push[[NUM0:[0-9]+]]=, 0($0){{$}}
8; CHECK-NEXT: return $pop[[NUM0]]{{$}}
9define float @ldf16_32(ptr %p) {
10  %v = call float @llvm.wasm.loadf16.f32(ptr %p)
11  ret float %v
12}
13
14; CHECK-LABEL: stf16_32:
15; CHECK:       f32.store_f16 0($1), $0
16; CHECK-NEXT:  return
17define void @stf16_32(float %v, ptr %p) {
18  tail call void @llvm.wasm.storef16.f32(float %v, ptr %p)
19  ret void
20}
21
22; CHECK-LABEL: splat_v8f16:
23; CHECK:       f16x8.splat $push0=, $0
24; CHECK-NEXT:  return $pop0
25define <8 x half> @splat_v8f16(float %x) {
26  %v = call <8 x half> @llvm.wasm.splat.f16x8(float %x)
27  ret <8 x half> %v
28}
29
30; CHECK-LABEL: const_splat_v8f16:
31; CHECK:       v128.const      $push0=, 20800, 0, 0, 0, 0, 0, 0, 20800
32; CHECK-NEXT:  return $pop0
33define <8 x half> @const_splat_v8f16() {
34  ret <8 x half> <half 42., half 0., half 0., half 0., half 0., half 0., half 0., half 42.>
35}
36
37; CHECK-LABEL: extract_lane_v8f16:
38; CHECK:       f16x8.extract_lane $push0=, $0, 1
39; CHECK-NEXT:  return $pop0
40define float @extract_lane_v8f16(<8 x half> %v) {
41  %r = call float @llvm.wasm.extract.lane.f16x8(<8 x half> %v, i32 1)
42  ret float %r
43}
44
45; CHECK-LABEL: replace_lane_v8f16:
46; CHECK:       f16x8.replace_lane $push0=, $0, 1, $1
47; CHECK-NEXT:  return $pop0
48define <8 x half> @replace_lane_v8f16(<8 x half> %v, float %f) {
49  %r = call <8 x half> @llvm.wasm.replace.lane.f16x8(<8 x half> %v, i32 1, float %f)
50  ret <8 x half> %r
51}
52
53; CHECK-LABEL: add_v8f16:
54; CHECK:       f16x8.add $push0=, $0, $1
55; CHECK-NEXT:  return $pop0
56define <8 x half> @add_v8f16(<8 x half> %a, <8 x half> %b) {
57  %r = fadd <8 x half> %a, %b
58  ret <8 x half> %r
59}
60
61; CHECK-LABEL: sub_v8f16:
62; CHECK:       f16x8.sub $push0=, $0, $1
63; CHECK-NEXT:  return $pop0
64define <8 x half> @sub_v8f16(<8 x half> %a, <8 x half> %b) {
65  %r = fsub <8 x half> %a, %b
66  ret <8 x half> %r
67}
68
69; CHECK-LABEL: mul_v8f16:
70; CHECK:       f16x8.mul $push0=, $0, $1
71; CHECK-NEXT:  return $pop0
72define <8 x half> @mul_v8f16(<8 x half> %a, <8 x half> %b) {
73  %r = fmul <8 x half> %a, %b
74  ret <8 x half> %r
75}
76
77; CHECK-LABEL: div_v8f16:
78; CHECK:       f16x8.div $push0=, $0, $1
79; CHECK-NEXT:  return $pop0
80define <8 x half> @div_v8f16(<8 x half> %a, <8 x half> %b) {
81  %r = fdiv <8 x half> %a, %b
82  ret <8 x half> %r
83}
84
85; CHECK-LABEL: min_intrinsic_v8f16:
86; CHECK:       f16x8.min $push0=, $0, $1
87; CHECK-NEXT:  return $pop0
88declare <8 x half> @llvm.minimum.v8f16(<8 x half>, <8 x half>)
89define <8 x half> @min_intrinsic_v8f16(<8 x half> %x, <8 x half> %y) {
90  %a = call <8 x half> @llvm.minimum.v8f16(<8 x half> %x, <8 x half> %y)
91  ret <8 x half> %a
92}
93
94; CHECK-LABEL: max_intrinsic_v8f16:
95; CHECK:       f16x8.max $push0=, $0, $1
96; CHECK-NEXT:  return $pop0
97declare <8 x half> @llvm.maximum.v8f16(<8 x half>, <8 x half>)
98define <8 x half> @max_intrinsic_v8f16(<8 x half> %x, <8 x half> %y) {
99  %a = call <8 x half> @llvm.maximum.v8f16(<8 x half> %x, <8 x half> %y)
100  ret <8 x half> %a
101}
102
103; CHECK-LABEL: pmin_intrinsic_v8f16:
104; CHECK:       f16x8.pmin $push0=, $0, $1
105; CHECK-NEXT:  return $pop0
106declare <8 x half> @llvm.wasm.pmin.v8f16(<8 x half>, <8 x half>)
107define <8 x half> @pmin_intrinsic_v8f16(<8 x half> %a, <8 x half> %b) {
108  %v = call <8 x half> @llvm.wasm.pmin.v8f16(<8 x half> %a, <8 x half> %b)
109  ret <8 x half> %v
110}
111
112; CHECK-LABEL: pmax_intrinsic_v8f16:
113; CHECK:       f16x8.pmax $push0=, $0, $1
114; CHECK-NEXT:  return $pop0
115declare <8 x half> @llvm.wasm.pmax.v8f16(<8 x half>, <8 x half>)
116define <8 x half> @pmax_intrinsic_v8f16(<8 x half> %a, <8 x half> %b) {
117  %v = call <8 x half> @llvm.wasm.pmax.v8f16(<8 x half> %a, <8 x half> %b)
118  ret <8 x half> %v
119}
120
121; CHECK-LABEL: compare_oeq_v8f16:
122; CHECK-NEXT: .functype compare_oeq_v8f16 (v128, v128) -> (v128){{$}}
123; CHECK-NEXT: f16x8.eq $push[[R:[0-9]+]]=, $0, $1{{$}}
124; CHECK-NEXT: return $pop[[R]]{{$}}
125define <8 x i1> @compare_oeq_v8f16 (<8 x half> %x, <8 x half> %y) {
126  %res = fcmp oeq <8 x half> %x, %y
127  ret <8 x i1> %res
128}
129
130; CHECK-LABEL: compare_une_v8f16:
131; CHECK-NEXT: .functype compare_une_v8f16 (v128, v128) -> (v128){{$}}
132; CHECK-NEXT: f16x8.ne $push[[R:[0-9]+]]=, $0, $1{{$}}
133; CHECK-NEXT: return $pop[[R]]{{$}}
134define <8 x i1> @compare_une_v8f16 (<8 x half> %x, <8 x half> %y) {
135  %res = fcmp une <8 x half> %x, %y
136  ret <8 x i1> %res
137}
138
139; CHECK-LABEL: compare_olt_v8f16:
140; CHECK-NEXT: .functype compare_olt_v8f16 (v128, v128) -> (v128){{$}}
141; CHECK-NEXT: f16x8.lt $push[[R:[0-9]+]]=, $0, $1{{$}}
142; CHECK-NEXT: return $pop[[R]]{{$}}
143define <8 x i1> @compare_olt_v8f16 (<8 x half> %x, <8 x half> %y) {
144  %res = fcmp olt <8 x half> %x, %y
145  ret <8 x i1> %res
146}
147
148; CHECK-LABEL: compare_ogt_v8f16:
149; CHECK-NEXT: .functype compare_ogt_v8f16 (v128, v128) -> (v128){{$}}
150; CHECK-NEXT: f16x8.gt $push[[R:[0-9]+]]=, $0, $1{{$}}
151; CHECK-NEXT: return $pop[[R]]{{$}}
152define <8 x i1> @compare_ogt_v8f16 (<8 x half> %x, <8 x half> %y) {
153  %res = fcmp ogt <8 x half> %x, %y
154  ret <8 x i1> %res
155}
156
157; CHECK-LABEL: compare_ole_v8f16:
158; CHECK-NEXT: .functype compare_ole_v8f16 (v128, v128) -> (v128){{$}}
159; CHECK-NEXT: f16x8.le $push[[R:[0-9]+]]=, $0, $1{{$}}
160; CHECK-NEXT: return $pop[[R]]{{$}}
161define <8 x i1> @compare_ole_v8f16 (<8 x half> %x, <8 x half> %y) {
162  %res = fcmp ole <8 x half> %x, %y
163  ret <8 x i1> %res
164}
165
166; CHECK-LABEL: compare_oge_v8f16:
167; CHECK-NEXT: .functype compare_oge_v8f16 (v128, v128) -> (v128){{$}}
168; CHECK-NEXT: f16x8.ge $push[[R:[0-9]+]]=, $0, $1{{$}}
169; CHECK-NEXT: return $pop[[R]]{{$}}
170define <8 x i1> @compare_oge_v8f16 (<8 x half> %x, <8 x half> %y) {
171  %res = fcmp oge <8 x half> %x, %y
172  ret <8 x i1> %res
173}
174
175; CHECK-LABEL: abs_v8f16:
176; CHECK-NEXT:  .functype abs_v8f16 (v128) -> (v128)
177; CHECK-NEXT:  f16x8.abs $push0=, $0
178; CHECK-NEXT:  return $pop0
179declare <8 x half> @llvm.fabs.v8f16(<8 x half>) nounwind readnone
180define <8 x half> @abs_v8f16(<8 x half> %x) {
181  %a = call <8 x half> @llvm.fabs.v8f16(<8 x half> %x)
182  ret <8 x half> %a
183}
184
185; CHECK-LABEL: neg_v8f16:
186; CHECK-NEXT:  .functype neg_v8f16 (v128) -> (v128)
187; CHECK-NEXT:  f16x8.neg $push0=, $0
188; CHECK-NEXT:  return $pop0
189define <8 x half> @neg_v8f16(<8 x half> %x) {
190  %a = fsub nsz <8 x half> <half 0., half 0., half 0., half 0., half 0., half 0., half 0., half 0.>, %x
191  ret <8 x half> %a
192}
193
194; CHECK-LABEL: sqrt_v8f16:
195; CHECK-NEXT:  .functype sqrt_v8f16 (v128) -> (v128)
196; CHECK-NEXT:  f16x8.sqrt $push0=, $0
197; CHECK-NEXT:  return $pop0
198declare <8 x half> @llvm.sqrt.v8f16(<8 x half> %x)
199define <8 x half> @sqrt_v8f16(<8 x half> %x) {
200  %a = call <8 x half> @llvm.sqrt.v8f16(<8 x half> %x)
201  ret <8 x half> %a
202}
203
204; CHECK-LABEL: ceil_v8f16:
205; CHECK-NEXT:  .functype ceil_v8f16 (v128) -> (v128){{$}}
206; CHECK-NEXT:  f16x8.ceil $push[[R:[0-9]+]]=, $0{{$}}
207; CHECK-NEXT:  return $pop[[R]]{{$}}
208declare <8 x half> @llvm.ceil.v8f16(<8 x half>)
209define <8 x half> @ceil_v8f16(<8 x half> %a) {
210  %v = call <8 x half> @llvm.ceil.v8f16(<8 x half> %a)
211  ret <8 x half> %v
212}
213
214; CHECK-LABEL: floor_v8f16:
215; CHECK-NEXT:  .functype floor_v8f16 (v128) -> (v128){{$}}
216; CHECK-NEXT:  f16x8.floor $push[[R:[0-9]+]]=, $0{{$}}
217; CHECK-NEXT:  return $pop[[R]]{{$}}
218declare <8 x half> @llvm.floor.v8f16(<8 x half>)
219define <8 x half> @floor_v8f16(<8 x half> %a) {
220  %v = call <8 x half> @llvm.floor.v8f16(<8 x half> %a)
221  ret <8 x half> %v
222}
223
224; CHECK-LABEL: trunc_v8f16:
225; CHECK-NEXT:  .functype trunc_v8f16 (v128) -> (v128){{$}}
226; CHECK-NEXT:  f16x8.trunc $push[[R:[0-9]+]]=, $0{{$}}
227; CHECK-NEXT:  return $pop[[R]]{{$}}
228declare <8 x half> @llvm.trunc.v8f16(<8 x half>)
229define <8 x half> @trunc_v8f16(<8 x half> %a) {
230  %v = call <8 x half> @llvm.trunc.v8f16(<8 x half> %a)
231  ret <8 x half> %v
232}
233
234; CHECK-LABEL: nearest_v8f16:
235; CHECK-NEXT:  .functype nearest_v8f16 (v128) -> (v128){{$}}
236; CHECK-NEXT:  f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}}
237; CHECK-NEXT:  return $pop[[R]]{{$}}
238declare <8 x half> @llvm.nearbyint.v8f16(<8 x half>)
239define <8 x half> @nearest_v8f16(<8 x half> %a) {
240  %v = call <8 x half> @llvm.nearbyint.v8f16(<8 x half> %a)
241  ret <8 x half> %v
242}
243
244; CHECK-LABEL: nearest_v8f16_via_rint:
245; CHECK-NEXT:  .functype nearest_v8f16_via_rint (v128) -> (v128){{$}}
246; CHECK-NEXT:  f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}}
247; CHECK-NEXT:  return $pop[[R]]{{$}}
248declare <8 x half> @llvm.rint.v8f16(<8 x half>)
249define <8 x half> @nearest_v8f16_via_rint(<8 x half> %a) {
250  %v = call <8 x half> @llvm.rint.v8f16(<8 x half> %a)
251  ret <8 x half> %v
252}
253
254; CHECK-LABEL: nearest_v8f16_via_roundeven:
255; CHECK-NEXT:  .functype nearest_v8f16_via_roundeven (v128) -> (v128){{$}}
256; CHECK-NEXT:  f16x8.nearest $push[[R:[0-9]+]]=, $0{{$}}
257; CHECK-NEXT:  return $pop[[R]]{{$}}
258declare <8 x half> @llvm.roundeven.v8f16(<8 x half>)
259define <8 x half> @nearest_v8f16_via_roundeven(<8 x half> %a) {
260  %v = call <8 x half> @llvm.roundeven.v8f16(<8 x half> %a)
261  ret <8 x half> %v
262}
263
264define <8 x half> @convert_s_v8f16(<8 x i16> %x) {
265; CHECK-LABEL: convert_s_v8f16:
266; CHECK:         .functype convert_s_v8f16 (v128) -> (v128)
267; CHECK-NEXT:    f16x8.convert_i16x8_s $push0=, $0
268; CHECK-NEXT:    return $pop[[R]]{{$}}
269  %a = sitofp <8 x i16> %x to <8 x half>
270  ret <8 x half> %a
271}
272
273define <8 x half> @convert_u_v8f16(<8 x i16> %x) {
274; CHECK-LABEL: convert_u_v8f16:
275; CHECK:         .functype convert_u_v8f16 (v128) -> (v128)
276; CHECK-NEXT:    f16x8.convert_i16x8_u $push0=, $0
277; CHECK-NEXT:    return $pop[[R]]{{$}}
278  %a = uitofp <8 x i16> %x to <8 x half>
279  ret <8 x half> %a
280}
281
282define <8 x i16> @trunc_sat_s_v8i16(<8 x half> %x) {
283; CHECK-LABEL: trunc_sat_s_v8i16:
284; CHECK:         .functype trunc_sat_s_v8i16 (v128) -> (v128)
285; CHECK-NEXT:    i16x8.trunc_sat_f16x8_s $push0=, $0
286; CHECK-NEXT:    return $pop[[R]]{{$}}
287  %a = fptosi <8 x half> %x to <8 x i16>
288  ret <8 x i16> %a
289}
290
291define <8 x i16> @trunc_sat_u_v8i16(<8 x half> %x) {
292; CHECK-LABEL: trunc_sat_u_v8i16:
293; CHECK:         .functype trunc_sat_u_v8i16 (v128) -> (v128)
294; CHECK-NEXT:    i16x8.trunc_sat_f16x8_u $push0=, $0
295; CHECK-NEXT:    return $pop[[R]]{{$}}
296  %a = fptoui <8 x half> %x to <8 x i16>
297  ret <8 x i16> %a
298}
299
300define <8 x i16> @trunc_sat_s_v8i16_sat(<8 x half> %x) {
301; CHECK-LABEL: trunc_sat_s_v8i16_sat:
302; CHECK:         .functype trunc_sat_s_v8i16_sat (v128) -> (v128)
303; CHECK-NEXT:    i16x8.trunc_sat_f16x8_s $push0=, $0
304; CHECK-NEXT:    return $pop[[R]]{{$}}
305  %a = call <8 x i16> @llvm.fptosi.sat.v8i16.v8f16(<8 x half> %x)
306  ret <8 x i16> %a
307}
308
309define <8 x i16> @trunc_sat_u_v8i16_sat(<8 x half> %x) {
310; CHECK-LABEL: trunc_sat_u_v8i16_sat:
311; CHECK:         .functype trunc_sat_u_v8i16_sat (v128) -> (v128)
312; CHECK-NEXT:    i16x8.trunc_sat_f16x8_u $push0=, $0
313; CHECK-NEXT:    return $pop[[R]]{{$}}
314  %a = call <8 x i16> @llvm.fptoui.sat.v8i16.v8f16(<8 x half> %x)
315  ret <8 x i16> %a
316}
317
318; ==============================================================================
319; Load and Store
320; ==============================================================================
321define <8 x half> @load_v8f16(ptr %p) {
322; CHECK-LABEL: load_v8f16:
323; CHECK:         .functype load_v8f16 (i32) -> (v128)
324; CHECK-NEXT:    v128.load $push0=, 0($0)
325; CHECK-NEXT:    return $pop0
326  %v = load <8 x half>, ptr %p
327  ret <8 x half> %v
328}
329
330define void @store_v8f16(<8 x half> %v, ptr %p) {
331; CHECK-LABEL: store_v8f16:
332; CHECK:         .functype store_v8f16 (v128, i32) -> ()
333; CHECK-NEXT:    v128.store 0($1), $0
334; CHECK-NEXT:    return
335  store <8 x half> %v , ptr %p
336  ret void
337}
338