Skip to content

Commit f1ac850

Browse files
committedMay 12, 2015
[Builtins] Implement half-precision conversions.
Mostly uninteresting, except: - in __extendXfYf2, when checking if the number is normal, the old code relied on the unsignedness of src_rep_t, which is a problem when sizeof(src_rep_t) < sizeof(int): the result gets promoted to int, the signedness of which breaks the comparison. I added an explicit cast; it shouldn't affect other types. - we can't pass __fp16, so src_t and src_rep_t are the same. - the gnu_*_ieee symbols are simply duplicated definitions, as aliases are problematic on mach-o (where only weak aliases are supported; that's not what we want). Differential Revision: http://reviews.llvm.org/D9693 llvm-svn: 237161
1 parent 7a38d75 commit f1ac850

11 files changed

+470
-5
lines changed
 

‎compiler-rt/lib/builtins/CMakeLists.txt

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ set(GENERIC_SOURCES
4444
enable_execute_stack.c
4545
eprintf.c
4646
extendsfdf2.c
47+
extendhfsf2.c
4748
ffsdi2.c
4849
ffsti2.c
4950
fixdfdi.c
@@ -123,7 +124,9 @@ set(GENERIC_SOURCES
123124
subvti3.c
124125
subtf3.c
125126
trampoline_setup.c
127+
truncdfhf2.c
126128
truncdfsf2.c
129+
truncsfhf2.c
127130
ucmpdi2.c
128131
ucmpti2.c
129132
udivdi3.c
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- lib/extendhfsf2.c - half -> single 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+
11+
#define SRC_HALF
12+
#define DST_SINGLE
13+
#include "fp_extend_impl.inc"
14+
15+
COMPILER_RT_ABI float __extendhfsf2(uint16_t a) {
16+
return __extendXfYf2__(a);
17+
}
18+
19+
COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) {
20+
return __extendXfYf2__(a);
21+
}

‎compiler-rt/lib/builtins/fp_extend.h

+16-3
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,24 @@ static inline int src_rep_t_clz(src_rep_t a) {
3939
#endif
4040
}
4141

42+
#elif defined SRC_HALF
43+
typedef uint16_t src_t;
44+
typedef uint16_t src_rep_t;
45+
#define SRC_REP_C UINT16_C
46+
static const int srcSigBits = 10;
47+
#define src_rep_t_clz __builtin_clz
48+
4249
#else
43-
#error Source should be single precision or double precision!
50+
#error Source should be half, single, or double precision!
4451
#endif //end source precision
4552

46-
#if defined DST_DOUBLE
53+
#if defined DST_SINGLE
54+
typedef float dst_t;
55+
typedef uint32_t dst_rep_t;
56+
#define DST_REP_C UINT32_C
57+
static const int dstSigBits = 23;
58+
59+
#elif defined DST_DOUBLE
4760
typedef double dst_t;
4861
typedef uint64_t dst_rep_t;
4962
#define DST_REP_C UINT64_C
@@ -56,7 +69,7 @@ typedef __uint128_t dst_rep_t;
5669
static const int dstSigBits = 112;
5770

5871
#else
59-
#error Destination should be double precision or quad precision!
72+
#error Destination should be single, double, or quad precision!
6073
#endif //end destination precision
6174

6275
// End of specialization parameters. Two helper routines for conversion to and

‎compiler-rt/lib/builtins/fp_extend_impl.inc

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ static inline dst_t __extendXfYf2__(src_t a) {
6666
const src_rep_t sign = aRep & srcSignMask;
6767
dst_rep_t absResult;
6868

69-
if (aAbs - srcMinNormal < srcInfinity - srcMinNormal) {
69+
// If sizeof(src_rep_t) < sizeof(int), the subtraction result is promoted
70+
// to (signed) int. To avoid that, explicitly cast to src_rep_t.
71+
if ((src_rep_t)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
7072
// a is a normal number.
7173
// Extend to the destination type by shifting the significand and
7274
// exponent into the proper position and rebiasing the exponent.

‎compiler-rt/lib/builtins/fp_trunc.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616

1717
#include "int_lib.h"
1818

19-
#if defined SRC_DOUBLE
19+
#if defined SRC_SINGLE
20+
typedef float src_t;
21+
typedef uint32_t src_rep_t;
22+
#define SRC_REP_C UINT32_C
23+
static const int srcSigBits = 23;
24+
25+
#elif defined SRC_DOUBLE
2026
typedef double src_t;
2127
typedef uint64_t src_rep_t;
2228
#define SRC_REP_C UINT64_C
@@ -44,6 +50,12 @@ typedef uint32_t dst_rep_t;
4450
#define DST_REP_C UINT32_C
4551
static const int dstSigBits = 23;
4652

53+
#elif defined DST_HALF
54+
typedef uint16_t dst_t;
55+
typedef uint16_t dst_rep_t;
56+
#define DST_REP_C UINT16_C
57+
static const int dstSigBits = 10;
58+
4759
#else
4860
#error Destination should be single precision or double precision!
4961
#endif //end destination precision

‎compiler-rt/lib/builtins/truncdfhf2.c

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//===-- lib/truncdfhf2.c - double -> 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 SRC_DOUBLE
11+
#define DST_HALF
12+
#include "fp_trunc_impl.inc"
13+
14+
COMPILER_RT_ABI uint16_t __truncdfhf2(double a) {
15+
return __truncXfYf2__(a);
16+
}

‎compiler-rt/lib/builtins/truncsfhf2.c

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//===-- lib/truncsfhf2.c - single -> 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 SRC_SINGLE
11+
#define DST_HALF
12+
#include "fp_trunc_impl.inc"
13+
14+
COMPILER_RT_ABI uint16_t __truncsfhf2(float a) {
15+
return __truncXfYf2__(a);
16+
}
17+
18+
COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) {
19+
return __truncXfYf2__(a);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
//===--------------- extendhfsf2_test.c - Test __extendhfsf2 --------------===//
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+
// This file tests __extendhfsf2 for the compiler_rt library.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include <stdio.h>
15+
16+
#include "fp_test.h"
17+
18+
float __extendhfsf2(uint16_t a);
19+
20+
int test__extendhfsf2(uint16_t a, float expected)
21+
{
22+
float x = __extendhfsf2(a);
23+
int ret = compareResultH(x, expected);
24+
25+
if (ret){
26+
printf("error in test__extendhfsf2(%#.4x) = %f, "
27+
"expected %f\n", a, x, expected);
28+
}
29+
return ret;
30+
}
31+
32+
char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0};
33+
34+
int main()
35+
{
36+
// qNaN
37+
if (test__extendhfsf2(UINT16_C(0x7e00),
38+
makeQNaN32()))
39+
return 1;
40+
// NaN
41+
if (test__extendhfsf2(UINT16_C(0x7e00),
42+
makeNaN32(UINT32_C(0x8000))))
43+
return 1;
44+
// inf
45+
if (test__extendhfsf2(UINT16_C(0x7c00),
46+
makeInf32()))
47+
return 1;
48+
if (test__extendhfsf2(UINT16_C(0xfc00),
49+
-makeInf32()))
50+
return 1;
51+
// zero
52+
if (test__extendhfsf2(UINT16_C(0x0),
53+
0.0f))
54+
return 1;
55+
if (test__extendhfsf2(UINT16_C(0x8000),
56+
-0.0f))
57+
return 1;
58+
59+
if (test__extendhfsf2(UINT16_C(0x4248),
60+
3.1415926535f))
61+
return 1;
62+
if (test__extendhfsf2(UINT16_C(0xc248),
63+
-3.1415926535f))
64+
return 1;
65+
if (test__extendhfsf2(UINT16_C(0x7c00),
66+
0x1.987124876876324p+100f))
67+
return 1;
68+
if (test__extendhfsf2(UINT16_C(0x6e62),
69+
0x1.988p+12f))
70+
return 1;
71+
if (test__extendhfsf2(UINT16_C(0x3c00),
72+
0x1.0p+0f))
73+
return 1;
74+
if (test__extendhfsf2(UINT16_C(0x0400),
75+
0x1.0p-14f))
76+
return 1;
77+
// denormal
78+
if (test__extendhfsf2(UINT16_C(0x0010),
79+
0x1.0p-20f))
80+
return 1;
81+
if (test__extendhfsf2(UINT16_C(0x0001),
82+
0x1.0p-24f))
83+
return 1;
84+
if (test__extendhfsf2(UINT16_C(0x8001),
85+
-0x1.0p-24f))
86+
return 1;
87+
if (test__extendhfsf2(UINT16_C(0x0001),
88+
0x1.5p-25f))
89+
return 1;
90+
// and back to zero
91+
if (test__extendhfsf2(UINT16_C(0x0000),
92+
0x1.0p-25f))
93+
return 1;
94+
if (test__extendhfsf2(UINT16_C(0x8000),
95+
-0x1.0p-25f))
96+
return 1;
97+
// max (precise)
98+
if (test__extendhfsf2(UINT16_C(0x7bff),
99+
65504.0f))
100+
return 1;
101+
// max (rounded)
102+
if (test__extendhfsf2(UINT16_C(0x7bff),
103+
65504.0f))
104+
return 1;
105+
// max (to +inf)
106+
if (test__extendhfsf2(UINT16_C(0x7c00),
107+
makeInf32()))
108+
return 1;
109+
if (test__extendhfsf2(UINT16_C(0xfc00),
110+
-makeInf32()))
111+
return 1;
112+
return 0;
113+
}

‎compiler-rt/test/builtins/Unit/fp_test.h

+43
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ enum EXPECTED_RESULT {
1919
LESS_0, LESS_EQUAL_0, EQUAL_0, GREATER_0, GREATER_EQUAL_0, NEQUAL_0
2020
};
2121

22+
static inline uint16_t fromRep16(uint16_t x)
23+
{
24+
return x;
25+
}
26+
2227
static inline float fromRep32(uint32_t x)
2328
{
2429
float ret;
@@ -41,6 +46,11 @@ static inline long double fromRep128(uint64_t hi, uint64_t lo)
4146
return ret;
4247
}
4348

49+
static inline uint16_t toRep16(uint16_t x)
50+
{
51+
return x;
52+
}
53+
4454
static inline uint32_t toRep32(float x)
4555
{
4656
uint32_t ret;
@@ -62,6 +72,24 @@ static inline __uint128_t toRep128(long double x)
6272
return ret;
6373
}
6474

75+
static inline int compareResultH(uint16_t result,
76+
uint16_t expected)
77+
{
78+
uint16_t rep = toRep16(result);
79+
80+
if (rep == expected){
81+
return 0;
82+
}
83+
// test other posible NaN representation(signal NaN)
84+
else if (expected == 0x7e00U){
85+
if ((rep & 0x7c00U) == 0x7c00U &&
86+
(rep & 0x3ffU) > 0){
87+
return 0;
88+
}
89+
}
90+
return 1;
91+
}
92+
6593
static inline int compareResultF(float result,
6694
uint32_t expected)
6795
{
@@ -177,6 +205,11 @@ static inline char *expectedStr(enum EXPECTED_RESULT expected)
177205
return "";
178206
}
179207

208+
static inline uint16_t makeQNaN16()
209+
{
210+
return fromRep16(0x7e00U);
211+
}
212+
180213
static inline float makeQNaN32()
181214
{
182215
return fromRep32(0x7fc00000U);
@@ -192,6 +225,11 @@ static inline long double makeQNaN128()
192225
return fromRep128(0x7fff800000000000UL, 0x0UL);
193226
}
194227

228+
static inline uint16_t makeNaN16(uint16_t rand)
229+
{
230+
return fromRep16(0x7c00U | (rand & 0x7fffU));
231+
}
232+
195233
static inline float makeNaN32(uint32_t rand)
196234
{
197235
return fromRep32(0x7f800000U | (rand & 0x7fffffU));
@@ -207,6 +245,11 @@ static inline long double makeNaN128(uint64_t rand)
207245
return fromRep128(0x7fff000000000000UL | (rand & 0xffffffffffffUL), 0x0UL);
208246
}
209247

248+
static inline uint16_t makeInf16()
249+
{
250+
return fromRep16(0x7c00U);
251+
}
252+
210253
static inline float makeInf32()
211254
{
212255
return fromRep32(0x7f800000U);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===--------------- truncdfhf2_test.c - Test __truncdfhf2 ----------------===//
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+
// This file tests __truncdfhf2 for the compiler_rt library.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include <stdio.h>
15+
16+
#include "fp_test.h"
17+
18+
uint16_t __truncdfhf2(double a);
19+
20+
int test__truncdfhf2(double a, uint16_t expected)
21+
{
22+
uint16_t x = __truncdfhf2(a);
23+
int ret = compareResultH(x, expected);
24+
25+
if (ret){
26+
printf("error in test__truncdfhf2(%f) = %#.4x, "
27+
"expected %#.4x\n", a, x, fromRep16(expected));
28+
}
29+
return ret;
30+
}
31+
32+
char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0};
33+
34+
int main()
35+
{
36+
// qNaN
37+
if (test__truncdfhf2(makeQNaN64(),
38+
UINT16_C(0x7e00)))
39+
return 1;
40+
// NaN
41+
if (test__truncdfhf2(makeNaN64(UINT64_C(0x8000)),
42+
UINT16_C(0x7e00)))
43+
return 1;
44+
// inf
45+
if (test__truncdfhf2(makeInf64(),
46+
UINT16_C(0x7c00)))
47+
return 1;
48+
if (test__truncdfhf2(-makeInf64(),
49+
UINT16_C(0xfc00)))
50+
return 1;
51+
// zero
52+
if (test__truncdfhf2(0.0, UINT16_C(0x0)))
53+
return 1;
54+
if (test__truncdfhf2(-0.0, UINT16_C(0x8000)))
55+
return 1;
56+
57+
if (test__truncdfhf2(3.1415926535,
58+
UINT16_C(0x4248)))
59+
return 1;
60+
if (test__truncdfhf2(-3.1415926535,
61+
UINT16_C(0xc248)))
62+
return 1;
63+
if (test__truncdfhf2(0x1.987124876876324p+1000,
64+
UINT16_C(0x7c00)))
65+
return 1;
66+
if (test__truncdfhf2(0x1.987124876876324p+12,
67+
UINT16_C(0x6e62)))
68+
return 1;
69+
if (test__truncdfhf2(0x1.0p+0,
70+
UINT16_C(0x3c00)))
71+
return 1;
72+
if (test__truncdfhf2(0x1.0p-14,
73+
UINT16_C(0x0400)))
74+
return 1;
75+
// denormal
76+
if (test__truncdfhf2(0x1.0p-20,
77+
UINT16_C(0x0010)))
78+
return 1;
79+
if (test__truncdfhf2(0x1.0p-24,
80+
UINT16_C(0x0001)))
81+
return 1;
82+
if (test__truncdfhf2(-0x1.0p-24,
83+
UINT16_C(0x8001)))
84+
return 1;
85+
if (test__truncdfhf2(0x1.5p-25,
86+
UINT16_C(0x0001)))
87+
return 1;
88+
// and back to zero
89+
if (test__truncdfhf2(0x1.0p-25,
90+
UINT16_C(0x0000)))
91+
return 1;
92+
if (test__truncdfhf2(-0x1.0p-25,
93+
UINT16_C(0x8000)))
94+
return 1;
95+
// max (precise)
96+
if (test__truncdfhf2(65504.0,
97+
UINT16_C(0x7bff)))
98+
return 1;
99+
// max (rounded)
100+
if (test__truncdfhf2(65519.0,
101+
UINT16_C(0x7bff)))
102+
return 1;
103+
// max (to +inf)
104+
if (test__truncdfhf2(65520.0,
105+
UINT16_C(0x7c00)))
106+
return 1;
107+
if (test__truncdfhf2(-65520.0,
108+
UINT16_C(0xfc00)))
109+
return 1;
110+
return 0;
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//===--------------- truncsfhf2_test.c - Test __truncsfhf2 ----------------===//
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+
// This file tests __truncsfhf2 for the compiler_rt library.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include <stdio.h>
15+
16+
#include "fp_test.h"
17+
18+
uint16_t __truncsfhf2(float a);
19+
20+
int test__truncsfhf2(float a, uint16_t expected)
21+
{
22+
uint16_t x = __truncsfhf2(a);
23+
int ret = compareResultH(x, expected);
24+
25+
if (ret){
26+
printf("error in test__truncsfhf2(%f) = %#.4x, "
27+
"expected %#.4x\n", a, x, fromRep16(expected));
28+
}
29+
return ret;
30+
}
31+
32+
char assumption_1[sizeof(__fp16) * CHAR_BIT == 16] = {0};
33+
34+
int main()
35+
{
36+
// qNaN
37+
if (test__truncsfhf2(makeQNaN32(),
38+
UINT16_C(0x7e00)))
39+
return 1;
40+
// NaN
41+
if (test__truncsfhf2(makeNaN32(UINT32_C(0x8000)),
42+
UINT16_C(0x7e00)))
43+
return 1;
44+
// inf
45+
if (test__truncsfhf2(makeInf32(),
46+
UINT16_C(0x7c00)))
47+
return 1;
48+
if (test__truncsfhf2(-makeInf32(),
49+
UINT16_C(0xfc00)))
50+
return 1;
51+
// zero
52+
if (test__truncsfhf2(0.0f, UINT16_C(0x0)))
53+
return 1;
54+
if (test__truncsfhf2(-0.0f, UINT16_C(0x8000)))
55+
return 1;
56+
57+
if (test__truncsfhf2(3.1415926535f,
58+
UINT16_C(0x4248)))
59+
return 1;
60+
if (test__truncsfhf2(-3.1415926535f,
61+
UINT16_C(0xc248)))
62+
return 1;
63+
if (test__truncsfhf2(0x1.987124876876324p+100f,
64+
UINT16_C(0x7c00)))
65+
return 1;
66+
if (test__truncsfhf2(0x1.987124876876324p+12f,
67+
UINT16_C(0x6e62)))
68+
return 1;
69+
if (test__truncsfhf2(0x1.0p+0f,
70+
UINT16_C(0x3c00)))
71+
return 1;
72+
if (test__truncsfhf2(0x1.0p-14f,
73+
UINT16_C(0x0400)))
74+
return 1;
75+
// denormal
76+
if (test__truncsfhf2(0x1.0p-20f,
77+
UINT16_C(0x0010)))
78+
return 1;
79+
if (test__truncsfhf2(0x1.0p-24f,
80+
UINT16_C(0x0001)))
81+
return 1;
82+
if (test__truncsfhf2(-0x1.0p-24f,
83+
UINT16_C(0x8001)))
84+
return 1;
85+
if (test__truncsfhf2(0x1.5p-25f,
86+
UINT16_C(0x0001)))
87+
return 1;
88+
// and back to zero
89+
if (test__truncsfhf2(0x1.0p-25f,
90+
UINT16_C(0x0000)))
91+
return 1;
92+
if (test__truncsfhf2(-0x1.0p-25f,
93+
UINT16_C(0x8000)))
94+
return 1;
95+
// max (precise)
96+
if (test__truncsfhf2(65504.0f,
97+
UINT16_C(0x7bff)))
98+
return 1;
99+
// max (rounded)
100+
if (test__truncsfhf2(65519.0f,
101+
UINT16_C(0x7bff)))
102+
return 1;
103+
// max (to +inf)
104+
if (test__truncsfhf2(65520.0f,
105+
UINT16_C(0x7c00)))
106+
return 1;
107+
if (test__truncsfhf2(-65520.0f,
108+
UINT16_C(0xfc00)))
109+
return 1;
110+
return 0;
111+
}

0 commit comments

Comments
 (0)
Please sign in to comment.