Skip to content

Commit 6dfea56

Browse files
authored
[builtins] Start to refactor int to fp conversion functions to use a common implementation (#66903)
After this patch, the softfp implementations of floatdidf and floatundidf use a common implementation (int_to_fp.h and int_to_fp_impl.inc). This roughly follows the pattern used for a wide range of other builtins, e.g. fp_trunc_impl.inc. Currently there is substantial copy and paste for the various int to fp conversion functions, with just a few constants being changed. This is a barrier to maintainability, and it's also not attractive to copy this approach as we introduce additional int to fp conversion functions for bf16 and half (which we currently lack, but need - see <https://reviews.llvm.org/D157509>). I've opted to conservatively start by replacing just two functions, leaving a follow-up patch to replace others that follow the same pattern. Also, for better or worse I've left the logic in float[un]didf largely unchanged other than using a similar approach to fp_trunc_impl.inc to remove the constants that are tied to a specific output floating point format.
1 parent 0823cb7 commit 6dfea56

File tree

4 files changed

+130
-91
lines changed

4 files changed

+130
-91
lines changed

compiler-rt/lib/builtins/floatdidf.c

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -45,53 +45,11 @@ COMPILER_RT_ABI double __floatdidf(di_int a) {
4545
// flags to set, and we don't want to code-gen to an unknown soft-float
4646
// implementation.
4747

48-
COMPILER_RT_ABI double __floatdidf(di_int a) {
49-
if (a == 0)
50-
return 0.0;
51-
const unsigned N = sizeof(di_int) * CHAR_BIT;
52-
const di_int s = a >> (N - 1);
53-
a = (du_int)(a ^ s) - s;
54-
int sd = N - __builtin_clzll(a); // number of significant digits
55-
int e = sd - 1; // exponent
56-
if (sd > DBL_MANT_DIG) {
57-
// start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
58-
// finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
59-
// 12345678901234567890123456
60-
// 1 = msb 1 bit
61-
// P = bit DBL_MANT_DIG-1 bits to the right of 1
62-
// Q = bit DBL_MANT_DIG bits to the right of 1
63-
// R = "or" of all bits to the right of Q
64-
switch (sd) {
65-
case DBL_MANT_DIG + 1:
66-
a <<= 1;
67-
break;
68-
case DBL_MANT_DIG + 2:
69-
break;
70-
default:
71-
a = ((du_int)a >> (sd - (DBL_MANT_DIG + 2))) |
72-
((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
73-
};
74-
// finish:
75-
a |= (a & 4) != 0; // Or P into R
76-
++a; // round - this step may add a significant bit
77-
a >>= 2; // dump Q and R
78-
// a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
79-
if (a & ((du_int)1 << DBL_MANT_DIG)) {
80-
a >>= 1;
81-
++e;
82-
}
83-
// a is now rounded to DBL_MANT_DIG bits
84-
} else {
85-
a <<= (DBL_MANT_DIG - sd);
86-
// a is now rounded to DBL_MANT_DIG bits
87-
}
88-
double_bits fb;
89-
fb.u.s.high = ((su_int)s & 0x80000000) | // sign
90-
((su_int)(e + 1023) << 20) | // exponent
91-
((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
92-
fb.u.s.low = (su_int)a; // mantissa-low
93-
return fb.f;
94-
}
48+
#define SRC_I64
49+
#define DST_DOUBLE
50+
#include "int_to_fp_impl.inc"
51+
52+
COMPILER_RT_ABI double __floatdidf(di_int a) { return __floatXiYf__(a); }
9553
#endif
9654

9755
#if defined(__ARM_EABI__)

compiler-rt/lib/builtins/floatundidf.c

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -51,50 +51,11 @@ COMPILER_RT_ABI double __floatundidf(du_int a) {
5151
// flags to set, and we don't want to code-gen to an unknown soft-float
5252
// implementation.
5353

54-
COMPILER_RT_ABI double __floatundidf(du_int a) {
55-
if (a == 0)
56-
return 0.0;
57-
const unsigned N = sizeof(du_int) * CHAR_BIT;
58-
int sd = N - __builtin_clzll(a); // number of significant digits
59-
int e = sd - 1; // exponent
60-
if (sd > DBL_MANT_DIG) {
61-
// start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
62-
// finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
63-
// 12345678901234567890123456
64-
// 1 = msb 1 bit
65-
// P = bit DBL_MANT_DIG-1 bits to the right of 1
66-
// Q = bit DBL_MANT_DIG bits to the right of 1
67-
// R = "or" of all bits to the right of Q
68-
switch (sd) {
69-
case DBL_MANT_DIG + 1:
70-
a <<= 1;
71-
break;
72-
case DBL_MANT_DIG + 2:
73-
break;
74-
default:
75-
a = (a >> (sd - (DBL_MANT_DIG + 2))) |
76-
((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
77-
};
78-
// finish:
79-
a |= (a & 4) != 0; // Or P into R
80-
++a; // round - this step may add a significant bit
81-
a >>= 2; // dump Q and R
82-
// a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
83-
if (a & ((du_int)1 << DBL_MANT_DIG)) {
84-
a >>= 1;
85-
++e;
86-
}
87-
// a is now rounded to DBL_MANT_DIG bits
88-
} else {
89-
a <<= (DBL_MANT_DIG - sd);
90-
// a is now rounded to DBL_MANT_DIG bits
91-
}
92-
double_bits fb;
93-
fb.u.s.high = ((su_int)(e + 1023) << 20) | // exponent
94-
((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
95-
fb.u.s.low = (su_int)a; // mantissa-low
96-
return fb.f;
97-
}
54+
#define SRC_U64
55+
#define DST_DOUBLE
56+
#include "int_to_fp_impl.inc"
57+
58+
COMPILER_RT_ABI double __floatundidf(du_int a) { return __floatXiYf__(a); }
9859
#endif
9960

10061
#if defined(__ARM_EABI__)

compiler-rt/lib/builtins/int_to_fp.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===-- int_to_fp.h - integer to floating point conversion ----------------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Set source and destination defines in order to use a correctly
10+
// parameterised floatXiYf implementation.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef INT_TO_FP_H
15+
#define INT_TO_FP_H
16+
17+
#include "int_lib.h"
18+
19+
#if defined SRC_I64
20+
typedef int64_t src_t;
21+
typedef uint64_t usrc_t;
22+
static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
23+
24+
#elif defined SRC_U64
25+
typedef uint64_t src_t;
26+
typedef uint64_t usrc_t;
27+
static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
28+
29+
#else
30+
#error Source should be a handled integer type.
31+
#endif
32+
33+
#if defined DST_DOUBLE
34+
typedef double dst_t;
35+
typedef uint64_t dst_rep_t;
36+
#define DST_REP_C UINT64_C
37+
static const int dstSigBits = 52;
38+
39+
#else
40+
#error Destination should be a handled floating point type
41+
#endif
42+
43+
static __inline dst_t dstFromRep(dst_rep_t x) {
44+
const union {
45+
dst_t f;
46+
dst_rep_t i;
47+
} rep = {.i = x};
48+
return rep.f;
49+
}
50+
51+
#endif // INT_TO_FP_H
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===-- int_to_fp_impl.inc - integer to floating point conversion ---------===//
2+
//
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
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Thsi file implements a generic conversion from an integer type to an
10+
// IEEE-754 floating point type, allowing a common implementation to be hsared
11+
// without copy and paste.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "int_to_fp.h"
16+
17+
static __inline dst_t __floatXiYf__(src_t a) {
18+
if (a == 0)
19+
return 0.0;
20+
const int dstMantDig = dstSigBits + 1;
21+
const int srcBits = sizeof(src_t) * CHAR_BIT;
22+
const int srcIsSigned = ((src_t)-1) < 0;
23+
const src_t s = srcIsSigned ? a >> (srcBits - 1) : 0;
24+
a = (usrc_t)(a ^ s) - s;
25+
int sd = srcBits - clzSrcT(a); // number of significant digits
26+
int e = sd - 1; // exponent
27+
if (sd > dstMantDig) {
28+
// start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
29+
// finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
30+
// 12345678901234567890123456
31+
// 1 = msb 1 bit
32+
// P = bit dstMantDig-1 bits to the right of 1
33+
// Q = bit dstMantDig bits to the right of 1
34+
// R = "or" of all bits to the right of Q
35+
switch (sd) {
36+
case dstMantDig + 1:
37+
a <<= 1;
38+
break;
39+
case dstMantDig + 2:
40+
break;
41+
default:
42+
a = ((usrc_t)a >> (sd - (dstMantDig + 2))) |
43+
((a & ((usrc_t)(-1) >> ((srcBits + dstMantDig + 2) - sd))) != 0);
44+
};
45+
// finish:
46+
a |= (a & 4) != 0; // Or P into R
47+
++a; // round - this step may add a significant bit
48+
a >>= 2; // dump Q and R
49+
// a is now rounded to dstMantDig or dstMantDig+1 bits
50+
if (a & ((usrc_t)1 << dstMantDig)) {
51+
a >>= 1;
52+
++e;
53+
}
54+
// a is now rounded to dstMantDig bits
55+
} else {
56+
a <<= (dstMantDig - sd);
57+
// a is now rounded to dstMantDig bits
58+
}
59+
const int dstBits = sizeof(dst_t) * CHAR_BIT;
60+
const dst_rep_t dstSignMask = DST_REP_C(1) << (dstBits - 1);
61+
const int dstExpBits = dstBits - dstSigBits - 1;
62+
const int dstExpBias = (1 << (dstExpBits - 1)) - 1;
63+
const dst_rep_t dstSignificandMask = (DST_REP_C(1) << dstSigBits) - 1;
64+
// Combine sign, exponent, and mantissa.
65+
const dst_rep_t result = ((dst_rep_t)s & dstSignMask) |
66+
((dst_rep_t)(e + dstExpBias) << dstSigBits) |
67+
((dst_rep_t)(a) & dstSignificandMask);
68+
return dstFromRep(result);
69+
}

0 commit comments

Comments
 (0)