1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=i686-apple-darwin | FileCheck %s --check-prefix=X32-NOF16C
3; RUN: llc < %s -mtriple=i686-apple-darwin -mattr=f16c | FileCheck %s --check-prefix=X32-F16C
4; RUN: llc < %s -mtriple=x86_64-apple-darwin | FileCheck %s --check-prefix=X64-NOF16C
5; RUN: llc < %s -mtriple=x86_64-apple-darwin -mattr=f16c | FileCheck %s --check-prefix=X64-F16C
6
7@a = global half 0xH0000, align 2
8@b = global half 0xH0000, align 2
9@c = global half 0xH0000, align 2
10
11define float @half_to_float() strictfp {
12; X32-NOF16C-LABEL: half_to_float:
13; X32-NOF16C:       ## %bb.0:
14; X32-NOF16C-NEXT:    subl $12, %esp
15; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
16; X32-NOF16C-NEXT:    movzwl _a, %eax
17; X32-NOF16C-NEXT:    movl %eax, (%esp)
18; X32-NOF16C-NEXT:    calll ___extendhfsf2
19; X32-NOF16C-NEXT:    addl $12, %esp
20; X32-NOF16C-NEXT:    retl
21;
22; X32-F16C-LABEL: half_to_float:
23; X32-F16C:       ## %bb.0:
24; X32-F16C-NEXT:    pushl %eax
25; X32-F16C-NEXT:    .cfi_def_cfa_offset 8
26; X32-F16C-NEXT:    movzwl _a, %eax
27; X32-F16C-NEXT:    vmovd %eax, %xmm0
28; X32-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
29; X32-F16C-NEXT:    vmovss %xmm0, (%esp)
30; X32-F16C-NEXT:    flds (%esp)
31; X32-F16C-NEXT:    wait
32; X32-F16C-NEXT:    popl %eax
33; X32-F16C-NEXT:    retl
34;
35; X64-NOF16C-LABEL: half_to_float:
36; X64-NOF16C:       ## %bb.0:
37; X64-NOF16C-NEXT:    pushq %rax
38; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
39; X64-NOF16C-NEXT:    movzwl _a(%rip), %edi
40; X64-NOF16C-NEXT:    callq ___extendhfsf2
41; X64-NOF16C-NEXT:    popq %rax
42; X64-NOF16C-NEXT:    retq
43;
44; X64-F16C-LABEL: half_to_float:
45; X64-F16C:       ## %bb.0:
46; X64-F16C-NEXT:    movzwl _a(%rip), %eax
47; X64-F16C-NEXT:    vmovd %eax, %xmm0
48; X64-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
49; X64-F16C-NEXT:    retq
50  %1 = load half, half* @a, align 2
51  %2 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %1, metadata !"fpexcept.strict") #0
52  ret float %2
53}
54
55define double @half_to_double() strictfp {
56; X32-NOF16C-LABEL: half_to_double:
57; X32-NOF16C:       ## %bb.0:
58; X32-NOF16C-NEXT:    subl $12, %esp
59; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
60; X32-NOF16C-NEXT:    movzwl _a, %eax
61; X32-NOF16C-NEXT:    movl %eax, (%esp)
62; X32-NOF16C-NEXT:    calll ___extendhfsf2
63; X32-NOF16C-NEXT:    addl $12, %esp
64; X32-NOF16C-NEXT:    retl
65;
66; X32-F16C-LABEL: half_to_double:
67; X32-F16C:       ## %bb.0:
68; X32-F16C-NEXT:    subl $12, %esp
69; X32-F16C-NEXT:    .cfi_def_cfa_offset 16
70; X32-F16C-NEXT:    movzwl _a, %eax
71; X32-F16C-NEXT:    vmovd %eax, %xmm0
72; X32-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
73; X32-F16C-NEXT:    vcvtss2sd %xmm0, %xmm0, %xmm0
74; X32-F16C-NEXT:    vmovsd %xmm0, (%esp)
75; X32-F16C-NEXT:    fldl (%esp)
76; X32-F16C-NEXT:    wait
77; X32-F16C-NEXT:    addl $12, %esp
78; X32-F16C-NEXT:    retl
79;
80; X64-NOF16C-LABEL: half_to_double:
81; X64-NOF16C:       ## %bb.0:
82; X64-NOF16C-NEXT:    pushq %rax
83; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
84; X64-NOF16C-NEXT:    movzwl _a(%rip), %edi
85; X64-NOF16C-NEXT:    callq ___extendhfsf2
86; X64-NOF16C-NEXT:    cvtss2sd %xmm0, %xmm0
87; X64-NOF16C-NEXT:    popq %rax
88; X64-NOF16C-NEXT:    retq
89;
90; X64-F16C-LABEL: half_to_double:
91; X64-F16C:       ## %bb.0:
92; X64-F16C-NEXT:    movzwl _a(%rip), %eax
93; X64-F16C-NEXT:    vmovd %eax, %xmm0
94; X64-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
95; X64-F16C-NEXT:    vcvtss2sd %xmm0, %xmm0, %xmm0
96; X64-F16C-NEXT:    retq
97  %1 = load half, half* @a, align 2
98  %2 = tail call double @llvm.experimental.constrained.fpext.f64.f16(half %1, metadata !"fpexcept.strict") #0
99  ret double %2
100}
101
102define x86_fp80 @half_to_fp80() strictfp {
103; X32-NOF16C-LABEL: half_to_fp80:
104; X32-NOF16C:       ## %bb.0:
105; X32-NOF16C-NEXT:    subl $12, %esp
106; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
107; X32-NOF16C-NEXT:    movzwl _a, %eax
108; X32-NOF16C-NEXT:    movl %eax, (%esp)
109; X32-NOF16C-NEXT:    calll ___extendhfsf2
110; X32-NOF16C-NEXT:    addl $12, %esp
111; X32-NOF16C-NEXT:    retl
112;
113; X32-F16C-LABEL: half_to_fp80:
114; X32-F16C:       ## %bb.0:
115; X32-F16C-NEXT:    pushl %eax
116; X32-F16C-NEXT:    .cfi_def_cfa_offset 8
117; X32-F16C-NEXT:    movzwl _a, %eax
118; X32-F16C-NEXT:    vmovd %eax, %xmm0
119; X32-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
120; X32-F16C-NEXT:    vmovss %xmm0, (%esp)
121; X32-F16C-NEXT:    flds (%esp)
122; X32-F16C-NEXT:    wait
123; X32-F16C-NEXT:    popl %eax
124; X32-F16C-NEXT:    retl
125;
126; X64-NOF16C-LABEL: half_to_fp80:
127; X64-NOF16C:       ## %bb.0:
128; X64-NOF16C-NEXT:    pushq %rax
129; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
130; X64-NOF16C-NEXT:    movzwl _a(%rip), %edi
131; X64-NOF16C-NEXT:    callq ___extendhfsf2
132; X64-NOF16C-NEXT:    movss %xmm0, {{[0-9]+}}(%rsp)
133; X64-NOF16C-NEXT:    flds {{[0-9]+}}(%rsp)
134; X64-NOF16C-NEXT:    wait
135; X64-NOF16C-NEXT:    popq %rax
136; X64-NOF16C-NEXT:    retq
137;
138; X64-F16C-LABEL: half_to_fp80:
139; X64-F16C:       ## %bb.0:
140; X64-F16C-NEXT:    movzwl _a(%rip), %eax
141; X64-F16C-NEXT:    vmovd %eax, %xmm0
142; X64-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
143; X64-F16C-NEXT:    vmovss %xmm0, -{{[0-9]+}}(%rsp)
144; X64-F16C-NEXT:    flds -{{[0-9]+}}(%rsp)
145; X64-F16C-NEXT:    wait
146; X64-F16C-NEXT:    retq
147  %1 = load half, half* @a, align 2
148  %2 = tail call x86_fp80 @llvm.experimental.constrained.fpext.f80.f16(half %1, metadata !"fpexcept.strict") #0
149  ret x86_fp80 %2
150}
151
152define void @float_to_half(float %0) strictfp {
153; X32-NOF16C-LABEL: float_to_half:
154; X32-NOF16C:       ## %bb.0:
155; X32-NOF16C-NEXT:    subl $12, %esp
156; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
157; X32-NOF16C-NEXT:    flds {{[0-9]+}}(%esp)
158; X32-NOF16C-NEXT:    fstps (%esp)
159; X32-NOF16C-NEXT:    wait
160; X32-NOF16C-NEXT:    calll ___truncsfhf2
161; X32-NOF16C-NEXT:    movw %ax, _a
162; X32-NOF16C-NEXT:    addl $12, %esp
163; X32-NOF16C-NEXT:    retl
164;
165; X32-F16C-LABEL: float_to_half:
166; X32-F16C:       ## %bb.0:
167; X32-F16C-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
168; X32-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
169; X32-F16C-NEXT:    vpextrw $0, %xmm0, _a
170; X32-F16C-NEXT:    retl
171;
172; X64-NOF16C-LABEL: float_to_half:
173; X64-NOF16C:       ## %bb.0:
174; X64-NOF16C-NEXT:    pushq %rax
175; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
176; X64-NOF16C-NEXT:    callq ___truncsfhf2
177; X64-NOF16C-NEXT:    movw %ax, _a(%rip)
178; X64-NOF16C-NEXT:    popq %rax
179; X64-NOF16C-NEXT:    retq
180;
181; X64-F16C-LABEL: float_to_half:
182; X64-F16C:       ## %bb.0:
183; X64-F16C-NEXT:    vxorps %xmm1, %xmm1, %xmm1
184; X64-F16C-NEXT:    vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3]
185; X64-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
186; X64-F16C-NEXT:    vpextrw $0, %xmm0, _a(%rip)
187; X64-F16C-NEXT:    retq
188  %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f32(float %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
189  store half %2, half* @a, align 2
190  ret void
191}
192
193define void @double_to_half(double %0) strictfp {
194; X32-NOF16C-LABEL: double_to_half:
195; X32-NOF16C:       ## %bb.0:
196; X32-NOF16C-NEXT:    subl $12, %esp
197; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
198; X32-NOF16C-NEXT:    fldl {{[0-9]+}}(%esp)
199; X32-NOF16C-NEXT:    fstpl (%esp)
200; X32-NOF16C-NEXT:    wait
201; X32-NOF16C-NEXT:    calll ___truncdfhf2
202; X32-NOF16C-NEXT:    movw %ax, _a
203; X32-NOF16C-NEXT:    addl $12, %esp
204; X32-NOF16C-NEXT:    retl
205;
206; X32-F16C-LABEL: double_to_half:
207; X32-F16C:       ## %bb.0:
208; X32-F16C-NEXT:    subl $12, %esp
209; X32-F16C-NEXT:    .cfi_def_cfa_offset 16
210; X32-F16C-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
211; X32-F16C-NEXT:    vmovsd %xmm0, (%esp)
212; X32-F16C-NEXT:    calll ___truncdfhf2
213; X32-F16C-NEXT:    movw %ax, _a
214; X32-F16C-NEXT:    addl $12, %esp
215; X32-F16C-NEXT:    retl
216;
217; X64-NOF16C-LABEL: double_to_half:
218; X64-NOF16C:       ## %bb.0:
219; X64-NOF16C-NEXT:    pushq %rax
220; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
221; X64-NOF16C-NEXT:    callq ___truncdfhf2
222; X64-NOF16C-NEXT:    movw %ax, _a(%rip)
223; X64-NOF16C-NEXT:    popq %rax
224; X64-NOF16C-NEXT:    retq
225;
226; X64-F16C-LABEL: double_to_half:
227; X64-F16C:       ## %bb.0:
228; X64-F16C-NEXT:    pushq %rax
229; X64-F16C-NEXT:    .cfi_def_cfa_offset 16
230; X64-F16C-NEXT:    callq ___truncdfhf2
231; X64-F16C-NEXT:    movw %ax, _a(%rip)
232; X64-F16C-NEXT:    popq %rax
233; X64-F16C-NEXT:    retq
234  %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f64(double %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
235  store half %2, half* @a, align 2
236  ret void
237}
238
239define void @fp80_to_half(x86_fp80 %0) strictfp {
240; X32-NOF16C-LABEL: fp80_to_half:
241; X32-NOF16C:       ## %bb.0:
242; X32-NOF16C-NEXT:    subl $28, %esp
243; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 32
244; X32-NOF16C-NEXT:    fldt {{[0-9]+}}(%esp)
245; X32-NOF16C-NEXT:    fstpt (%esp)
246; X32-NOF16C-NEXT:    wait
247; X32-NOF16C-NEXT:    calll ___truncxfhf2
248; X32-NOF16C-NEXT:    movw %ax, _a
249; X32-NOF16C-NEXT:    addl $28, %esp
250; X32-NOF16C-NEXT:    retl
251;
252; X32-F16C-LABEL: fp80_to_half:
253; X32-F16C:       ## %bb.0:
254; X32-F16C-NEXT:    subl $28, %esp
255; X32-F16C-NEXT:    .cfi_def_cfa_offset 32
256; X32-F16C-NEXT:    fldt {{[0-9]+}}(%esp)
257; X32-F16C-NEXT:    fstpt (%esp)
258; X32-F16C-NEXT:    wait
259; X32-F16C-NEXT:    calll ___truncxfhf2
260; X32-F16C-NEXT:    movw %ax, _a
261; X32-F16C-NEXT:    addl $28, %esp
262; X32-F16C-NEXT:    retl
263;
264; X64-NOF16C-LABEL: fp80_to_half:
265; X64-NOF16C:       ## %bb.0:
266; X64-NOF16C-NEXT:    subq $24, %rsp
267; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 32
268; X64-NOF16C-NEXT:    fldt {{[0-9]+}}(%rsp)
269; X64-NOF16C-NEXT:    fstpt (%rsp)
270; X64-NOF16C-NEXT:    wait
271; X64-NOF16C-NEXT:    callq ___truncxfhf2
272; X64-NOF16C-NEXT:    movw %ax, _a(%rip)
273; X64-NOF16C-NEXT:    addq $24, %rsp
274; X64-NOF16C-NEXT:    retq
275;
276; X64-F16C-LABEL: fp80_to_half:
277; X64-F16C:       ## %bb.0:
278; X64-F16C-NEXT:    subq $24, %rsp
279; X64-F16C-NEXT:    .cfi_def_cfa_offset 32
280; X64-F16C-NEXT:    fldt {{[0-9]+}}(%rsp)
281; X64-F16C-NEXT:    fstpt (%rsp)
282; X64-F16C-NEXT:    wait
283; X64-F16C-NEXT:    callq ___truncxfhf2
284; X64-F16C-NEXT:    movw %ax, _a(%rip)
285; X64-F16C-NEXT:    addq $24, %rsp
286; X64-F16C-NEXT:    retq
287  %2 = tail call half @llvm.experimental.constrained.fptrunc.f16.f80(x86_fp80 %0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
288  store half %2, half* @a, align 2
289  ret void
290}
291
292define void @add() strictfp {
293; X32-NOF16C-LABEL: add:
294; X32-NOF16C:       ## %bb.0:
295; X32-NOF16C-NEXT:    subl $12, %esp
296; X32-NOF16C-NEXT:    .cfi_def_cfa_offset 16
297; X32-NOF16C-NEXT:    movzwl _a, %eax
298; X32-NOF16C-NEXT:    movl %eax, (%esp)
299; X32-NOF16C-NEXT:    calll ___extendhfsf2
300; X32-NOF16C-NEXT:    fstps {{[-0-9]+}}(%e{{[sb]}}p) ## 4-byte Folded Spill
301; X32-NOF16C-NEXT:    wait
302; X32-NOF16C-NEXT:    movzwl _b, %eax
303; X32-NOF16C-NEXT:    movl %eax, (%esp)
304; X32-NOF16C-NEXT:    calll ___extendhfsf2
305; X32-NOF16C-NEXT:    flds {{[-0-9]+}}(%e{{[sb]}}p) ## 4-byte Folded Reload
306; X32-NOF16C-NEXT:    faddp %st, %st(1)
307; X32-NOF16C-NEXT:    fstps (%esp)
308; X32-NOF16C-NEXT:    wait
309; X32-NOF16C-NEXT:    calll ___truncsfhf2
310; X32-NOF16C-NEXT:    movw %ax, _c
311; X32-NOF16C-NEXT:    addl $12, %esp
312; X32-NOF16C-NEXT:    retl
313;
314; X32-F16C-LABEL: add:
315; X32-F16C:       ## %bb.0:
316; X32-F16C-NEXT:    movzwl _a, %eax
317; X32-F16C-NEXT:    vmovd %eax, %xmm0
318; X32-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
319; X32-F16C-NEXT:    movzwl _b, %eax
320; X32-F16C-NEXT:    vmovd %eax, %xmm1
321; X32-F16C-NEXT:    vcvtph2ps %xmm1, %xmm1
322; X32-F16C-NEXT:    vaddss %xmm1, %xmm0, %xmm0
323; X32-F16C-NEXT:    vxorps %xmm1, %xmm1, %xmm1
324; X32-F16C-NEXT:    vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3]
325; X32-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
326; X32-F16C-NEXT:    vpextrw $0, %xmm0, _c
327; X32-F16C-NEXT:    retl
328;
329; X64-NOF16C-LABEL: add:
330; X64-NOF16C:       ## %bb.0:
331; X64-NOF16C-NEXT:    pushq %rax
332; X64-NOF16C-NEXT:    .cfi_def_cfa_offset 16
333; X64-NOF16C-NEXT:    movzwl _a(%rip), %edi
334; X64-NOF16C-NEXT:    callq ___extendhfsf2
335; X64-NOF16C-NEXT:    movss %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) ## 4-byte Spill
336; X64-NOF16C-NEXT:    movzwl _b(%rip), %edi
337; X64-NOF16C-NEXT:    callq ___extendhfsf2
338; X64-NOF16C-NEXT:    addss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 ## 4-byte Folded Reload
339; X64-NOF16C-NEXT:    callq ___truncsfhf2
340; X64-NOF16C-NEXT:    movw %ax, _c(%rip)
341; X64-NOF16C-NEXT:    popq %rax
342; X64-NOF16C-NEXT:    retq
343;
344; X64-F16C-LABEL: add:
345; X64-F16C:       ## %bb.0:
346; X64-F16C-NEXT:    movzwl _a(%rip), %eax
347; X64-F16C-NEXT:    vmovd %eax, %xmm0
348; X64-F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
349; X64-F16C-NEXT:    movzwl _b(%rip), %eax
350; X64-F16C-NEXT:    vmovd %eax, %xmm1
351; X64-F16C-NEXT:    vcvtph2ps %xmm1, %xmm1
352; X64-F16C-NEXT:    vaddss %xmm1, %xmm0, %xmm0
353; X64-F16C-NEXT:    vxorps %xmm1, %xmm1, %xmm1
354; X64-F16C-NEXT:    vblendps {{.*#+}} xmm0 = xmm0[0],xmm1[1,2,3]
355; X64-F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
356; X64-F16C-NEXT:    vpextrw $0, %xmm0, _c(%rip)
357; X64-F16C-NEXT:    retq
358  %1 = load half, half* @a, align 2
359  %2 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %1, metadata !"fpexcept.strict") #0
360  %3 = load half, half* @b, align 2
361  %4 = tail call float @llvm.experimental.constrained.fpext.f32.f16(half %3, metadata !"fpexcept.strict") #0
362  %5 = tail call float @llvm.experimental.constrained.fadd.f32(float %2, float %4, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
363  %6 = tail call half @llvm.experimental.constrained.fptrunc.f16.f32(float %5, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
364  store half %6, half* @c, align 2
365  ret void
366}
367
368declare float @llvm.experimental.constrained.fpext.f32.f16(half, metadata)
369declare double @llvm.experimental.constrained.fpext.f64.f16(half, metadata)
370declare x86_fp80 @llvm.experimental.constrained.fpext.f80.f16(half, metadata)
371declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
372declare half @llvm.experimental.constrained.fptrunc.f16.f32(float, metadata, metadata)
373declare half @llvm.experimental.constrained.fptrunc.f16.f64(double, metadata, metadata)
374declare half @llvm.experimental.constrained.fptrunc.f16.f80(x86_fp80, metadata, metadata)
375
376attributes #0 = { strictfp }
377
378