-
Notifications
You must be signed in to change notification settings - Fork 12.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[builtins] Start to refactor int to fp conversion functions to use a …
…common implementation 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.
- Loading branch information
Showing
4 changed files
with
130 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
//===-- int_to_fp.h - integer to floating point conversion ----------------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Set source and destination defines in order to use a correctly | ||
// parameterised floatXiYf implementation. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef INT_TO_FP_H | ||
#define INT_TO_FP_H | ||
|
||
#include "int_lib.h" | ||
|
||
#if defined SRC_I64 | ||
typedef int64_t src_t; | ||
typedef uint64_t usrc_t; | ||
static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); } | ||
|
||
#elif defined SRC_U64 | ||
typedef uint64_t src_t; | ||
typedef uint64_t usrc_t; | ||
static __inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); } | ||
|
||
#else | ||
#error Source should be a handled integer type. | ||
#endif | ||
|
||
#if defined DST_DOUBLE | ||
typedef double dst_t; | ||
typedef uint64_t dst_rep_t; | ||
#define DST_REP_C UINT64_C | ||
static const int dstSigBits = 52; | ||
|
||
#else | ||
#error Destination should be a handled floating point type | ||
#endif | ||
|
||
static __inline dst_t dstFromRep(dst_rep_t x) { | ||
const union { | ||
dst_t f; | ||
dst_rep_t i; | ||
} rep = {.i = x}; | ||
return rep.f; | ||
} | ||
|
||
#endif // INT_TO_FP_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//===-- int_to_fp_impl.inc - integer to floating point conversion ---------===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Thsi file implements a generic conversion from an integer type to an | ||
// IEEE-754 floating point type, allowing a common implementation to be hsared | ||
// without copy and paste. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "int_to_fp.h" | ||
|
||
static __inline dst_t __floatXiYf__(src_t a) { | ||
if (a == 0) | ||
return 0.0; | ||
const int dstMantDig = dstSigBits + 1; | ||
const int srcBits = sizeof(src_t) * CHAR_BIT; | ||
const int srcIsSigned = ((src_t)-1) < 0; | ||
const src_t s = srcIsSigned ? a >> (srcBits - 1) : 0; | ||
a = (usrc_t)(a ^ s) - s; | ||
int sd = srcBits - clzSrcT(a); // number of significant digits | ||
int e = sd - 1; // exponent | ||
if (sd > dstMantDig) { | ||
// start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx | ||
// finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR | ||
// 12345678901234567890123456 | ||
// 1 = msb 1 bit | ||
// P = bit dstMantDig-1 bits to the right of 1 | ||
// Q = bit dstMantDig bits to the right of 1 | ||
// R = "or" of all bits to the right of Q | ||
switch (sd) { | ||
case dstMantDig + 1: | ||
a <<= 1; | ||
break; | ||
case dstMantDig + 2: | ||
break; | ||
default: | ||
a = ((usrc_t)a >> (sd - (dstMantDig + 2))) | | ||
((a & ((usrc_t)(-1) >> ((srcBits + dstMantDig + 2) - sd))) != 0); | ||
}; | ||
// finish: | ||
a |= (a & 4) != 0; // Or P into R | ||
++a; // round - this step may add a significant bit | ||
a >>= 2; // dump Q and R | ||
// a is now rounded to dstMantDig or dstMantDig+1 bits | ||
if (a & ((usrc_t)1 << dstMantDig)) { | ||
a >>= 1; | ||
++e; | ||
} | ||
// a is now rounded to dstMantDig bits | ||
} else { | ||
a <<= (dstMantDig - sd); | ||
// a is now rounded to dstMantDig bits | ||
} | ||
const int dstBits = sizeof(dst_t) * CHAR_BIT; | ||
const dst_rep_t dstSignMask = DST_REP_C(1) << (dstBits - 1); | ||
const int dstExpBits = dstBits - dstSigBits - 1; | ||
const int dstExpBias = (1 << (dstExpBits - 1)) - 1; | ||
const dst_rep_t dstSignificandMask = (DST_REP_C(1) << dstSigBits) - 1; | ||
// Combine sign, exponent, and mantissa. | ||
const dst_rep_t result = ((dst_rep_t)s & dstSignMask) | | ||
((dst_rep_t)(e + dstExpBias) << dstSigBits) | | ||
((dst_rep_t)(a) & dstSignificandMask); | ||
return dstFromRep(result); | ||
} |