kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

int_to_fp_impl.inc (8930B)


      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 // ---- int_to_fp.h (was a separate header; merged) ----
     16 #include "int_lib.h"
     17 
     18 // Self-clean any prior inclusion's per-(src, dst) state. May coexist with
     19 // fp_extend.h / fp_trunc.h which define overlapping bare-name aliases.
     20 #undef _INT_TO_FP_SRC_SUF
     21 #undef _INT_TO_FP_DST_SUF
     22 #undef SRC_REP_C
     23 #undef DST_REP_C
     24 #undef src_t
     25 #undef usrc_t
     26 #undef dst_t
     27 #undef dst_rep_t
     28 #undef clzSrcT
     29 #undef dstFromRep
     30 #undef dstSigBits
     31 
     32 #if defined SRC_I64
     33 #define _INT_TO_FP_SRC_SUF i64
     34 #elif defined SRC_U64
     35 #define _INT_TO_FP_SRC_SUF u64
     36 #elif defined SRC_I128
     37 #define _INT_TO_FP_SRC_SUF i128
     38 #elif defined SRC_U128
     39 #define _INT_TO_FP_SRC_SUF u128
     40 #else
     41 #error Source should be a handled integer type.
     42 #endif
     43 
     44 #if defined DST_SINGLE
     45 #define _INT_TO_FP_DST_SUF sf
     46 #elif defined DST_DOUBLE
     47 #define _INT_TO_FP_DST_SUF df
     48 #elif defined DST_QUAD
     49 #define _INT_TO_FP_DST_SUF tf
     50 #else
     51 #error Destination should be a handled floating point type
     52 #endif
     53 
     54 #define _INT_TO_FP_PASTE4_(a, b, c, d) a##b##c##d
     55 #define _INT_TO_FP_PASTE4(a, b, c, d)  _INT_TO_FP_PASTE4_(a, b, c, d)
     56 #define _INT_TO_FP_PAIR(stem)          _INT_TO_FP_PASTE4(stem, _, _INT_TO_FP_SRC_SUF, _INT_TO_FP_DST_SUF)
     57 
     58 // ---- Bare-name aliases (re-set every inclusion). ------------------------
     59 
     60 #define src_t                       _INT_TO_FP_PAIR(src_t)
     61 #define usrc_t                      _INT_TO_FP_PAIR(usrc_t)
     62 #define dst_t                       _INT_TO_FP_PAIR(dst_t)
     63 #define dst_rep_t                   _INT_TO_FP_PAIR(dst_rep_t)
     64 #define clzSrcT                     _INT_TO_FP_PAIR(clzSrcT)
     65 #define dstFromRep                  _INT_TO_FP_PAIR(dstFromRep)
     66 #define dstSigBits                  _INT_TO_FP_PAIR(dstSigBits)
     67 
     68 // DST_REP_C: simple textual macro per dst.
     69 #if defined DST_SINGLE
     70 #define DST_REP_C UINT32_C
     71 #elif defined DST_DOUBLE
     72 #define DST_REP_C UINT64_C
     73 #elif defined DST_QUAD
     74 #define DST_REP_C (__uint128_t)
     75 #endif
     76 
     77 // ---- One-time emission per (TU, src+dst pair). --------------------------
     78 // Pairs kit uses: (i64,u64) × (sf,df) and (i128,u128) × (sf,df,tf).
     79 
     80 #if defined SRC_I64 && defined DST_SINGLE && !defined INT_TO_FP_I64SF_EMITTED
     81 #define INT_TO_FP_I64SF_EMITTED
     82 #define _INT_TO_FP_EMIT 1
     83 #elif defined SRC_I64 && defined DST_DOUBLE && !defined INT_TO_FP_I64DF_EMITTED
     84 #define INT_TO_FP_I64DF_EMITTED
     85 #define _INT_TO_FP_EMIT 1
     86 #elif defined SRC_U64 && defined DST_SINGLE && !defined INT_TO_FP_U64SF_EMITTED
     87 #define INT_TO_FP_U64SF_EMITTED
     88 #define _INT_TO_FP_EMIT 1
     89 #elif defined SRC_U64 && defined DST_DOUBLE && !defined INT_TO_FP_U64DF_EMITTED
     90 #define INT_TO_FP_U64DF_EMITTED
     91 #define _INT_TO_FP_EMIT 1
     92 #elif defined SRC_I128 && defined DST_SINGLE && !defined INT_TO_FP_I128SF_EMITTED
     93 #define INT_TO_FP_I128SF_EMITTED
     94 #define _INT_TO_FP_EMIT 1
     95 #elif defined SRC_I128 && defined DST_DOUBLE && !defined INT_TO_FP_I128DF_EMITTED
     96 #define INT_TO_FP_I128DF_EMITTED
     97 #define _INT_TO_FP_EMIT 1
     98 #elif defined SRC_I128 && defined DST_QUAD && !defined INT_TO_FP_I128TF_EMITTED
     99 #define INT_TO_FP_I128TF_EMITTED
    100 #define _INT_TO_FP_EMIT 1
    101 #elif defined SRC_U128 && defined DST_SINGLE && !defined INT_TO_FP_U128SF_EMITTED
    102 #define INT_TO_FP_U128SF_EMITTED
    103 #define _INT_TO_FP_EMIT 1
    104 #elif defined SRC_U128 && defined DST_DOUBLE && !defined INT_TO_FP_U128DF_EMITTED
    105 #define INT_TO_FP_U128DF_EMITTED
    106 #define _INT_TO_FP_EMIT 1
    107 #elif defined SRC_U128 && defined DST_QUAD && !defined INT_TO_FP_U128TF_EMITTED
    108 #define INT_TO_FP_U128TF_EMITTED
    109 #define _INT_TO_FP_EMIT 1
    110 #endif
    111 
    112 #ifdef _INT_TO_FP_EMIT
    113 #undef _INT_TO_FP_EMIT
    114 
    115 #if defined SRC_I64
    116 typedef int64_t src_t;
    117 typedef uint64_t usrc_t;
    118 static inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
    119 
    120 #elif defined SRC_U64
    121 typedef uint64_t src_t;
    122 typedef uint64_t usrc_t;
    123 static inline int clzSrcT(usrc_t x) { return __builtin_clzll(x); }
    124 
    125 #elif defined SRC_I128
    126 typedef __int128_t src_t;
    127 typedef __uint128_t usrc_t;
    128 static inline int clzSrcT(usrc_t x) { return __clzti2(x); }
    129 
    130 #elif defined SRC_U128
    131 typedef __uint128_t src_t;
    132 typedef __uint128_t usrc_t;
    133 static inline int clzSrcT(usrc_t x) { return __clzti2(x); }
    134 
    135 #endif
    136 
    137 #if defined DST_SINGLE
    138 typedef float dst_t;
    139 typedef uint32_t dst_rep_t;
    140 
    141 enum {
    142   dstSigBits = 23,
    143 };
    144 
    145 #elif defined DST_DOUBLE
    146 typedef double dst_t;
    147 typedef uint64_t dst_rep_t;
    148 
    149 enum {
    150   dstSigBits = 52,
    151 };
    152 
    153 #elif defined DST_QUAD
    154 typedef tf_float dst_t;
    155 typedef __uint128_t dst_rep_t;
    156 
    157 enum {
    158   dstSigBits = 112,
    159 };
    160 
    161 #endif
    162 
    163 static inline dst_t dstFromRep(dst_rep_t x) {
    164   const union {
    165     dst_t f;
    166     dst_rep_t i;
    167   } rep = {.i = x};
    168   return rep.f;
    169 }
    170 
    171 #endif // _INT_TO_FP_EMIT
    172 
    173 #define __floatXiYf__ _INT_TO_FP_PAIR(__floatXiYf__)
    174 
    175 #if defined SRC_I64 && defined DST_SINGLE && !defined INT_TO_FP_IMPL_I64SF_EMITTED
    176 #define INT_TO_FP_IMPL_I64SF_EMITTED
    177 #define _INT_TO_FP_IMPL_EMIT 1
    178 #elif defined SRC_I64 && defined DST_DOUBLE && !defined INT_TO_FP_IMPL_I64DF_EMITTED
    179 #define INT_TO_FP_IMPL_I64DF_EMITTED
    180 #define _INT_TO_FP_IMPL_EMIT 1
    181 #elif defined SRC_U64 && defined DST_SINGLE && !defined INT_TO_FP_IMPL_U64SF_EMITTED
    182 #define INT_TO_FP_IMPL_U64SF_EMITTED
    183 #define _INT_TO_FP_IMPL_EMIT 1
    184 #elif defined SRC_U64 && defined DST_DOUBLE && !defined INT_TO_FP_IMPL_U64DF_EMITTED
    185 #define INT_TO_FP_IMPL_U64DF_EMITTED
    186 #define _INT_TO_FP_IMPL_EMIT 1
    187 #elif defined SRC_I128 && defined DST_SINGLE && !defined INT_TO_FP_IMPL_I128SF_EMITTED
    188 #define INT_TO_FP_IMPL_I128SF_EMITTED
    189 #define _INT_TO_FP_IMPL_EMIT 1
    190 #elif defined SRC_I128 && defined DST_DOUBLE && !defined INT_TO_FP_IMPL_I128DF_EMITTED
    191 #define INT_TO_FP_IMPL_I128DF_EMITTED
    192 #define _INT_TO_FP_IMPL_EMIT 1
    193 #elif defined SRC_I128 && defined DST_QUAD && !defined INT_TO_FP_IMPL_I128TF_EMITTED
    194 #define INT_TO_FP_IMPL_I128TF_EMITTED
    195 #define _INT_TO_FP_IMPL_EMIT 1
    196 #elif defined SRC_U128 && defined DST_SINGLE && !defined INT_TO_FP_IMPL_U128SF_EMITTED
    197 #define INT_TO_FP_IMPL_U128SF_EMITTED
    198 #define _INT_TO_FP_IMPL_EMIT 1
    199 #elif defined SRC_U128 && defined DST_DOUBLE && !defined INT_TO_FP_IMPL_U128DF_EMITTED
    200 #define INT_TO_FP_IMPL_U128DF_EMITTED
    201 #define _INT_TO_FP_IMPL_EMIT 1
    202 #elif defined SRC_U128 && defined DST_QUAD && !defined INT_TO_FP_IMPL_U128TF_EMITTED
    203 #define INT_TO_FP_IMPL_U128TF_EMITTED
    204 #define _INT_TO_FP_IMPL_EMIT 1
    205 #endif
    206 
    207 #ifdef _INT_TO_FP_IMPL_EMIT
    208 #undef _INT_TO_FP_IMPL_EMIT
    209 
    210 static inline dst_t __floatXiYf__(src_t a) {
    211   if (a == 0)
    212     return 0.0;
    213 
    214   enum {
    215     dstMantDig = dstSigBits + 1,
    216     srcBits = sizeof(src_t) * CHAR_BIT,
    217     srcIsSigned = ((src_t)-1) < 0,
    218   };
    219 
    220   const src_t s = srcIsSigned ? a >> (srcBits - 1) : 0;
    221 
    222   a = (usrc_t)(a ^ s) - s;
    223   int sd = srcBits - clzSrcT(a);         // number of significant digits
    224   int e = sd - 1;                        // exponent
    225   if (sd > dstMantDig) {
    226     //  start:  0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
    227     //  finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
    228     //                                                12345678901234567890123456
    229     //  1 = msb 1 bit
    230     //  P = bit dstMantDig-1 bits to the right of 1
    231     //  Q = bit dstMantDig bits to the right of 1
    232     //  R = "or" of all bits to the right of Q
    233     if (sd == dstMantDig + 1) {
    234       a <<= 1;
    235     } else if (sd == dstMantDig + 2) {
    236       // Do nothing.
    237     } else {
    238       a = ((usrc_t)a >> (sd - (dstMantDig + 2))) |
    239           ((a & ((usrc_t)(-1) >> ((srcBits + dstMantDig + 2) - sd))) != 0);
    240     }
    241     // finish:
    242     a |= (a & 4) != 0; // Or P into R
    243     ++a;               // round - this step may add a significant bit
    244     a >>= 2;           // dump Q and R
    245     // a is now rounded to dstMantDig or dstMantDig+1 bits
    246     if (a & ((usrc_t)1 << dstMantDig)) {
    247       a >>= 1;
    248       ++e;
    249     }
    250     // a is now rounded to dstMantDig bits
    251   } else {
    252     a <<= (dstMantDig - sd);
    253     // a is now rounded to dstMantDig bits
    254   }
    255   const int dstBits = sizeof(dst_t) * CHAR_BIT;
    256   const dst_rep_t dstSignMask = DST_REP_C(1) << (dstBits - 1);
    257   const int dstExpBits = dstBits - dstSigBits - 1;
    258   const int dstExpBias = (1 << (dstExpBits - 1)) - 1;
    259   const dst_rep_t dstSignificandMask = (DST_REP_C(1) << dstSigBits) - 1;
    260   // Combine sign, exponent, and mantissa.
    261   const dst_rep_t result = ((dst_rep_t)s & dstSignMask) |
    262                            ((dst_rep_t)(e + dstExpBias) << dstSigBits) |
    263                            ((dst_rep_t)(a) & dstSignificandMask);
    264   return dstFromRep(result);
    265 }
    266 
    267 #endif // _INT_TO_FP_IMPL_EMIT