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 #ifdef COMPILER_RT_HAS_FLOAT16
66 typedef _Float16 src_t;
67 #else
68 typedef uint16_t src_t;
69 #endif
70 typedef uint16_t src_rep_t;
71 #define SRC_REP_C UINT16_C
72 static const int srcBits = sizeof(src_t) * CHAR_BIT;
73 static const int srcSigFracBits = 10;
74 // -1 accounts for the sign bit.
75 // srcBits - srcSigFracBits - 1
76 static const int srcExpBits = 5;
77 
78 static inline int src_rep_t_clz_impl(src_rep_t a) {
79   return __builtin_clz(a) - 16;
80 }
81 
82 #define src_rep_t_clz src_rep_t_clz_impl
83 
84 #else
85 #error Source should be half, single, or double precision!
86 #endif // end source precision
87 
88 #if defined DST_SINGLE
89 typedef float dst_t;
90 typedef uint32_t dst_rep_t;
91 #define DST_REP_C UINT32_C
92 static const int dstBits = sizeof(dst_t) * CHAR_BIT;
93 static const int dstSigFracBits = 23;
94 // -1 accounts for the sign bit.
95 // dstBits - dstSigFracBits - 1
96 static const int dstExpBits = 8;
97 
98 #elif defined DST_DOUBLE
99 typedef double dst_t;
100 typedef uint64_t dst_rep_t;
101 #define DST_REP_C UINT64_C
102 static const int dstBits = sizeof(dst_t) * CHAR_BIT;
103 static const int dstSigFracBits = 52;
104 // -1 accounts for the sign bit.
105 // dstBits - dstSigFracBits - 1
106 static const int dstExpBits = 11;
107 
108 #elif defined DST_QUAD
109 typedef tf_float dst_t;
110 typedef __uint128_t dst_rep_t;
111 #define DST_REP_C (__uint128_t)
112 static const int dstBits = sizeof(dst_t) * CHAR_BIT;
113 static const int dstSigFracBits = 112;
114 // -1 accounts for the sign bit.
115 // dstBits - dstSigFracBits - 1
116 static const int dstExpBits = 15;
117 
118 #else
119 #error Destination should be single, double, or quad precision!
120 #endif // end destination precision
121 
122 // End of specialization parameters.
123 
124 // TODO: These helper routines should be placed into fp_lib.h
125 // Currently they depend on macros/constants defined above.
126 
127 static inline src_rep_t extract_sign_from_src(src_rep_t x) {
128   const src_rep_t srcSignMask = SRC_REP_C(1) << (srcBits - 1);
129   return (x & srcSignMask) >> (srcBits - 1);
130 }
131 
132 static inline src_rep_t extract_exp_from_src(src_rep_t x) {
133   const int srcSigBits = srcBits - 1 - srcExpBits;
134   const src_rep_t srcExpMask = ((SRC_REP_C(1) << srcExpBits) - 1) << srcSigBits;
135   return (x & srcExpMask) >> srcSigBits;
136 }
137 
138 static inline src_rep_t extract_sig_frac_from_src(src_rep_t x) {
139   const src_rep_t srcSigFracMask = (SRC_REP_C(1) << srcSigFracBits) - 1;
140   return x & srcSigFracMask;
141 }
142 
143 #ifdef src_rep_t_clz
144 static inline int clz_in_sig_frac(src_rep_t sigFrac) {
145       const int skip = 1 + srcExpBits;
146       return src_rep_t_clz(sigFrac) - skip;
147 }
148 #endif
149 
150 static inline dst_rep_t construct_dst_rep(dst_rep_t sign, dst_rep_t exp, dst_rep_t sigFrac) {
151   return (sign << (dstBits - 1)) | (exp << (dstBits - 1 - dstExpBits)) | sigFrac;
152 }
153 
154 // Two helper routines for conversion to and from the representation of
155 // floating-point data as integer values follow.
156 
157 static inline src_rep_t srcToRep(src_t x) {
158   const union {
159     src_t f;
160     src_rep_t i;
161   } rep = {.f = x};
162   return rep.i;
163 }
164 
165 static inline dst_t dstFromRep(dst_rep_t x) {
166   const union {
167     dst_t f;
168     dst_rep_t i;
169   } rep = {.i = x};
170   return rep.f;
171 }
172 // End helper routines.  Conversion implementation follows.
173 
174 #endif // FP_EXTEND_HEADER
175