Skip to content

Commit db61b18

Browse files
committed
[compiler-rt] [builtins] Support conversion between fp16 and fp128
This patch adds both extendhftf2 and trunctfhf2 to support conversion between half-precision and quad-precision floating-point values. They are built iff the compiler supports _Float16. Some notes on ARM plaforms: while fp16 is supported on all architectures, _Float16 is supported only for 32-bit ARM, 64-bit ARM, and SPIR (as indicated by clang/docs/LanguageExtensions.rst). Also, fp16 is a storage format and 64-bit ARM supports floating-point convert precision to half as base armv8-a instruction. This patch does not change the ABI for 32-bit ARM, it will continue to pass _Float16 as uint16. This re-enabled revert done by https://reviews.llvm.org/rGb534beabeed3ba1777cd0ff9ce552d077e496726 Differential Revision: https://reviews.llvm.org/D92242
1 parent e22259f commit db61b18

File tree

5 files changed

+268
-0
lines changed

5 files changed

+268
-0
lines changed

compiler-rt/lib/builtins/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ set(GENERIC_TF_SOURCES
179179
divtc3.c
180180
divtf3.c
181181
extenddftf2.c
182+
extendhftf2.c
182183
extendsftf2.c
183184
fixtfdi.c
184185
fixtfsi.c
@@ -197,6 +198,7 @@ set(GENERIC_TF_SOURCES
197198
powitf2.c
198199
subtf3.c
199200
trunctfdf2.c
201+
trunctfhf2.c
200202
trunctfsf2.c
201203
)
202204

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- lib/extendhftf2.c - half -> quad conversion ---------------*- C -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#define QUAD_PRECISION
11+
#include "fp_lib.h"
12+
13+
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \
14+
defined(COMPILER_RT_HAS_FLOAT16)
15+
#define SRC_HALF
16+
#define DST_QUAD
17+
#include "fp_extend_impl.inc"
18+
19+
COMPILER_RT_ABI long double __extendhftf2(_Float16 a) {
20+
return __extendXfYf2__(a);
21+
}
22+
23+
#endif
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===-- lib/trunctfhf2.c - quad -> half conversion ----------------*- C -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#define QUAD_PRECISION
11+
#include "fp_lib.h"
12+
13+
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \
14+
defined(COMPILER_RT_HAS_FLOAT16)
15+
#define SRC_QUAD
16+
#define DST_HALF
17+
#include "fp_trunc_impl.inc"
18+
19+
COMPILER_RT_ABI _Float16 __trunctfhf2(long double a) {
20+
return __truncXfYf2__(a);
21+
}
22+
23+
#endif
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// RUN: %clang_builtins %s %librt -o %t && %run %t
2+
// REQUIRES: librt_has_extendhftf2
3+
4+
#include "int_lib.h"
5+
#include <stdio.h>
6+
7+
#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16)
8+
9+
#include "fp_test.h"
10+
11+
COMPILER_RT_ABI long double __extendhftf2(TYPE_FP16 a);
12+
13+
int test__extendhftf2(TYPE_FP16 a, uint64_t expectedHi, uint64_t expectedLo) {
14+
long double x = __extendhftf2(a);
15+
int ret = compareResultLD(x, expectedHi, expectedLo);
16+
17+
if (ret) {
18+
printf("error in test__extendhftf2(%#.4x) = %.20Lf, "
19+
"expected %.20Lf\n",
20+
toRep16(a), x,
21+
fromRep128(expectedHi, expectedLo));
22+
}
23+
return ret;
24+
}
25+
26+
char assumption_1[sizeof(TYPE_FP16) * CHAR_BIT == 16] = {0};
27+
28+
#endif
29+
30+
int main() {
31+
#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16)
32+
// qNaN
33+
if (test__extendhftf2(makeQNaN16(),
34+
UINT64_C(0x7fff800000000000),
35+
UINT64_C(0x0)))
36+
return 1;
37+
// NaN
38+
if (test__extendhftf2(makeNaN16(UINT16_C(0x0100)),
39+
UINT64_C(0x7fff400000000000),
40+
UINT64_C(0x0)))
41+
return 1;
42+
// inf
43+
if (test__extendhftf2(makeInf16(),
44+
UINT64_C(0x7fff000000000000),
45+
UINT64_C(0x0)))
46+
return 1;
47+
if (test__extendhftf2(-makeInf16(),
48+
UINT64_C(0xffff000000000000),
49+
UINT64_C(0x0)))
50+
return 1;
51+
// zero
52+
if (test__extendhftf2(fromRep16(0x0U),
53+
UINT64_C(0x0), UINT64_C(0x0)))
54+
return 1;
55+
if (test__extendhftf2(fromRep16(0x8000U),
56+
UINT64_C(0x8000000000000000),
57+
UINT64_C(0x0)))
58+
return 1;
59+
// denormal
60+
if (test__extendhftf2(fromRep16(0x0010U),
61+
UINT64_C(0x3feb000000000000),
62+
UINT64_C(0x0000000000000000)))
63+
return 1;
64+
if (test__extendhftf2(fromRep16(0x0001U),
65+
UINT64_C(0x3fe7000000000000),
66+
UINT64_C(0x0000000000000000)))
67+
return 1;
68+
if (test__extendhftf2(fromRep16(0x8001U),
69+
UINT64_C(0xbfe7000000000000),
70+
UINT64_C(0x0000000000000000)))
71+
return 1;
72+
73+
// pi
74+
if (test__extendhftf2(fromRep16(0x4248U),
75+
UINT64_C(0x4000920000000000),
76+
UINT64_C(0x0000000000000000)))
77+
return 1;
78+
if (test__extendhftf2(fromRep16(0xc248U),
79+
UINT64_C(0xc000920000000000),
80+
UINT64_C(0x0000000000000000)))
81+
return 1;
82+
83+
if (test__extendhftf2(fromRep16(0x508cU),
84+
UINT64_C(0x4004230000000000),
85+
UINT64_C(0x0)))
86+
return 1;
87+
if (test__extendhftf2(fromRep16(0x1bb7U),
88+
UINT64_C(0x3ff6edc000000000),
89+
UINT64_C(0x0)))
90+
return 1;
91+
#else
92+
printf("skipped\n");
93+
#endif
94+
return 0;
95+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// RUN: %clang_builtins %s %librt -o %t && %run %t
2+
// REQUIRES: librt_has_trunctfhf2
3+
4+
#include "int_lib.h"
5+
#include <stdio.h>
6+
7+
#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16)
8+
9+
#include "fp_test.h"
10+
11+
TYPE_FP16 __trunctfhf2(long double a);
12+
13+
int test__trunctfhf2(long double a, uint16_t expected) {
14+
TYPE_FP16 x = __trunctfhf2(a);
15+
int ret = compareResultH(x, expected);
16+
17+
if (ret) {
18+
printf("error in test__trunctfhf2(%.20Lf) = %#.4x, "
19+
"expected %#.4x\n",
20+
a, toRep16(x), expected);
21+
}
22+
return ret;
23+
}
24+
25+
char assumption_1[sizeof(TYPE_FP16) * CHAR_BIT == 16] = {0};
26+
27+
#endif
28+
29+
int main() {
30+
#if __LDBL_MANT_DIG__ == 113 && defined(COMPILER_RT_HAS_FLOAT16)
31+
// qNaN
32+
if (test__trunctfhf2(makeQNaN128(),
33+
UINT16_C(0x7e00)))
34+
return 1;
35+
// NaN
36+
if (test__trunctfhf2(makeNaN128(UINT64_C(0x810000000000)),
37+
UINT16_C(0x7e00)))
38+
return 1;
39+
// inf
40+
if (test__trunctfhf2(makeInf128(),
41+
UINT16_C(0x7c00)))
42+
return 1;
43+
if (test__trunctfhf2(-makeInf128(),
44+
UINT16_C(0xfc00)))
45+
return 1;
46+
// zero
47+
if (test__trunctfhf2(0.0L, UINT16_C(0x0)))
48+
return 1;
49+
if (test__trunctfhf2(-0.0L, UINT16_C(0x8000)))
50+
return 1;
51+
52+
if (test__trunctfhf2(3.1415926535L,
53+
UINT16_C(0x4248)))
54+
return 1;
55+
if (test__trunctfhf2(-3.1415926535L,
56+
UINT16_C(0xc248)))
57+
return 1;
58+
if (test__trunctfhf2(0x1.987124876876324p+100L,
59+
UINT16_C(0x7c00)))
60+
return 1;
61+
if (test__trunctfhf2(0x1.987124876876324p+12L,
62+
UINT16_C(0x6e62)))
63+
return 1;
64+
if (test__trunctfhf2(0x1.0p+0L,
65+
UINT16_C(0x3c00)))
66+
return 1;
67+
if (test__trunctfhf2(0x1.0p-14L,
68+
UINT16_C(0x0400)))
69+
return 1;
70+
// denormal
71+
if (test__trunctfhf2(0x1.0p-20L,
72+
UINT16_C(0x0010)))
73+
return 1;
74+
if (test__trunctfhf2(0x1.0p-24L,
75+
UINT16_C(0x0001)))
76+
return 1;
77+
if (test__trunctfhf2(-0x1.0p-24L,
78+
UINT16_C(0x8001)))
79+
return 1;
80+
if (test__trunctfhf2(0x1.5p-25L,
81+
UINT16_C(0x0001)))
82+
return 1;
83+
// and back to zero
84+
if (test__trunctfhf2(0x1.0p-25L,
85+
UINT16_C(0x0000)))
86+
return 1;
87+
if (test__trunctfhf2(-0x1.0p-25L,
88+
UINT16_C(0x8000)))
89+
return 1;
90+
// max (precise)
91+
if (test__trunctfhf2(65504.0L,
92+
UINT16_C(0x7bff)))
93+
return 1;
94+
// max (rounded)
95+
if (test__trunctfhf2(65519.0L,
96+
UINT16_C(0x7bff)))
97+
return 1;
98+
// max (to +inf)
99+
if (test__trunctfhf2(65520.0L,
100+
UINT16_C(0x7c00)))
101+
return 1;
102+
if (test__trunctfhf2(65536.0L,
103+
UINT16_C(0x7c00)))
104+
return 1;
105+
if (test__trunctfhf2(-65520.0L,
106+
UINT16_C(0xfc00)))
107+
return 1;
108+
109+
if (test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5L,
110+
UINT16_C(0x508f)))
111+
return 1;
112+
if (test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9L,
113+
UINT16_C(0x1b8f)))
114+
return 1;
115+
if (test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453L,
116+
UINT16_C(0x7c00)))
117+
return 1;
118+
if (test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43L,
119+
UINT16_C(0x0)))
120+
return 1;
121+
#else
122+
printf("skipped\n");
123+
#endif
124+
return 0;
125+
}

0 commit comments

Comments
 (0)