Skip to content

Commit 64a9e6f

Browse files
committed
Fix compiler runtime for _Float16 type
1 parent 0ef3648 commit 64a9e6f

File tree

14 files changed

+797
-53
lines changed

14 files changed

+797
-53
lines changed

libc/intrin/float16.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2024 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
20+
/**
21+
* @fileoverview fp16 compiler runtime
22+
*/
23+
24+
#define asint(x) ((union pun){x}).i
25+
#define isnan(x) (((x) & 0x7fff) > 0x7c00)
26+
27+
union pun {
28+
_Float16 f;
29+
unsigned short i;
30+
};
31+
32+
int __eqhf2(_Float16 fx, _Float16 fy) {
33+
int x = asint(fx);
34+
int y = asint(fy);
35+
return (x == y) & !isnan(x) & !isnan(y);
36+
}
37+
38+
int __nehf2(_Float16 fx, _Float16 fy) {
39+
int x = asint(fx);
40+
int y = asint(fy);
41+
return (x != y) & !isnan(x) & !isnan(y);
42+
}

libc/math.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,10 @@ typedef double double_t;
159159
#define fpclassify(x) \
160160
__builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x)
161161

162-
#define signbit(x) \
163-
(sizeof(x) == sizeof(double) ? __builtin_signbit(x) \
164-
: sizeof(x) == sizeof(float) ? __builtin_signbitf(x) \
165-
: __builtin_signbitl(x))
162+
#define signbit(x) \
163+
(sizeof(x) == sizeof(long double) ? __builtin_signbitl(x) \
164+
: sizeof(x) == sizeof(float) ? __builtin_signbitf(x) \
165+
: __builtin_signbit(x))
166166

167167
extern int signgam;
168168

test/math/float16_test.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2024 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/math.h"
20+
21+
#define CHECK(x) \
22+
if (!(x)) return __LINE__
23+
#define FALSE(x) \
24+
{ \
25+
volatile bool x_ = x; \
26+
if (x_) return __LINE__; \
27+
}
28+
#define TRUE(x) \
29+
{ \
30+
volatile bool x_ = x; \
31+
if (!x_) return __LINE__; \
32+
}
33+
34+
_Float16 identity(_Float16 x) {
35+
return x;
36+
}
37+
_Float16 (*half)(_Float16) = identity;
38+
39+
int main() {
40+
volatile float f;
41+
volatile double d;
42+
volatile _Float16 pi = 3.141;
43+
44+
// half → float → half
45+
f = pi;
46+
pi = f;
47+
48+
// half → float
49+
float __extendhfsf2(_Float16);
50+
CHECK(0.f == __extendhfsf2(0));
51+
CHECK(3.140625f == __extendhfsf2(pi));
52+
CHECK(3.140625f == pi);
53+
54+
// half → double → half
55+
d = pi;
56+
pi = d;
57+
58+
// half → double
59+
double __extendhfdf2(_Float16);
60+
CHECK(0. == __extendhfdf2(0));
61+
CHECK(3.140625 == __extendhfdf2(pi));
62+
63+
// float → half
64+
_Float16 __truncsfhf2(float);
65+
CHECK(0 == (float)__truncsfhf2(0));
66+
CHECK(pi == (float)__truncsfhf2(3.141f));
67+
CHECK(3.140625f == (float)__truncsfhf2(3.141f));
68+
69+
// double → half
70+
_Float16 __truncdfhf2(double);
71+
CHECK(0 == (double)__truncdfhf2(0));
72+
CHECK(3.140625 == (double)__truncdfhf2(3.141));
73+
74+
// specials
75+
volatile _Float16 nan = NAN;
76+
volatile _Float16 positive_infinity = +INFINITY;
77+
volatile _Float16 negative_infinity = -INFINITY;
78+
CHECK(isnan(nan));
79+
CHECK(!isinf(pi));
80+
CHECK(!isnan(pi));
81+
CHECK(isinf(positive_infinity));
82+
CHECK(isinf(negative_infinity));
83+
CHECK(!isnan(positive_infinity));
84+
CHECK(!isnan(negative_infinity));
85+
CHECK(!signbit(pi));
86+
CHECK(signbit(half(-pi)));
87+
CHECK(!signbit(half(+0.)));
88+
CHECK(signbit(half(-0.)));
89+
90+
// arithmetic
91+
CHECK(half(-3) == -half(3));
92+
CHECK(half(9) == half(3) * half(3));
93+
CHECK(half(0) == half(pi) - half(pi));
94+
CHECK(half(6.28125) == half(pi) + half(pi));
95+
96+
// comparisons
97+
CHECK(half(3) > half(2));
98+
CHECK(half(3) < half(4));
99+
CHECK(half(3) <= half(3));
100+
CHECK(half(3) >= half(3));
101+
TRUE(half(NAN) != half(NAN));
102+
FALSE(half(NAN) == half(NAN));
103+
TRUE(half(3) != half(NAN));
104+
FALSE(half(3) == half(NAN));
105+
TRUE(half(NAN) != half(3));
106+
FALSE(half(NAN) == half(3));
107+
}

third_party/compiler_rt/extendhfdf2.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===-- lib/extendhfdf2.c - half -> dubble conversion -------------*- C -*-===//
2+
//
3+
// The Cosmopolitan 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_DOUBLE
13+
#include "third_party/compiler_rt/fp16_extend_impl.inc"
14+
15+
COMPILER_RT_ABI dst_t __extendhfdf2(src_t a) {
16+
return __extendXfYf2__(a);
17+
}

third_party/compiler_rt/extendhfsf2.c

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,27 @@
11
//===-- lib/extendhfsf2.c - half -> single conversion -------------*- C -*-===//
22
//
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.
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
76
//
87
//===----------------------------------------------------------------------===//
9-
//
10-
11-
__static_yoink("huge_compiler_rt_license");
128

139
#define SRC_HALF
1410
#define DST_SINGLE
15-
#include "third_party/compiler_rt/fp_extend_impl.inc"
11+
#include "fp16_extend_impl.inc"
1612

1713
// Use a forwarding definition and noinline to implement a poor man's alias,
1814
// as there isn't a good cross-platform way of defining one.
19-
COMPILER_RT_ABI __attribute__((__noinline__)) float __extendhfsf2(uint16_t a) {
20-
return __extendXfYf2__(a);
15+
COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) {
16+
return __extendXfYf2__(a);
2117
}
2218

23-
COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) {
24-
return __extendhfsf2(a);
25-
}
19+
COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); }
2620

2721
#if defined(__ARM_EABI__)
2822
#if defined(COMPILER_RT_ARMHF_TARGET)
29-
AEABI_RTABI float __aeabi_h2f(uint16_t a) {
30-
return __extendhfsf2(a);
31-
}
23+
AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); }
3224
#else
33-
AEABI_RTABI float __aeabi_h2f(uint16_t a) COMPILER_RT_ALIAS(__extendhfsf2);
25+
COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f)
3426
#endif
3527
#endif
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
//===-lib/fp_extend.h - low precision -> high precision conversion -*- C
2+
//-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// Set source and destination setting
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef FP_EXTEND_HEADER
15+
#define FP_EXTEND_HEADER
16+
17+
#include "int_lib.h"
18+
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 srcBits = sizeof(src_t) * CHAR_BIT;
24+
static const int srcSigFracBits = 23;
25+
// -1 accounts for the sign bit.
26+
// srcBits - srcSigFracBits - 1
27+
static const int srcExpBits = 8;
28+
#define src_rep_t_clz clzsi
29+
30+
#elif defined SRC_DOUBLE
31+
typedef double src_t;
32+
typedef uint64_t src_rep_t;
33+
#define SRC_REP_C UINT64_C
34+
static const int srcBits = sizeof(src_t) * CHAR_BIT;
35+
static const int srcSigFracBits = 52;
36+
// -1 accounts for the sign bit.
37+
// srcBits - srcSigFracBits - 1
38+
static const int srcExpBits = 11;
39+
40+
static inline int src_rep_t_clz_impl(src_rep_t a) {
41+
#if defined __LP64__
42+
return __builtin_clzl(a);
43+
#else
44+
if (a & REP_C(0xffffffff00000000))
45+
return clzsi(a >> 32);
46+
else
47+
return 32 + clzsi(a & REP_C(0xffffffff));
48+
#endif
49+
}
50+
#define src_rep_t_clz src_rep_t_clz_impl
51+
52+
#elif defined SRC_80
53+
typedef xf_float src_t;
54+
typedef __uint128_t src_rep_t;
55+
#define SRC_REP_C (__uint128_t)
56+
// sign bit, exponent and significand occupy the lower 80 bits.
57+
static const int srcBits = 80;
58+
static const int srcSigFracBits = 63;
59+
// -1 accounts for the sign bit.
60+
// -1 accounts for the explicitly stored integer bit.
61+
// srcBits - srcSigFracBits - 1 - 1
62+
static const int srcExpBits = 15;
63+
64+
#elif defined SRC_HALF
65+
typedef _Float16 src_t;
66+
typedef uint16_t src_rep_t;
67+
#define SRC_REP_C UINT16_C
68+
static const int srcBits = sizeof(src_t) * CHAR_BIT;
69+
static const int srcSigFracBits = 10;
70+
// -1 accounts for the sign bit.
71+
// srcBits - srcSigFracBits - 1
72+
static const int srcExpBits = 5;
73+
74+
static inline int src_rep_t_clz_impl(src_rep_t a) {
75+
return __builtin_clz(a) - 16;
76+
}
77+
78+
#define src_rep_t_clz src_rep_t_clz_impl
79+
80+
#else
81+
#error Source should be half, single, or double precision!
82+
#endif // end source precision
83+
84+
#if defined DST_SINGLE
85+
typedef float dst_t;
86+
typedef uint32_t dst_rep_t;
87+
#define DST_REP_C UINT32_C
88+
static const int dstBits = sizeof(dst_t) * CHAR_BIT;
89+
static const int dstSigFracBits = 23;
90+
// -1 accounts for the sign bit.
91+
// dstBits - dstSigFracBits - 1
92+
static const int dstExpBits = 8;
93+
94+
#elif defined DST_DOUBLE
95+
typedef double dst_t;
96+
typedef uint64_t dst_rep_t;
97+
#define DST_REP_C UINT64_C
98+
static const int dstBits = sizeof(dst_t) * CHAR_BIT;
99+
static const int dstSigFracBits = 52;
100+
// -1 accounts for the sign bit.
101+
// dstBits - dstSigFracBits - 1
102+
static const int dstExpBits = 11;
103+
104+
#elif defined DST_QUAD
105+
typedef tf_float dst_t;
106+
typedef __uint128_t dst_rep_t;
107+
#define DST_REP_C (__uint128_t)
108+
static const int dstBits = sizeof(dst_t) * CHAR_BIT;
109+
static const int dstSigFracBits = 112;
110+
// -1 accounts for the sign bit.
111+
// dstBits - dstSigFracBits - 1
112+
static const int dstExpBits = 15;
113+
114+
#else
115+
#error Destination should be single, double, or quad precision!
116+
#endif // end destination precision
117+
118+
// End of specialization parameters.
119+
120+
// TODO: These helper routines should be placed into fp_lib.h
121+
// Currently they depend on macros/constants defined above.
122+
123+
static inline src_rep_t extract_sign_from_src(src_rep_t x) {
124+
const src_rep_t srcSignMask = SRC_REP_C(1) << (srcBits - 1);
125+
return (x & srcSignMask) >> (srcBits - 1);
126+
}
127+
128+
static inline src_rep_t extract_exp_from_src(src_rep_t x) {
129+
const int srcSigBits = srcBits - 1 - srcExpBits;
130+
const src_rep_t srcExpMask = ((SRC_REP_C(1) << srcExpBits) - 1) << srcSigBits;
131+
return (x & srcExpMask) >> srcSigBits;
132+
}
133+
134+
static inline src_rep_t extract_sig_frac_from_src(src_rep_t x) {
135+
const src_rep_t srcSigFracMask = (SRC_REP_C(1) << srcSigFracBits) - 1;
136+
return x & srcSigFracMask;
137+
}
138+
139+
#ifdef src_rep_t_clz
140+
static inline int clz_in_sig_frac(src_rep_t sigFrac) {
141+
const int skip = 1 + srcExpBits;
142+
return src_rep_t_clz(sigFrac) - skip;
143+
}
144+
#endif
145+
146+
static inline dst_rep_t construct_dst_rep(dst_rep_t sign, dst_rep_t exp, dst_rep_t sigFrac) {
147+
return (sign << (dstBits - 1)) | (exp << (dstBits - 1 - dstExpBits)) | sigFrac;
148+
}
149+
150+
// Two helper routines for conversion to and from the representation of
151+
// floating-point data as integer values follow.
152+
153+
static inline src_rep_t srcToRep(src_t x) {
154+
const union {
155+
src_t f;
156+
src_rep_t i;
157+
} rep = {.f = x};
158+
return rep.i;
159+
}
160+
161+
static inline dst_t dstFromRep(dst_rep_t x) {
162+
const union {
163+
dst_t f;
164+
dst_rep_t i;
165+
} rep = {.i = x};
166+
return rep.f;
167+
}
168+
// End helper routines. Conversion implementation follows.
169+
170+
#endif // FP_EXTEND_HEADER

0 commit comments

Comments
 (0)