1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=-f16c | FileCheck %s -check-prefix=LIBCALL
3; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=+f16c | FileCheck %s -check-prefix=F16C
4; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=-f16c,+soft-float | FileCheck %s -check-prefix=SOFTFLOAT
5; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -mattr=+f16c,+soft-float | FileCheck %s -check-prefix=SOFTFLOAT
6
7; This is a test for float to half float conversions on x86-64.
8;
9; If flag -soft-float is set, or if there is no F16C support, then:
10; 1) half float to float conversions are
11;    translated into calls to __gnu_h2f_ieee defined
12;    by the compiler runtime library;
13; 2) float to half float conversions are translated into calls
14;    to __gnu_f2h_ieee which expected to be defined by the
15;    compiler runtime library.
16;
17; Otherwise (we have F16C support):
18; 1) half float to float conversion are translated using
19;    vcvtph2ps instructions;
20; 2) float to half float conversions are translated using
21;    vcvtps2ph instructions
22
23
24define void @test1(float %src, i16* %dest) {
25; LIBCALL-LABEL: test1:
26; LIBCALL:       # %bb.0:
27; LIBCALL-NEXT:    pushq %rbx
28; LIBCALL-NEXT:    .cfi_def_cfa_offset 16
29; LIBCALL-NEXT:    .cfi_offset %rbx, -16
30; LIBCALL-NEXT:    movq %rdi, %rbx
31; LIBCALL-NEXT:    callq __gnu_f2h_ieee
32; LIBCALL-NEXT:    movw %ax, (%rbx)
33; LIBCALL-NEXT:    popq %rbx
34; LIBCALL-NEXT:    .cfi_def_cfa_offset 8
35; LIBCALL-NEXT:    retq
36;
37; F16C-LABEL: test1:
38; F16C:       # %bb.0:
39; F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
40; F16C-NEXT:    vpextrw $0, %xmm0, (%rdi)
41; F16C-NEXT:    retq
42;
43; SOFTFLOAT-LABEL: test1:
44; SOFTFLOAT:       # %bb.0:
45; SOFTFLOAT-NEXT:    pushq %rbx
46; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 16
47; SOFTFLOAT-NEXT:    .cfi_offset %rbx, -16
48; SOFTFLOAT-NEXT:    movq %rsi, %rbx
49; SOFTFLOAT-NEXT:    callq __gnu_f2h_ieee
50; SOFTFLOAT-NEXT:    movw %ax, (%rbx)
51; SOFTFLOAT-NEXT:    popq %rbx
52; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 8
53; SOFTFLOAT-NEXT:    retq
54  %1 = tail call i16 @llvm.convert.to.fp16.f32(float %src)
55  store i16 %1, i16* %dest, align 2
56  ret void
57}
58
59define float @test2(i16* nocapture %src) {
60; LIBCALL-LABEL: test2:
61; LIBCALL:       # %bb.0:
62; LIBCALL-NEXT:    movzwl (%rdi), %edi
63; LIBCALL-NEXT:    jmp __gnu_h2f_ieee@PLT # TAILCALL
64;
65; F16C-LABEL: test2:
66; F16C:       # %bb.0:
67; F16C-NEXT:    movzwl (%rdi), %eax
68; F16C-NEXT:    vmovd %eax, %xmm0
69; F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
70; F16C-NEXT:    retq
71;
72; SOFTFLOAT-LABEL: test2:
73; SOFTFLOAT:       # %bb.0:
74; SOFTFLOAT-NEXT:    pushq %rax
75; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 16
76; SOFTFLOAT-NEXT:    movzwl (%rdi), %edi
77; SOFTFLOAT-NEXT:    callq __gnu_h2f_ieee
78; SOFTFLOAT-NEXT:    popq %rcx
79; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 8
80; SOFTFLOAT-NEXT:    retq
81  %1 = load i16, i16* %src, align 2
82  %2 = tail call float @llvm.convert.from.fp16.f32(i16 %1)
83  ret float %2
84}
85
86define float @test3(float %src) nounwind uwtable readnone {
87; LIBCALL-LABEL: test3:
88; LIBCALL:       # %bb.0:
89; LIBCALL-NEXT:    pushq %rax
90; LIBCALL-NEXT:    .cfi_def_cfa_offset 16
91; LIBCALL-NEXT:    callq __gnu_f2h_ieee
92; LIBCALL-NEXT:    movzwl %ax, %edi
93; LIBCALL-NEXT:    popq %rax
94; LIBCALL-NEXT:    .cfi_def_cfa_offset 8
95; LIBCALL-NEXT:    jmp __gnu_h2f_ieee@PLT # TAILCALL
96;
97; F16C-LABEL: test3:
98; F16C:       # %bb.0:
99; F16C-NEXT:    vcvtps2ph $4, %xmm0, %xmm0
100; F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
101; F16C-NEXT:    retq
102;
103; SOFTFLOAT-LABEL: test3:
104; SOFTFLOAT:       # %bb.0:
105; SOFTFLOAT-NEXT:    pushq %rax
106; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 16
107; SOFTFLOAT-NEXT:    callq __gnu_f2h_ieee
108; SOFTFLOAT-NEXT:    movzwl %ax, %edi
109; SOFTFLOAT-NEXT:    callq __gnu_h2f_ieee
110; SOFTFLOAT-NEXT:    popq %rcx
111; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 8
112; SOFTFLOAT-NEXT:    retq
113  %1 = tail call i16 @llvm.convert.to.fp16.f32(float %src)
114  %2 = tail call float @llvm.convert.from.fp16.f32(i16 %1)
115  ret float %2
116}
117
118define double @test4(i16* nocapture %src) {
119; LIBCALL-LABEL: test4:
120; LIBCALL:       # %bb.0:
121; LIBCALL-NEXT:    pushq %rax
122; LIBCALL-NEXT:    .cfi_def_cfa_offset 16
123; LIBCALL-NEXT:    movzwl (%rdi), %edi
124; LIBCALL-NEXT:    callq __gnu_h2f_ieee
125; LIBCALL-NEXT:    cvtss2sd %xmm0, %xmm0
126; LIBCALL-NEXT:    popq %rax
127; LIBCALL-NEXT:    .cfi_def_cfa_offset 8
128; LIBCALL-NEXT:    retq
129;
130; F16C-LABEL: test4:
131; F16C:       # %bb.0:
132; F16C-NEXT:    movzwl (%rdi), %eax
133; F16C-NEXT:    vmovd %eax, %xmm0
134; F16C-NEXT:    vcvtph2ps %xmm0, %xmm0
135; F16C-NEXT:    vcvtss2sd %xmm0, %xmm0, %xmm0
136; F16C-NEXT:    retq
137;
138; SOFTFLOAT-LABEL: test4:
139; SOFTFLOAT:       # %bb.0:
140; SOFTFLOAT-NEXT:    pushq %rax
141; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 16
142; SOFTFLOAT-NEXT:    movzwl (%rdi), %edi
143; SOFTFLOAT-NEXT:    callq __gnu_h2f_ieee
144; SOFTFLOAT-NEXT:    movl %eax, %edi
145; SOFTFLOAT-NEXT:    callq __extendsfdf2
146; SOFTFLOAT-NEXT:    popq %rcx
147; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 8
148; SOFTFLOAT-NEXT:    retq
149  %1 = load i16, i16* %src, align 2
150  %2 = tail call double @llvm.convert.from.fp16.f64(i16 %1)
151  ret double %2
152}
153
154define i16 @test5(double %src) {
155; LIBCALL-LABEL: test5:
156; LIBCALL:       # %bb.0:
157; LIBCALL-NEXT:    jmp __truncdfhf2@PLT # TAILCALL
158;
159; F16C-LABEL: test5:
160; F16C:       # %bb.0:
161; F16C-NEXT:    jmp __truncdfhf2@PLT # TAILCALL
162;
163; SOFTFLOAT-LABEL: test5:
164; SOFTFLOAT:       # %bb.0:
165; SOFTFLOAT-NEXT:    pushq %rax
166; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 16
167; SOFTFLOAT-NEXT:    callq __truncdfhf2
168; SOFTFLOAT-NEXT:    popq %rcx
169; SOFTFLOAT-NEXT:    .cfi_def_cfa_offset 8
170; SOFTFLOAT-NEXT:    retq
171  %val = tail call i16 @llvm.convert.to.fp16.f64(double %src)
172  ret i16 %val
173}
174
175declare float @llvm.convert.from.fp16.f32(i16) nounwind readnone
176declare i16 @llvm.convert.to.fp16.f32(float) nounwind readnone
177declare double @llvm.convert.from.fp16.f64(i16) nounwind readnone
178declare i16 @llvm.convert.to.fp16.f64(double) nounwind readnone
179