]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/compiler-rt/lib/builtins/fp_trunc_impl.inc
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / compiler-rt / lib / builtins / fp_trunc_impl.inc
1 //= lib/fp_trunc_impl.inc - high precision -> low precision 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 // This file implements a fairly generic conversion from a wider to a narrower
10 // IEEE-754 floating-point type in the default (round to nearest, ties to even)
11 // rounding mode.  The constants and types defined following the includes below
12 // parameterize the conversion.
13 //
14 // This routine can be trivially adapted to support conversions to
15 // half-precision or from quad-precision. It does not support types that don't
16 // use the usual IEEE-754 interchange formats; specifically, some work would be
17 // needed to adapt it to (for example) the Intel 80-bit format or PowerPC
18 // double-double format.
19 //
20 // Note please, however, that this implementation is only intended to support
21 // *narrowing* operations; if you need to convert to a *wider* floating-point
22 // type (e.g. float -> double), then this routine will not do what you want it
23 // to.
24 //
25 // It also requires that integer types at least as large as both formats
26 // are available on the target platform; this may pose a problem when trying
27 // to add support for quad on some 32-bit systems, for example.
28 //
29 // Finally, the following assumptions are made:
30 //
31 // 1. Floating-point types and integer types have the same endianness on the
32 //    target platform.
33 //
34 // 2. Quiet NaNs, if supported, are indicated by the leading bit of the
35 //    significand field being set.
36 //
37 //===----------------------------------------------------------------------===//
38
39 #include "fp_trunc.h"
40
41 static __inline dst_t __truncXfYf2__(src_t a) {
42   // Various constants whose values follow from the type parameters.
43   // Any reasonable optimizer will fold and propagate all of these.
44   const int srcBits = sizeof(src_t) * CHAR_BIT;
45   const int srcExpBits = srcBits - srcSigBits - 1;
46   const int srcInfExp = (1 << srcExpBits) - 1;
47   const int srcExpBias = srcInfExp >> 1;
48
49   const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
50   const src_rep_t srcSignificandMask = srcMinNormal - 1;
51   const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
52   const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
53   const src_rep_t srcAbsMask = srcSignMask - 1;
54   const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
55   const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
56   const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
57   const src_rep_t srcNaNCode = srcQNaN - 1;
58
59   const int dstBits = sizeof(dst_t) * CHAR_BIT;
60   const int dstExpBits = dstBits - dstSigBits - 1;
61   const int dstInfExp = (1 << dstExpBits) - 1;
62   const int dstExpBias = dstInfExp >> 1;
63
64   const int underflowExponent = srcExpBias + 1 - dstExpBias;
65   const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
66   const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
67   const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
68
69   const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
70   const dst_rep_t dstNaNCode = dstQNaN - 1;
71
72   // Break a into a sign and representation of the absolute value.
73   const src_rep_t aRep = srcToRep(a);
74   const src_rep_t aAbs = aRep & srcAbsMask;
75   const src_rep_t sign = aRep & srcSignMask;
76   dst_rep_t absResult;
77
78   if (aAbs - underflow < aAbs - overflow) {
79     // The exponent of a is within the range of normal numbers in the
80     // destination format.  We can convert by simply right-shifting with
81     // rounding and adjusting the exponent.
82     absResult = aAbs >> (srcSigBits - dstSigBits);
83     absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
84
85     const src_rep_t roundBits = aAbs & roundMask;
86     // Round to nearest.
87     if (roundBits > halfway)
88       absResult++;
89     // Tie to even.
90     else if (roundBits == halfway)
91       absResult += absResult & 1;
92   } else if (aAbs > srcInfinity) {
93     // a is NaN.
94     // Conjure the result by beginning with infinity, setting the qNaN
95     // bit and inserting the (truncated) trailing NaN field.
96     absResult = (dst_rep_t)dstInfExp << dstSigBits;
97     absResult |= dstQNaN;
98     absResult |=
99         ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
100   } else if (aAbs >= overflow) {
101     // a overflows to infinity.
102     absResult = (dst_rep_t)dstInfExp << dstSigBits;
103   } else {
104     // a underflows on conversion to the destination type or is an exact
105     // zero.  The result may be a denormal or zero.  Extract the exponent
106     // to get the shift amount for the denormalization.
107     const int aExp = aAbs >> srcSigBits;
108     const int shift = srcExpBias - dstExpBias - aExp + 1;
109
110     const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
111
112     // Right shift by the denormalization amount with sticky.
113     if (shift > srcSigBits) {
114       absResult = 0;
115     } else {
116       const bool sticky = significand << (srcBits - shift);
117       src_rep_t denormalizedSignificand = significand >> shift | sticky;
118       absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
119       const src_rep_t roundBits = denormalizedSignificand & roundMask;
120       // Round to nearest
121       if (roundBits > halfway)
122         absResult++;
123       // Ties to even
124       else if (roundBits == halfway)
125         absResult += absResult & 1;
126     }
127   }
128
129   // Apply the signbit to the absolute value.
130   const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
131   return dstFromRep(result);
132 }