Add support to promote f16 to f32
[oota-llvm.git] / test / CodeGen / ARM / fp16-promote.ll
1 ; RUN: llc -asm-verbose=false < %s -mattr=+vfp3,+fp16 | FileCheck %s -check-prefix=CHECK-FP16 -check-prefix=CHECK-ALL
2 ; RUN: llc -asm-verbose=false < %s | FileCheck %s -check-prefix=CHECK-LIBCALL -check-prefix=CHECK-ALL
3
4 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n32"
5 target triple = "armv7-eabihf"
6
7 ; CHECK-FP16-LABEL: test_fadd:
8 ; CHECK-FP16-NEXT: .fnstart
9 ; CHECK-FP16-NEXT: ldrh r2, [r0]
10 ; CHECK-FP16-NEXT: ldrh r1, [r1]
11 ; CHECK-FP16-NEXT: vmov s0, r1
12 ; CHECK-FP16-NEXT: vmov s2, r2
13 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
14 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
15 ; CHECK-FP16-NEXT: vadd.f32 s0, s2, s0
16 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
17 ; CHECK-FP16-NEXT: vmov r1, s0
18 ; CHECK-FP16-NEXT: strh r1, [r0]
19 ; CHECK-FP16-NEXT: bx lr
20 ; CHECK-LIBCALL-LABEL: test_fadd:
21 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
22 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
23 ; CHECK-LIBCALL: vadd.f32
24 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
25 define void @test_fadd(half* %p, half* %q) #0 {
26   %a = load half, half* %p, align 2
27   %b = load half, half* %q, align 2
28   %r = fadd half %a, %b
29   store half %r, half* %p
30   ret void
31 }
32
33 ; CHECK-FP16-LABEL: test_fsub:
34 ; CHECK-FP16-NEXT: .fnstart
35 ; CHECK-FP16-NEXT: ldrh r2, [r0]
36 ; CHECK-FP16-NEXT: ldrh r1, [r1]
37 ; CHECK-FP16-NEXT: vmov s0, r1
38 ; CHECK-FP16-NEXT: vmov s2, r2
39 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
40 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
41 ; CHECK-FP16-NEXT: vsub.f32 s0, s2, s0
42 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
43 ; CHECK-FP16-NEXT: vmov r1, s0
44 ; CHECK-FP16-NEXT: strh r1, [r0]
45 ; CHECK-FP16-NEXT: bx lr
46 ; CHECK-LIBCALL-LABEL: test_fsub:
47 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
48 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
49 ; CHECK-LIBCALL: vsub.f32
50 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
51 define void @test_fsub(half* %p, half* %q) #0 {
52   %a = load half, half* %p, align 2
53   %b = load half, half* %q, align 2
54   %r = fsub half %a, %b
55   store half %r, half* %p
56   ret void
57 }
58
59 ; CHECK-FP16-LABEL: test_fmul:
60 ; CHECK-FP16-NEXT: .fnstart
61 ; CHECK-FP16-NEXT: ldrh r2, [r0]
62 ; CHECK-FP16-NEXT: ldrh r1, [r1]
63 ; CHECK-FP16-NEXT: vmov s0, r1
64 ; CHECK-FP16-NEXT: vmov s2, r2
65 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
66 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
67 ; CHECK-FP16-NEXT: vmul.f32 s0, s2, s0
68 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
69 ; CHECK-FP16-NEXT: vmov r1, s0
70 ; CHECK-FP16-NEXT: strh r1, [r0]
71 ; CHECK-FP16-NEXT: bx lr
72 ; CHECK-LIBCALL-LABEL: test_fmul
73 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
74 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
75 ; CHECK-LIBCALL: vmul.f32
76 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
77 define void @test_fmul(half* %p, half* %q) #0 {
78   %a = load half, half* %p, align 2
79   %b = load half, half* %q, align 2
80   %r = fmul half %a, %b
81   store half %r, half* %p
82   ret void
83 }
84
85 ; CHECK-FP16-LABEL: test_fdiv:
86 ; CHECK-FP16-NEXT: .fnstart
87 ; CHECK-FP16-NEXT: ldrh r2, [r0]
88 ; CHECK-FP16-NEXT: ldrh r1, [r1]
89 ; CHECK-FP16-NEXT: vmov s0, r1
90 ; CHECK-FP16-NEXT: vmov s2, r2
91 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
92 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
93 ; CHECK-FP16-NEXT: vdiv.f32 s0, s2, s0
94 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
95 ; CHECK-FP16-NEXT: vmov r1, s0
96 ; CHECK-FP16-NEXT: strh r1, [r0]
97 ; CHECK-FP16-NEXT: bx lr
98 ; CHECK-LIBCALL-LABEL: test_fdiv
99 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
100 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
101 ; CHECK-LIBCALL: vdiv.f32
102 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
103 define void @test_fdiv(half* %p, half* %q) #0 {
104   %a = load half, half* %p, align 2
105   %b = load half, half* %q, align 2
106   %r = fdiv half %a, %b
107   store half %r, half* %p
108   ret void
109 }
110
111 ; CHECK-FP16-LABEL: test_frem:
112 ; CHECK-FP16-NEXT: .fnstart
113 ; CHECK-FP16-NEXT: push {r4, lr}
114 ; CHECK-FP16-NEXT: mov r4, r0
115 ; CHECK-FP16-NEXT: ldrh r0, [r1]
116 ; CHECK-FP16-NEXT: ldrh r1, [r4]
117 ; CHECK-FP16-NEXT: vmov s2, r0
118 ; CHECK-FP16-NEXT: vmov s0, r1
119 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
120 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
121 ; CHECK-FP16-NEXT: vmov r0, s0
122 ; CHECK-FP16-NEXT: vmov r1, s2
123 ; CHECK-FP16-NEXT: bl fmodf
124 ; CHECK-FP16-NEXT: vmov s0, r0
125 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
126 ; CHECK-FP16-NEXT: vmov r0, s0
127 ; CHECK-FP16-NEXT: strh r0, [r4]
128 ; CHECK-FP16-NEXT: pop {r4, pc}
129 ; CHECK-LIBCALL-LABEL: test_frem
130 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
131 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
132 ; CHECK-LIBCALL: bl fmodf
133 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
134 define void @test_frem(half* %p, half* %q) #0 {
135   %a = load half, half* %p, align 2
136   %b = load half, half* %q, align 2
137   %r = frem half %a, %b
138   store half %r, half* %p
139   ret void
140 }
141
142 ; CHECK-ALL-LABEL: test_load_store:
143 ; CHECK-ALL-NEXT: .fnstart
144 ; CHECK-ALL-NEXT: ldrh r0, [r0]
145 ; CHECK-ALL-NEXT: strh r0, [r1]
146 ; CHECK-ALL-NEXT: bx lr
147 define void @test_load_store(half* %p, half* %q) #0 {
148   %a = load half, half* %p, align 2
149   store half %a, half* %q
150   ret void
151 }
152
153 ; Testing only successfull compilation of function calls.  In ARM ABI, half
154 ; args and returns are handled as f32.
155
156 declare half @test_callee(half %a, half %b) #0
157
158 ; CHECK-ALL-LABEL: test_call:
159 ; CHECK-ALL-NEXT: .fnstart
160 ; CHECK-ALL-NEXT: push {r11, lr}
161 ; CHECK-ALL-NEXT: bl test_callee
162 ; CHECK-ALL-NEXT: pop {r11, pc}
163 define half @test_call(half %a, half %b) #0 {
164   %r = call half @test_callee(half %a, half %b)
165   ret half %r
166 }
167
168 ; CHECK-ALL-LABEL: test_call_flipped:
169 ; CHECK-ALL-NEXT: .fnstart
170 ; CHECK-ALL-NEXT: push {r11, lr}
171 ; CHECK-ALL-NEXT: mov r2, r0
172 ; CHECK-ALL-NEXT: mov r0, r1
173 ; CHECK-ALL-NEXT: mov r1, r2
174 ; CHECK-ALL-NEXT: bl test_callee
175 ; CHECK-ALL-NEXT: pop {r11, pc}
176 define half @test_call_flipped(half %a, half %b) #0 {
177   %r = call half @test_callee(half %b, half %a)
178   ret half %r
179 }
180
181 ; CHECK-ALL-LABEL: test_tailcall_flipped:
182 ; CHECK-ALL-NEXT: .fnstart
183 ; CHECK-ALL-NEXT: mov r2, r0
184 ; CHECK-ALL-NEXT: mov r0, r1
185 ; CHECK-ALL-NEXT: mov r1, r2
186 ; CHECK-ALL-NEXT: b test_callee
187 define half @test_tailcall_flipped(half %a, half %b) #0 {
188   %r = tail call half @test_callee(half %b, half %a)
189   ret half %r
190 }
191
192 ; Optimizer picks %p or %q based on %c and only loads that value
193 ; No conversion is needed
194 ; CHECK-BOTH-LABEL: test_select:
195 ; CHECK-BOTH-NEXT: .fnstart
196 ; CHECK-BOTH-NEXT: cmp r2, #0
197 ; CHECK-BOTH-NEXT: movne r1, r0
198 ; CHECK-BOTH-NEXT: ldrh r1, [r1]
199 ; CHECK-BOTH-NEXT: strh r1, [r0]
200 ; CHECK-BOTH-NEXT: bx lr
201 define void @test_select(half* %p, half* %q, i1 zeroext %c) #0 {
202   %a = load half, half* %p, align 2
203   %b = load half, half* %q, align 2
204   %r = select i1 %c, half %a, half %b
205   store half %r, half* %p
206   ret void
207 }
208
209 ; Test only two variants of fcmp.  These get translated to f32 vcmpe
210 ; instructions anyway.
211 ; CHECK-FP16-LABEL: test_fcmp_une:
212 ; CHECK-FP16-NEXT: .fnstart
213 ; CHECK-FP16-NEXT: ldrh r2, [r0]
214 ; CHECK-FP16-NEXT: ldrh r0, [r1]
215 ; CHECK-FP16-NEXT: vmov s0, r0
216 ; CHECK-FP16-NEXT: vmov s2, r2
217 ; CHECK-FP16-NEXT: mov r0, #0
218 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
219 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
220 ; CHECK-FP16-NEXT: vcmpe.f32 s2, s0
221 ; CHECK-FP16-NEXT: vmrs APSR_nzcv, fpscr
222 ; CHECK-FP16-NEXT: movwne r0, #1
223 ; CHECK-FP16-NEXT: bx lr
224 ; CHECK-LIBCALL-LABEL: test_fcmp_une:
225 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
226 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
227 ; CHECK-LIBCALL: vcmpe.f32
228 ; CHECK-LIBCALL: movwne
229 define i1 @test_fcmp_une(half* %p, half* %q) #0 {
230   %a = load half, half* %p, align 2
231   %b = load half, half* %q, align 2
232   %r = fcmp une half %a, %b
233   ret i1 %r
234 }
235
236 ; CHECK-FP16-LABEL: test_fcmp_ueq:
237 ; CHECK-FP16-NEXT: .fnstart
238 ; CHECK-FP16-NEXT: ldrh r2, [r0]
239 ; CHECK-FP16-NEXT: ldrh r0, [r1]
240 ; CHECK-FP16-NEXT: vmov s0, r0
241 ; CHECK-FP16-NEXT: vmov s2, r2
242 ; CHECK-FP16-NEXT: mov r0, #0
243 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
244 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
245 ; CHECK-FP16-NEXT: vcmpe.f32 s2, s0
246 ; CHECK-FP16-NEXT: vmrs APSR_nzcv, fpscr
247 ; CHECK-FP16-NEXT: movweq r0, #1
248 ; CHECK-FP16-NEXT: movwvs r0, #1
249 ; CHECK-FP16-NEXT: bx lr
250 ; CHECK-LIBCALL-LABEL: test_fcmp_ueq:
251 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
252 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
253 ; CHECK-LIBCALL: vcmpe.f32
254 ; CHECK-LIBCALL: movweq
255 define i1 @test_fcmp_ueq(half* %p, half* %q) #0 {
256   %a = load half, half* %p, align 2
257   %b = load half, half* %q, align 2
258   %r = fcmp ueq half %a, %b
259   ret i1 %r
260 }
261
262 ; CHECK-FP16-LABEL: test_br_cc:
263 ; CHECK-FP16-NEXT: .fnstart
264 ; CHECK-FP16-NEXT: ldrh r0, [r0]
265 ; CHECK-FP16-NEXT: ldrh r1, [r1]
266 ; CHECK-FP16-NEXT: vmov s0, r1
267 ; CHECK-FP16-NEXT: vmov s2, r0
268 ; CHECK-FP16-NEXT: mov r0, #0
269 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
270 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
271 ; CHECK-FP16-NEXT: vcmpe.f32 s2, s0
272 ; CHECK-FP16-NEXT: vmrs APSR_nzcv, fpscr
273 ; CHECK-FP16-NEXT: strmi r0, [r3]
274 ; CHECK-FP16-NEXT: strpl r0, [r2]
275 ; CHECK-FP16-NEXT: bx lr
276 ; CHECK-LIBCALL-LABEL: test_br_cc:
277 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
278 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
279 ; CHECK-LIBCALL: vcmpe.f32
280 ; CHECK-LIBCALL: strmi
281 ; CHECK-LIBCALL: strpl
282 define void @test_br_cc(half* %p, half* %q, i32* %p1, i32* %p2) #0 {
283   %a = load half, half* %p, align 2
284   %b = load half, half* %q, align 2
285   %c = fcmp uge half %a, %b
286   br i1 %c, label %then, label %else
287 then:
288   store i32 0, i32* %p1
289   ret void
290 else:
291   store i32 0, i32* %p2
292   ret void
293 }
294
295 declare i1 @test_dummy(half* %p) #0
296 ; CHECK-FP16-LABEL: test_phi:
297 ; CHECK-FP16-NEXT: .fnstart
298 ; CHECK-FP16-NEXT: push    {r4, lr}
299 ; CHECK-FP16-NEXT: vpush   {d8, d9}
300 ; CHECK-FP16-NEXT: mov     r4, r0
301 ; CHECK-FP16-NEXT: ldrh    r0, [r4]
302 ; CHECK-FP16-NEXT: vmov    s0, r0
303 ; CHECK-FP16-NEXT: vcvtb.f32.f16   s18, s0
304 ; CHECK-FP16-NEXT: [[LOOP:.LBB[1-9_]+]]:
305 ; CHECK-FP16-NEXT: ldrh    r0, [r4]
306 ; CHECK-FP16-NEXT: vmov.f32        s16, s18
307 ; CHECK-FP16-NEXT: vmov    s0, r0
308 ; CHECK-FP16-NEXT: mov     r0, r4
309 ; CHECK-FP16-NEXT: vcvtb.f32.f16   s18, s0
310 ; CHECK-FP16-NEXT: bl      test_dummy
311 ; CHECK-FP16-NEXT: tst     r0, #1
312 ; CHECK-FP16-NEXT: bne     [[LOOP]]
313 ; CHECK-FP16-NEXT: vcvtb.f16.f32   s0, s16
314 ; CHECK-FP16-NEXT: vmov    r0, s0
315 ; CHECK-FP16-NEXT: strh    r0, [r4]
316 ; CHECK-LIBCALL-LABEL: test_phi:
317 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
318 ; CHECK-LIBCALL: [[LOOP:.LBB[1-9_]+]]:
319 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
320 ; CHECK-LIBCALL: bl test_dummy
321 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
322 define void @test_phi(half* %p) #0 {
323 entry:
324   %a = load half, half* %p
325   br label %loop
326 loop:
327   %r = phi half [%a, %entry], [%b, %loop]
328   %b = load half, half* %p
329   %c = call i1 @test_dummy(half* %p)
330   br i1 %c, label %loop, label %return
331 return:
332   store half %r, half* %p
333   ret void
334 }
335
336 ; CHECK-FP16-LABEL: test_fptosi_i32:
337 ; CHECK-FP16-NEXT: .fnstart
338 ; CHECK-FP16-NEXT: ldrh r0, [r0]
339 ; CHECK-FP16-NEXT: vmov s0, r0
340 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
341 ; CHECK-FP16-NEXT: vcvt.s32.f32 s0, s0
342 ; CHECK-FP16-NEXT: vmov r0, s0
343 ; CHECK-FP16-NEXT: bx
344 ; CHECK-LIBCALL-LABEL: test_fptosi_i32:
345 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
346 ; CHECK-LIBCALL: vcvt.s32.f32
347 define i32 @test_fptosi_i32(half* %p) #0 {
348   %a = load half, half* %p, align 2
349   %r = fptosi half %a to i32
350   ret i32 %r
351 }
352
353 ; CHECK-FP16-LABEL: test_fptosi_i64:
354 ; CHECK-FP16-NEXT: .fnstart
355 ; CHECK-FP16-NEXT: push {r11, lr}
356 ; CHECK-FP16-NEXT: ldrh r0, [r0]
357 ; CHECK-FP16-NEXT: vmov s0, r0
358 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
359 ; CHECK-FP16-NEXT: vmov r0, s0
360 ; CHECK-FP16-NEXT: __aeabi_f2lz
361 ; CHECK-FP16-NEXT: pop {r11, pc}
362 ; CHECK-LIBCALL-LABEL: test_fptosi_i64:
363 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
364 ; CHECK-LIBCALL: bl __aeabi_f2lz
365 define i64 @test_fptosi_i64(half* %p) #0 {
366   %a = load half, half* %p, align 2
367   %r = fptosi half %a to i64
368   ret i64 %r
369 }
370
371 ; CHECK-FP16-LABEL: test_fptoui_i32:
372 ; CHECK-FP16-NEXT: .fnstart
373 ; CHECK-FP16-NEXT: ldrh r0, [r0]
374 ; CHECK-FP16-NEXT: vmov s0, r0
375 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
376 ; CHECK-FP16-NEXT: vcvt.u32.f32 s0, s0
377 ; CHECK-FP16-NEXT: vmov r0, s0
378 ; CHECK-FP16-NEXT: bx
379 ; CHECK-LIBCALL-LABEL: test_fptoui_i32:
380 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
381 ; CHECK-LIBCALL: vcvt.u32.f32
382 define i32 @test_fptoui_i32(half* %p) #0 {
383   %a = load half, half* %p, align 2
384   %r = fptoui half %a to i32
385   ret i32 %r
386 }
387
388 ; CHECK-FP16-LABEL: test_fptoui_i64:
389 ; CHECK-FP16-NEXT: .fnstart
390 ; CHECK-FP16-NEXT: push {r11, lr}
391 ; CHECK-FP16-NEXT: ldrh r0, [r0]
392 ; CHECK-FP16-NEXT: vmov s0, r0
393 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
394 ; CHECK-FP16-NEXT: vmov r0, s0
395 ; CHECK-FP16-NEXT: __aeabi_f2ulz
396 ; CHECK-FP16-NEXT: pop {r11, pc}
397 ; CHECK-LIBCALL-LABEL: test_fptoui_i64:
398 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
399 ; CHECK-LIBCALL: bl __aeabi_f2ulz
400 define i64 @test_fptoui_i64(half* %p) #0 {
401   %a = load half, half* %p, align 2
402   %r = fptoui half %a to i64
403   ret i64 %r
404 }
405
406 ; CHECK-FP16-LABEL: test_sitofp_i32:
407 ; CHECK-FP16-NEXT: .fnstart
408 ; CHECK-FP16-NEXT: vmov s0, r0
409 ; CHECK-FP16-NEXT: vcvt.f32.s32 s0, s0
410 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
411 ; CHECK-FP16-NEXT: vmov r0, s0
412 ; CHECK-FP16-NEXT: strh r0, [r1]
413 ; CHECK-FP16-NEXT: bx
414 ; CHECK-LIBCALL-LABEL: test_sitofp_i32:
415 ; CHECK-LIBCALL: vcvt.f32.s32
416 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
417 define void @test_sitofp_i32(i32 %a, half* %p) #0 {
418   %r = sitofp i32 %a to half
419   store half %r, half* %p
420   ret void
421 }
422
423 ; CHECK-FP16-LABEL: test_uitofp_i32:
424 ; CHECK-FP16-NEXT: .fnstart
425 ; CHECK-FP16-NEXT: vmov s0, r0
426 ; CHECK-FP16-NEXT: vcvt.f32.u32 s0, s0
427 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
428 ; CHECK-FP16-NEXT: vmov r0, s0
429 ; CHECK-FP16-NEXT: strh r0, [r1]
430 ; CHECK-FP16-NEXT: bx
431 ; CHECK-LIBCALL-LABEL: test_uitofp_i32:
432 ; CHECK-LIBCALL: vcvt.f32.u32
433 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
434 define void @test_uitofp_i32(i32 %a, half* %p) #0 {
435   %r = uitofp i32 %a to half
436   store half %r, half* %p
437   ret void
438 }
439
440 ; CHECK-FP16-LABEL: test_sitofp_i64:
441 ; CHECK-FP16-NEXT: .fnstart
442 ; CHECK-FP16-NEXT: push {r4, lr}
443 ; CHECK-FP16-NEXT: mov r4, r2
444 ; CHECK-FP16-NEXT: bl __aeabi_l2f
445 ; CHECK-FP16-NEXT: vmov s0, r0
446 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
447 ; CHECK-FP16-NEXT: vmov r0, s0
448 ; CHECK-FP16-NEXT: strh r0, [r4]
449 ; CHECK-FP16-NEXT: pop {r4, pc}
450 ; CHECK-LIBCALL-LABEL: test_sitofp_i64:
451 ; CHECK-LIBCALL: bl __aeabi_l2f
452 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
453 define void @test_sitofp_i64(i64 %a, half* %p) #0 {
454   %r = sitofp i64 %a to half
455   store half %r, half* %p
456   ret void
457 }
458
459 ; CHECK-FP16-LABEL: test_uitofp_i64:
460 ; CHECK-FP16-NEXT: .fnstart
461 ; CHECK-FP16-NEXT: push {r4, lr}
462 ; CHECK-FP16-NEXT: mov r4, r2
463 ; CHECK-FP16-NEXT: bl __aeabi_ul2f
464 ; CHECK-FP16-NEXT: vmov s0, r0
465 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
466 ; CHECK-FP16-NEXT: vmov r0, s0
467 ; CHECK-FP16-NEXT: strh r0, [r4]
468 ; CHECK-FP16-NEXT: pop {r4, pc}
469 ; CHECK-LIBCALL-LABEL: test_uitofp_i64:
470 ; CHECK-LIBCALL: bl __aeabi_ul2f
471 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
472 define void @test_uitofp_i64(i64 %a, half* %p) #0 {
473   %r = uitofp i64 %a to half
474   store half %r, half* %p
475   ret void
476 }
477
478 ; CHECK-FP16-LABEL: test_fptrunc_float:
479 ; CHECK-FP16-NEXT: .fnstart
480 ; CHECK-FP16-NEXT: vmov s0, r0
481 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
482 ; CHECK-FP16-NEXT: vmov r0, s0
483 ; CHECK-FP16-NEXT: strh r0, [r1]
484 ; CHECK-FP16-NEXT: bx
485 ; CHECK-LIBCALL-LABEL: test_fptrunc_float:
486 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
487 define void @test_fptrunc_float(float %f, half* %p) #0 {
488   %a = fptrunc float %f to half
489   store half %a, half* %p
490   ret void
491 }
492
493 ; CHECK-FP16-LABEL: test_fptrunc_double:
494 ; CHECK-FP16-NEXT: .fnstart
495 ; CHECK-FP16-NEXT: push {r4, lr}
496 ; CHECK-FP16-NEXT: mov r4, r2
497 ; CHECK-FP16-NEXT: bl __aeabi_d2h
498 ; CHECK-FP16-NEXT: strh r0, [r4]
499 ; CHECK-FP16-NEXT: pop {r4, pc}
500 ; CHECK-LIBCALL-LABEL: test_fptrunc_double:
501 ; CHECK-LIBCALL: bl __aeabi_d2h
502 define void @test_fptrunc_double(double %d, half* %p) #0 {
503   %a = fptrunc double %d to half
504   store half %a, half* %p
505   ret void
506 }
507
508 ; CHECK-FP16-LABEL: test_fpextend_float:
509 ; CHECK-FP16-NEXT: .fnstart
510 ; CHECK-FP16-NEXT: ldrh r0, [r0]
511 ; CHECK-FP16-NEXT: vmov s0, r0
512 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
513 ; CHECK-FP16-NEXT: vmov r0, s0
514 ; CHECK-FP16-NEXT: bx lr
515 ; CHECK-LIBCALL-LABEL: test_fpextend_float:
516 ; CHECK-LIBCALL: b __gnu_h2f_ieee
517 define float @test_fpextend_float(half* %p) {
518   %a = load half, half* %p, align 2
519   %r = fpext half %a to float
520   ret float %r
521 }
522
523 ; CHECK-FP16-LABEL: test_fpextend_double:
524 ; CHECK-FP16-NEXT: .fnstart
525 ; CHECK-FP16-NEXT: ldrh r0, [r0]
526 ; CHECK-FP16-NEXT: vmov s0, r0
527 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
528 ; CHECK-FP16-NEXT: vcvt.f64.f32 d16, s0
529 ; CHECK-FP16-NEXT: vmov r0, r1, d16
530 ; CHECK-FP16-NEXT: bx lr
531 ; CHECK-LIBCALL-LABEL: test_fpextend_double:
532 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
533 ; CHECK-LIBCALL: vcvt.f64.f32
534 define double @test_fpextend_double(half* %p) {
535   %a = load half, half* %p, align 2
536   %r = fpext half %a to double
537   ret double %r
538 }
539
540 ; CHECK-BOTH-LABEL: test_bitcast_halftoi16:
541 ; CHECK-BOTH-NEXT: .fnstart
542 ; CHECK-BOTH-NEXT: ldrh r0, [r0]
543 ; CHECK-BOTH-NEXT: bx lr
544 define i16 @test_bitcast_halftoi16(half* %p) #0 {
545   %a = load half, half* %p, align 2
546   %r = bitcast half %a to i16
547   ret i16 %r
548 }
549
550 ; CHECK-BOTH-LABEL: test_bitcast_i16tohalf:
551 ; CHECK-BOTH-NEXT: .fnstart
552 ; CHECK-BOTH-NEXT: strh r0, [r1]
553 ; CHECK-BOTH-NEXT: bx lr
554 define void @test_bitcast_i16tohalf(i16 %a, half* %p) #0 {
555   %r = bitcast i16 %a to half
556   store half %r, half* %p
557   ret void
558 }
559
560 declare half @llvm.sqrt.f16(half %a) #0
561 declare half @llvm.powi.f16(half %a, i32 %b) #0
562 declare half @llvm.sin.f16(half %a) #0
563 declare half @llvm.cos.f16(half %a) #0
564 declare half @llvm.pow.f16(half %a, half %b) #0
565 declare half @llvm.exp.f16(half %a) #0
566 declare half @llvm.exp2.f16(half %a) #0
567 declare half @llvm.log.f16(half %a) #0
568 declare half @llvm.log10.f16(half %a) #0
569 declare half @llvm.log2.f16(half %a) #0
570 declare half @llvm.fma.f16(half %a, half %b, half %c) #0
571 declare half @llvm.fabs.f16(half %a) #0
572 declare half @llvm.minnum.f16(half %a, half %b) #0
573 declare half @llvm.maxnum.f16(half %a, half %b) #0
574 declare half @llvm.copysign.f16(half %a, half %b) #0
575 declare half @llvm.floor.f16(half %a) #0
576 declare half @llvm.ceil.f16(half %a) #0
577 declare half @llvm.trunc.f16(half %a) #0
578 declare half @llvm.rint.f16(half %a) #0
579 declare half @llvm.nearbyint.f16(half %a) #0
580 declare half @llvm.round.f16(half %a) #0
581 declare half @llvm.fmuladd.f16(half %a, half %b, half %c) #0
582
583 ; CHECK-FP16-LABEL: test_sqrt:
584 ; CHECK-FP16-NEXT: .fnstart
585 ; CHECK-FP16-NEXT: ldrh r1, [r0]
586 ; CHECK-FP16-NEXT: vmov s0, r1
587 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
588 ; CHECK-FP16-NEXT: vsqrt.f32 s0, s0
589 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
590 ; CHECK-FP16-NEXT: vmov r1, s0
591 ; CHECK-FP16-NEXT: strh r1, [r0]
592 ; CHECK-FP16-NEXT: bx lr
593 ; CHECK-LIBCALL-LABEL: test_sqrt:
594 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
595 ; CHECK-LIBCALL: vsqrt.f32
596 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
597 define void @test_sqrt(half* %p) #0 {
598   %a = load half, half* %p, align 2
599   %r = call half @llvm.sqrt.f16(half %a)
600   store half %r, half* %p
601   ret void
602 }
603
604 ; CHECK-FP16-LABEL: test_fpowi:
605 ; CHECK-FP16-NEXT: .fnstart
606 ; CHECK-FP16-NEXT: push {r4, lr}
607 ; CHECK-FP16-NEXT: mov r4, r0
608 ; CHECK-FP16-NEXT: ldrh r0, [r4]
609 ; CHECK-FP16-NEXT: vmov s0, r0
610 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
611 ; CHECK-FP16-NEXT: vmov r0, s0
612 ; CHECK-FP16-NEXT: bl __powisf2
613 ; CHECK-FP16-NEXT: vmov s0, r0
614 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
615 ; CHECK-FP16-NEXT: vmov r0, s0
616 ; CHECK-FP16-NEXT: strh r0, [r4]
617 ; CHECK-FP16-NEXT: pop {r4, pc}
618 ; CHECK-LIBCALL-LABEL: test_fpowi:
619 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
620 ; CHECK-LIBCALL: bl __powisf2
621 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
622 define void @test_fpowi(half* %p, i32 %b) #0 {
623   %a = load half, half* %p, align 2
624   %r = call half @llvm.powi.f16(half %a, i32 %b)
625   store half %r, half* %p
626   ret void
627 }
628
629 ; CHECK-FP16-LABEL: test_sin:
630 ; CHECK-FP16-NEXT: .fnstart
631 ; CHECK-FP16-NEXT: push {r4, lr}
632 ; CHECK-FP16-NEXT: mov r4, r0
633 ; CHECK-FP16-NEXT: ldrh r0, [r4]
634 ; CHECK-FP16-NEXT: vmov s0, r0
635 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
636 ; CHECK-FP16-NEXT: vmov r0, s0
637 ; CHECK-FP16-NEXT: bl sinf
638 ; CHECK-FP16-NEXT: vmov s0, r0
639 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
640 ; CHECK-FP16-NEXT: vmov r0, s0
641 ; CHECK-FP16-NEXT: strh r0, [r4]
642 ; CHECK-FP16-NEXT: pop {r4, pc}
643 ; CHECK-LIBCALL-LABEL: test_sin:
644 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
645 ; CHECK-LIBCALL: bl sinf
646 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
647 define void @test_sin(half* %p) #0 {
648   %a = load half, half* %p, align 2
649   %r = call half @llvm.sin.f16(half %a)
650   store half %r, half* %p
651   ret void
652 }
653
654 ; CHECK-FP16-LABEL: test_cos:
655 ; CHECK-FP16-NEXT: .fnstart
656 ; CHECK-FP16-NEXT: push {r4, lr}
657 ; CHECK-FP16-NEXT: mov r4, r0
658 ; CHECK-FP16-NEXT: ldrh r0, [r4]
659 ; CHECK-FP16-NEXT: vmov s0, r0
660 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
661 ; CHECK-FP16-NEXT: vmov r0, s0
662 ; CHECK-FP16-NEXT: bl cosf
663 ; CHECK-FP16-NEXT: vmov s0, r0
664 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
665 ; CHECK-FP16-NEXT: vmov r0, s0
666 ; CHECK-FP16-NEXT: strh r0, [r4]
667 ; CHECK-FP16-NEXT: pop {r4, pc}
668 ; CHECK-LIBCALL-LABEL: test_cos:
669 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
670 ; CHECK-LIBCALL: bl cosf
671 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
672 define void @test_cos(half* %p) #0 {
673   %a = load half, half* %p, align 2
674   %r = call half @llvm.cos.f16(half %a)
675   store half %r, half* %p
676   ret void
677 }
678
679 ; CHECK-FP16-LABEL: test_pow:
680 ; CHECK-FP16-NEXT: .fnstart
681 ; CHECK-FP16-NEXT: push {r4, lr}
682 ; CHECK-FP16-NEXT: mov r4, r0
683 ; CHECK-FP16-NEXT: ldrh r0, [r1]
684 ; CHECK-FP16-NEXT: ldrh r1, [r4]
685 ; CHECK-FP16-NEXT: vmov s2, r0
686 ; CHECK-FP16-NEXT: vmov s0, r1
687 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
688 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
689 ; CHECK-FP16-NEXT: vmov r0, s0
690 ; CHECK-FP16-NEXT: vmov r1, s2
691 ; CHECK-FP16-NEXT: bl powf
692 ; CHECK-FP16-NEXT: vmov s0, r0
693 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
694 ; CHECK-FP16-NEXT: vmov r0, s0
695 ; CHECK-FP16-NEXT: strh r0, [r4]
696 ; CHECK-FP16-NEXT: pop {r4, pc}
697 ; CHECK-LIBCALL-LABEL: test_pow:
698 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
699 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
700 ; CHECK-LIBCALL: bl powf
701 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
702 define void @test_pow(half* %p, half* %q) #0 {
703   %a = load half, half* %p, align 2
704   %b = load half, half* %q, align 2
705   %r = call half @llvm.pow.f16(half %a, half %b)
706   store half %r, half* %p
707   ret void
708 }
709
710 ; CHECK-FP16-LABEL: test_exp:
711 ; CHECK-FP16-NEXT: .fnstart
712 ; CHECK-FP16-NEXT: push {r4, lr}
713 ; CHECK-FP16-NEXT: mov r4, r0
714 ; CHECK-FP16-NEXT: ldrh r0, [r4]
715 ; CHECK-FP16-NEXT: vmov s0, r0
716 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
717 ; CHECK-FP16-NEXT: vmov r0, s0
718 ; CHECK-FP16-NEXT: bl expf
719 ; CHECK-FP16-NEXT: vmov s0, r0
720 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
721 ; CHECK-FP16-NEXT: vmov r0, s0
722 ; CHECK-FP16-NEXT: strh r0, [r4]
723 ; CHECK-FP16-NEXT: pop {r4, pc}
724 ; CHECK-LIBCALL-LABEL: test_exp:
725 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
726 ; CHECK-LIBCALL: bl expf
727 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
728 define void @test_exp(half* %p) #0 {
729   %a = load half, half* %p, align 2
730   %r = call half @llvm.exp.f16(half %a)
731   store half %r, half* %p
732   ret void
733 }
734
735 ; CHECK-FP16-LABEL: test_exp2:
736 ; CHECK-FP16-NEXT: .fnstart
737 ; CHECK-FP16-NEXT: push {r4, lr}
738 ; CHECK-FP16-NEXT: mov r4, r0
739 ; CHECK-FP16-NEXT: ldrh r0, [r4]
740 ; CHECK-FP16-NEXT: vmov s0, r0
741 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
742 ; CHECK-FP16-NEXT: vmov r0, s0
743 ; CHECK-FP16-NEXT: bl exp2f
744 ; CHECK-FP16-NEXT: vmov s0, r0
745 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
746 ; CHECK-FP16-NEXT: vmov r0, s0
747 ; CHECK-FP16-NEXT: strh r0, [r4]
748 ; CHECK-FP16-NEXT: pop {r4, pc}
749 ; CHECK-LIBCALL-LABEL: test_exp2:
750 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
751 ; CHECK-LIBCALL: bl exp2f
752 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
753 define void @test_exp2(half* %p) #0 {
754   %a = load half, half* %p, align 2
755   %r = call half @llvm.exp2.f16(half %a)
756   store half %r, half* %p
757   ret void
758 }
759
760 ; CHECK-FP16-LABEL: test_log:
761 ; CHECK-FP16-NEXT: .fnstart
762 ; CHECK-FP16-NEXT: push {r4, lr}
763 ; CHECK-FP16-NEXT: mov r4, r0
764 ; CHECK-FP16-NEXT: ldrh r0, [r4]
765 ; CHECK-FP16-NEXT: vmov s0, r0
766 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
767 ; CHECK-FP16-NEXT: vmov r0, s0
768 ; CHECK-FP16-NEXT: bl logf
769 ; CHECK-FP16-NEXT: vmov s0, r0
770 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
771 ; CHECK-FP16-NEXT: vmov r0, s0
772 ; CHECK-FP16-NEXT: strh r0, [r4]
773 ; CHECK-FP16-NEXT: pop {r4, pc}
774 ; CHECK-LIBCALL-LABEL: test_log:
775 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
776 ; CHECK-LIBCALL: bl logf
777 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
778 define void @test_log(half* %p) #0 {
779   %a = load half, half* %p, align 2
780   %r = call half @llvm.log.f16(half %a)
781   store half %r, half* %p
782   ret void
783 }
784
785 ; CHECK-FP16-LABEL: test_log10:
786 ; CHECK-FP16-NEXT: .fnstart
787 ; CHECK-FP16-NEXT: push {r4, lr}
788 ; CHECK-FP16-NEXT: mov r4, r0
789 ; CHECK-FP16-NEXT: ldrh r0, [r4]
790 ; CHECK-FP16-NEXT: vmov s0, r0
791 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
792 ; CHECK-FP16-NEXT: vmov r0, s0
793 ; CHECK-FP16-NEXT: bl log10f
794 ; CHECK-FP16-NEXT: vmov s0, r0
795 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
796 ; CHECK-FP16-NEXT: vmov r0, s0
797 ; CHECK-FP16-NEXT: strh r0, [r4]
798 ; CHECK-FP16-NEXT: pop {r4, pc}
799 ; CHECK-LIBCALL-LABEL: test_log10:
800 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
801 ; CHECK-LIBCALL: bl log10f
802 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
803 define void @test_log10(half* %p) #0 {
804   %a = load half, half* %p, align 2
805   %r = call half @llvm.log10.f16(half %a)
806   store half %r, half* %p
807   ret void
808 }
809
810 ; CHECK-FP16-LABEL: test_log2:
811 ; CHECK-FP16-NEXT: .fnstart
812 ; CHECK-FP16-NEXT: push {r4, lr}
813 ; CHECK-FP16-NEXT: mov r4, r0
814 ; CHECK-FP16-NEXT: ldrh r0, [r4]
815 ; CHECK-FP16-NEXT: vmov s0, r0
816 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
817 ; CHECK-FP16-NEXT: vmov r0, s0
818 ; CHECK-FP16-NEXT: bl log2f
819 ; CHECK-FP16-NEXT: vmov s0, r0
820 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
821 ; CHECK-FP16-NEXT: vmov r0, s0
822 ; CHECK-FP16-NEXT: strh r0, [r4]
823 ; CHECK-FP16-NEXT: pop {r4, pc}
824 ; CHECK-LIBCALL-LABEL: test_log2:
825 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
826 ; CHECK-LIBCALL: bl log2f
827 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
828 define void @test_log2(half* %p) #0 {
829   %a = load half, half* %p, align 2
830   %r = call half @llvm.log2.f16(half %a)
831   store half %r, half* %p
832   ret void
833 }
834
835 ; CHECK-FP16-LABEL: test_fma:
836 ; CHECK-FP16-NEXT: .fnstart
837 ; CHECK-FP16-NEXT: push {r4, lr}
838 ; CHECK-FP16-NEXT: mov r4, r0
839 ; CHECK-FP16-NEXT: ldrh r0, [r2]
840 ; CHECK-FP16-NEXT: ldrh r1, [r1]
841 ; CHECK-FP16-NEXT: ldrh r2, [r4]
842 ; CHECK-FP16-NEXT: vmov s2, r1
843 ; CHECK-FP16-NEXT: vmov s4, r0
844 ; CHECK-FP16-NEXT: vmov s0, r2
845 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
846 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
847 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s4, s4
848 ; CHECK-FP16-NEXT: vmov r0, s0
849 ; CHECK-FP16-NEXT: vmov r1, s2
850 ; CHECK-FP16-NEXT: vmov r2, s4
851 ; CHECK-FP16-NEXT: bl fmaf
852 ; CHECK-FP16-NEXT: vmov s0, r0
853 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
854 ; CHECK-FP16-NEXT: vmov r0, s0
855 ; CHECK-FP16-NEXT: strh r0, [r4]
856 ; CHECK-FP16-NEXT: pop {r4, pc}
857 ; CHECK-LIBCALL-LABEL: test_fma:
858 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
859 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
860 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
861 ; CHECK-LIBCALL: bl fmaf
862 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
863 define void @test_fma(half* %p, half* %q, half* %r) #0 {
864   %a = load half, half* %p, align 2
865   %b = load half, half* %q, align 2
866   %c = load half, half* %r, align 2
867   %v = call half @llvm.fma.f16(half %a, half %b, half %c)
868   store half %v, half* %p
869   ret void
870 }
871
872 ; CHECK-FP16-LABEL: test_fabs:
873 ; CHECK-FP16-NEXT: .fnstart
874 ; CHECK-FP16-NEXT: ldrh r1, [r0]
875 ; CHECK-FP16-NEXT: vmov s0, r1
876 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
877 ; CHECK-FP16-NEXT: vabs.f32 s0, s0
878 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
879 ; CHECK-FP16-NEXT: vmov r1, s0
880 ; CHECK-FP16-NEXT: strh r1, [r0]
881 ; CHECK-FP16-NEXT: bx lr
882 ; CHECK-LIBCALL-LABEL: test_fabs:
883 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
884 ; CHECK-LIBCALL: bfc
885 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
886 define void @test_fabs(half* %p) {
887   %a = load half, half* %p, align 2
888   %r = call half @llvm.fabs.f16(half %a)
889   store half %r, half* %p
890   ret void
891 }
892
893 ; CHECK-FP16-LABEL: test_minnum:
894 ; CHECK-FP16-NEXT: .fnstart
895 ; CHECK-FP16-NEXT: push {r4, lr}
896 ; CHECK-FP16-NEXT: mov r4, r0
897 ; CHECK-FP16-NEXT: ldrh r0, [r1]
898 ; CHECK-FP16-NEXT: ldrh r1, [r4]
899 ; CHECK-FP16-NEXT: vmov s2, r0
900 ; CHECK-FP16-NEXT: vmov s0, r1
901 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
902 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
903 ; CHECK-FP16-NEXT: vmov r0, s0
904 ; CHECK-FP16-NEXT: vmov r1, s2
905 ; CHECK-FP16-NEXT: bl fminf
906 ; CHECK-FP16-NEXT: vmov s0, r0
907 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
908 ; CHECK-FP16-NEXT: vmov r0, s0
909 ; CHECK-FP16-NEXT: strh r0, [r4]
910 ; CHECK-FP16-NEXT: pop {r4, pc}
911 ; CHECK-LIBCALL-LABEL: test_minnum:
912 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
913 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
914 ; CHECK-LIBCALL: bl fminf
915 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
916 define void @test_minnum(half* %p, half* %q) #0 {
917   %a = load half, half* %p, align 2
918   %b = load half, half* %q, align 2
919   %r = call half @llvm.minnum.f16(half %a, half %b)
920   store half %r, half* %p
921   ret void
922 }
923
924 ; CHECK-FP16-LABEL: test_maxnum:
925 ; CHECK-FP16-NEXT: .fnstart
926 ; CHECK-FP16-NEXT: push {r4, lr}
927 ; CHECK-FP16-NEXT: mov r4, r0
928 ; CHECK-FP16-NEXT: ldrh r0, [r1]
929 ; CHECK-FP16-NEXT: ldrh r1, [r4]
930 ; CHECK-FP16-NEXT: vmov s2, r0
931 ; CHECK-FP16-NEXT: vmov s0, r1
932 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
933 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
934 ; CHECK-FP16-NEXT: vmov r0, s0
935 ; CHECK-FP16-NEXT: vmov r1, s2
936 ; CHECK-FP16-NEXT: bl fmaxf
937 ; CHECK-FP16-NEXT: vmov s0, r0
938 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
939 ; CHECK-FP16-NEXT: vmov r0, s0
940 ; CHECK-FP16-NEXT: strh r0, [r4]
941 ; CHECK-FP16-NEXT: pop {r4, pc}
942 ; CHECK-LIBCALL-LABEL: test_maxnum:
943 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
944 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
945 ; CHECK-LIBCALL: bl fmaxf
946 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
947 define void @test_maxnum(half* %p, half* %q) #0 {
948   %a = load half, half* %p, align 2
949   %b = load half, half* %q, align 2
950   %r = call half @llvm.maxnum.f16(half %a, half %b)
951   store half %r, half* %p
952   ret void
953 }
954
955 ; CHECK-FP16-LABEL: test_copysign:
956 ; CHECK-FP16-NEXT: .fnstart
957 ; CHECK-FP16-NEXT: ldrh r1, [r1]
958 ; CHECK-FP16-NEXT: ldrh r2, [r0]
959 ; CHECK-FP16-NEXT: vmov.i32 d2, #0x80000000
960 ; CHECK-FP16-NEXT: vmov s0, r2
961 ; CHECK-FP16-NEXT: vmov s2, r1
962 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
963 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s2, s2
964 ; CHECK-FP16-NEXT: vbsl d2, d1, d0
965 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s4
966 ; CHECK-FP16-NEXT: vmov r1, s0
967 ; CHECK-FP16-NEXT: strh r1, [r0]
968 ; CHECK-FP16-NEXT: bx lr
969 ; CHECK-LIBCALL-LABEL: test_copysign:
970 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
971 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
972 ; CHECK-LIBCALL: vbsl
973 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
974 define void @test_copysign(half* %p, half* %q) #0 {
975   %a = load half, half* %p, align 2
976   %b = load half, half* %q, align 2
977   %r = call half @llvm.copysign.f16(half %a, half %b)
978   store half %r, half* %p
979   ret void
980 }
981
982 ; CHECK-FP16-LABEL: test_floor:
983 ; CHECK-FP16-NEXT: .fnstart
984 ; CHECK-FP16-NEXT: push {r4, lr}
985 ; CHECK-FP16-NEXT: mov r4, r0
986 ; CHECK-FP16-NEXT: ldrh r0, [r4]
987 ; CHECK-FP16-NEXT: vmov s0, r0
988 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
989 ; CHECK-FP16-NEXT: vmov r0, s0
990 ; CHECK-FP16-NEXT: bl floorf
991 ; CHECK-FP16-NEXT: vmov s0, r0
992 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
993 ; CHECK-FP16-NEXT: vmov r0, s0
994 ; CHECK-FP16-NEXT: strh r0, [r4]
995 ; CHECK-FP16-NEXT: pop {r4, pc}
996 ; CHECK-LIBCALL-LABEL: test_floor:
997 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
998 ; CHECK-LIBCALL: bl floorf
999 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1000 define void @test_floor(half* %p) {
1001   %a = load half, half* %p, align 2
1002   %r = call half @llvm.floor.f16(half %a)
1003   store half %r, half* %p
1004   ret void
1005 }
1006
1007 ; CHECK-FP16-LABEL: test_ceil:
1008 ; CHECK-FP16-NEXT: .fnstart
1009 ; CHECK-FP16-NEXT: push {r4, lr}
1010 ; CHECK-FP16-NEXT: mov r4, r0
1011 ; CHECK-FP16-NEXT: ldrh r0, [r4]
1012 ; CHECK-FP16-NEXT: vmov s0, r0
1013 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1014 ; CHECK-FP16-NEXT: vmov r0, s0
1015 ; CHECK-FP16-NEXT: bl ceilf
1016 ; CHECK-FP16-NEXT: vmov s0, r0
1017 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
1018 ; CHECK-FP16-NEXT: vmov r0, s0
1019 ; CHECK-FP16-NEXT: strh r0, [r4]
1020 ; CHECK-FP16-NEXT: pop {r4, pc}
1021 ; CHECK-LIBCALL-LABEL: test_ceil:
1022 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1023 ; CHECK-LIBCALL: bl ceilf
1024 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1025 define void @test_ceil(half* %p) {
1026   %a = load half, half* %p, align 2
1027   %r = call half @llvm.ceil.f16(half %a)
1028   store half %r, half* %p
1029   ret void
1030 }
1031
1032 ; CHECK-FP16-LABEL: test_trunc:
1033 ; CHECK-FP16-NEXT: .fnstart
1034 ; CHECK-FP16-NEXT: push {r4, lr}
1035 ; CHECK-FP16-NEXT: mov r4, r0
1036 ; CHECK-FP16-NEXT: ldrh r0, [r4]
1037 ; CHECK-FP16-NEXT: vmov s0, r0
1038 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1039 ; CHECK-FP16-NEXT: vmov r0, s0
1040 ; CHECK-FP16-NEXT: bl truncf
1041 ; CHECK-FP16-NEXT: vmov s0, r0
1042 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
1043 ; CHECK-FP16-NEXT: vmov r0, s0
1044 ; CHECK-FP16-NEXT: strh r0, [r4]
1045 ; CHECK-FP16-NEXT: pop {r4, pc}
1046 ; CHECK-LIBCALL-LABEL: test_trunc:
1047 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1048 ; CHECK-LIBCALL: bl truncf
1049 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1050 define void @test_trunc(half* %p) {
1051   %a = load half, half* %p, align 2
1052   %r = call half @llvm.trunc.f16(half %a)
1053   store half %r, half* %p
1054   ret void
1055 }
1056
1057 ; CHECK-FP16-LABEL: test_rint:
1058 ; CHECK-FP16-NEXT: .fnstart
1059 ; CHECK-FP16-NEXT: push {r4, lr}
1060 ; CHECK-FP16-NEXT: mov r4, r0
1061 ; CHECK-FP16-NEXT: ldrh r0, [r4]
1062 ; CHECK-FP16-NEXT: vmov s0, r0
1063 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1064 ; CHECK-FP16-NEXT: vmov r0, s0
1065 ; CHECK-FP16-NEXT: bl rintf
1066 ; CHECK-FP16-NEXT: vmov s0, r0
1067 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
1068 ; CHECK-FP16-NEXT: vmov r0, s0
1069 ; CHECK-FP16-NEXT: strh r0, [r4]
1070 ; CHECK-FP16-NEXT: pop {r4, pc}
1071 ; CHECK-LIBCALL-LABEL: test_rint:
1072 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1073 ; CHECK-LIBCALL: bl rintf
1074 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1075 define void @test_rint(half* %p) {
1076   %a = load half, half* %p, align 2
1077   %r = call half @llvm.rint.f16(half %a)
1078   store half %r, half* %p
1079   ret void
1080 }
1081
1082 ; CHECK-FP16-LABEL: test_nearbyint:
1083 ; CHECK-FP16-NEXT: .fnstart
1084 ; CHECK-FP16-NEXT: push {r4, lr}
1085 ; CHECK-FP16-NEXT: mov r4, r0
1086 ; CHECK-FP16-NEXT: ldrh r0, [r4]
1087 ; CHECK-FP16-NEXT: vmov s0, r0
1088 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1089 ; CHECK-FP16-NEXT: vmov r0, s0
1090 ; CHECK-FP16-NEXT: bl nearbyintf
1091 ; CHECK-FP16-NEXT: vmov s0, r0
1092 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
1093 ; CHECK-FP16-NEXT: vmov r0, s0
1094 ; CHECK-FP16-NEXT: strh r0, [r4]
1095 ; CHECK-FP16-NEXT: pop {r4, pc}
1096 ; CHECK-LIBCALL-LABEL: test_nearbyint:
1097 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1098 ; CHECK-LIBCALL: bl nearbyintf
1099 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1100 define void @test_nearbyint(half* %p) {
1101   %a = load half, half* %p, align 2
1102   %r = call half @llvm.nearbyint.f16(half %a)
1103   store half %r, half* %p
1104   ret void
1105 }
1106
1107 ; CHECK-FP16-LABEL: test_round:
1108 ; CHECK-FP16-NEXT: .fnstart
1109 ; CHECK-FP16-NEXT: push {r4, lr}
1110 ; CHECK-FP16-NEXT: mov r4, r0
1111 ; CHECK-FP16-NEXT: ldrh r0, [r4]
1112 ; CHECK-FP16-NEXT: vmov s0, r0
1113 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1114 ; CHECK-FP16-NEXT: vmov r0, s0
1115 ; CHECK-FP16-NEXT: bl roundf
1116 ; CHECK-FP16-NEXT: vmov s0, r0
1117 ; CHECK-FP16-NEXT: vcvtb.f16.f32 s0, s0
1118 ; CHECK-FP16-NEXT: vmov r0, s0
1119 ; CHECK-FP16-NEXT: strh r0, [r4]
1120 ; CHECK-FP16-NEXT: pop {r4, pc}
1121 ; CHECK-LIBCALL-LABEL: test_round:
1122 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1123 ; CHECK-LIBCALL: bl roundf
1124 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1125 define void @test_round(half* %p) {
1126   %a = load half, half* %p, align 2
1127   %r = call half @llvm.round.f16(half %a)
1128   store half %r, half* %p
1129   ret void
1130 }
1131
1132 ; CHECK-FP16-LABEL: test_fmuladd:
1133 ; CHECK-FP16-NEXT: .fnstart
1134 ; CHECK-FP16-NEXT: ldrh    r2, [r2]
1135 ; CHECK-FP16-NEXT: ldrh    r3, [r0]
1136 ; CHECK-FP16-NEXT: ldrh    r1, [r1]
1137 ; CHECK-FP16-NEXT: vmov    s0, r1
1138 ; CHECK-FP16-NEXT: vmov    s2, r3
1139 ; CHECK-FP16-NEXT: vmov    s4, r2
1140 ; CHECK-FP16-NEXT: vcvtb.f32.f16   s0, s0
1141 ; CHECK-FP16-NEXT: vcvtb.f32.f16   s2, s2
1142 ; CHECK-FP16-NEXT: vcvtb.f32.f16   s4, s4
1143 ; CHECK-FP16-NEXT: vmla.f32        s4, s2, s0
1144 ; CHECK-FP16-NEXT: vcvtb.f16.f32   s0, s4
1145 ; CHECK-FP16-NEXT: vmov    r1, s0
1146 ; CHECK-FP16-NEXT: strh    r1, [r0]
1147 ; CHECK-FP16-NEXT: bx      lr
1148 ; CHECK-LIBCALL-LABEL: test_fmuladd:
1149 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1150 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1151 ; CHECK-LIBCALL: bl __gnu_h2f_ieee
1152 ; CHECK-LIBCALL: vmla.f32
1153 ; CHECK-LIBCALL: bl __gnu_f2h_ieee
1154 define void @test_fmuladd(half* %p, half* %q, half* %r) #0 {
1155   %a = load half, half* %p, align 2
1156   %b = load half, half* %q, align 2
1157   %c = load half, half* %r, align 2
1158   %v = call half @llvm.fmuladd.f16(half %a, half %b, half %c)
1159   store half %v, half* %p
1160   ret void
1161 }
1162
1163 ; f16 vectors are not legal in the backend.  Vector elements are not assigned
1164 ; to the register, but are stored in the stack instead.  Hence insertelement
1165 ; and extractelement have these extra loads and stores.
1166
1167 ; CHECK-ALL-LABEL: test_insertelement:
1168 ; CHECK-ALL-NEXT: .fnstart
1169 ; CHECK-ALL-NEXT: sub sp, sp, #8
1170 ; CHECK-ALL-NEXT: ldrh r3, [r1, #6]
1171 ; CHECK-ALL-NEXT: strh r3, [sp, #6]
1172 ; CHECK-ALL-NEXT: ldrh r3, [r1, #4]
1173 ; CHECK-ALL-NEXT: strh r3, [sp, #4]
1174 ; CHECK-ALL-NEXT: ldrh r3, [r1, #2]
1175 ; CHECK-ALL-NEXT: strh r3, [sp, #2]
1176 ; CHECK-ALL-NEXT: ldrh r3, [r1]
1177 ; CHECK-ALL-NEXT: strh r3, [sp]
1178 ; CHECK-ALL-NEXT: mov r3, sp
1179 ; CHECK-ALL-NEXT: ldrh r0, [r0]
1180 ; CHECK-ALL-NEXT: add r2, r3, r2, lsl #1
1181 ; CHECK-ALL-NEXT: strh r0, [r2]
1182 ; CHECK-ALL-NEXT: ldrh r0, [sp, #6]
1183 ; CHECK-ALL-NEXT: strh r0, [r1, #6]
1184 ; CHECK-ALL-NEXT: ldrh r0, [sp, #4]
1185 ; CHECK-ALL-NEXT: strh r0, [r1, #4]
1186 ; CHECK-ALL-NEXT: ldrh r0, [sp, #2]
1187 ; CHECK-ALL-NEXT: strh r0, [r1, #2]
1188 ; CHECK-ALL-NEXT: ldrh r0, [sp]
1189 ; CHECK-ALL-NEXT: strh r0, [r1]
1190 ; CHECK-ALL-NEXT: add sp, sp, #8
1191 ; CHECK-ALL-NEXT: bx lr
1192 define void @test_insertelement(half* %p, <4 x half>* %q, i32 %i) #0 {
1193   %a = load half, half* %p, align 2
1194   %b = load <4 x half>, <4 x half>* %q, align 8
1195   %c = insertelement <4 x half> %b, half %a, i32 %i
1196   store <4 x half> %c, <4 x half>* %q
1197   ret void
1198 }
1199
1200 ; CHECK-ALL-LABEL: test_extractelement:
1201 ; CHECK-ALL-NEXT: .fnstart
1202 ; CHECK-ALL-NEXT: sub sp, sp, #8
1203 ; CHECK-ALL-NEXT: ldrh r12, [r1, #2]
1204 ; CHECK-ALL-NEXT: ldrh r3, [r1]
1205 ; CHECK-ALL-NEXT: orr r3, r3, r12, lsl #16
1206 ; CHECK-ALL-NEXT: str r3, [sp]
1207 ; CHECK-ALL-NEXT: ldrh r3, [r1, #6]
1208 ; CHECK-ALL-NEXT: ldrh r1, [r1, #4]
1209 ; CHECK-ALL-NEXT: orr r1, r1, r3, lsl #16
1210 ; CHECK-ALL-NEXT: str r1, [sp, #4]
1211 ; CHECK-ALL-NEXT: mov r1, sp
1212 ; CHECK-ALL-NEXT: add r1, r1, r2, lsl #1
1213 ; CHECK-ALL-NEXT: ldrh r1, [r1]
1214 ; CHECK-ALL-NEXT: strh r1, [r0]
1215 ; CHECK-ALL-NEXT: add sp, sp, #8
1216 ; CHECK-ALL-NEXT: bx lr
1217 define void @test_extractelement(half* %p, <4 x half>* %q, i32 %i) #0 {
1218   %a = load <4 x half>, <4 x half>* %q, align 8
1219   %b = extractelement <4 x half> %a, i32 %i
1220   store half %b, half* %p
1221   ret void
1222 }
1223
1224 ; test struct operations
1225
1226 %struct.dummy = type { i32, half }
1227
1228 ; CHECK-ALL-LABEL: test_insertvalue:
1229 ; CHECK-ALL-NEXT: .fnstart
1230 ; CHECK-ALL-NEXT: ldr r2, [r0]
1231 ; CHECK-ALL-NEXT: ldrh r1, [r1]
1232 ; CHECK-ALL-NEXT: strh r1, [r0, #4]
1233 ; CHECK-ALL-NEXT: str r2, [r0]
1234 ; CHECK-ALL-NEXT: bx lr
1235 define void @test_insertvalue(%struct.dummy* %p, half* %q) {
1236   %a = load %struct.dummy, %struct.dummy* %p
1237   %b = load half, half* %q
1238   %c = insertvalue %struct.dummy %a, half %b, 1
1239   store %struct.dummy %c, %struct.dummy* %p
1240   ret void
1241 }
1242
1243 ; CHECK-ALL-LABEL: test_extractvalue:
1244 ; CHECK-ALL-NEXT: .fnstart
1245 ; CHECK-ALL-NEXT: ldrh r0, [r0, #4]
1246 ; CHECK-ALL-NEXT: strh r0, [r1]
1247 ; CHECK-ALL-NEXT: bx lr
1248 define void @test_extractvalue(%struct.dummy* %p, half* %q) {
1249   %a = load %struct.dummy, %struct.dummy* %p
1250   %b = extractvalue %struct.dummy %a, 1
1251   store half %b, half* %q
1252   ret void
1253 }
1254
1255 ; CHECK-FP16-LABEL: test_struct_return:
1256 ; CHECK-FP16-NEXT: .fnstart
1257 ; CHECK-FP16-NEXT: ldr r2, [r0]
1258 ; CHECK-FP16-NEXT: ldrh r0, [r0, #4]
1259 ; CHECK-FP16-NEXT: vmov s0, r0
1260 ; CHECK-FP16-NEXT: mov r0, r2
1261 ; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0
1262 ; CHECK-FP16-NEXT: vmov r1, s0
1263 ; CHECK-FP16-NEXT: bx lr
1264 ; CHECK-LIBCALL-LABEL: test_struct_return:
1265 ; CHECK-LIBCALL-NEXT: .fnstart
1266 ; CHECK-LIBCALL-NEXT: push {r4, lr}
1267 ; CHECK-LIBCALL-NEXT: ldr r4, [r0]
1268 ; CHECK-LIBCALL-NEXT: ldrh r0, [r0, #4]
1269 ; CHECK-LIBCALL-NEXT: bl __gnu_h2f_ieee
1270 ; CHECK-LIBCALL-NEXT: mov r1, r0
1271 ; CHECK-LIBCALL-NEXT: mov r0, r4
1272 ; CHECK-LIBCALL-NEXT: pop {r4, pc}
1273 define %struct.dummy @test_struct_return(%struct.dummy* %p) {
1274   %a = load %struct.dummy, %struct.dummy* %p
1275   ret %struct.dummy %a
1276 }
1277
1278 ; CHECK-ALL-LABEL: test_struct_arg:
1279 ; CHECK-ALL-NEXT: .fnstart
1280 ; CHECK-ALL-NEXT: mov r0, r1
1281 ; CHECK-ALL-NEXT: bx lr
1282 define half @test_struct_arg(%struct.dummy %p) {
1283   %a = extractvalue %struct.dummy %p, 1
1284   ret half %a
1285 }
1286
1287 attributes #0 = { nounwind }