Line data Source code
1 : /* Definitions for simple data type for real numbers.
2 : Copyright (C) 2002-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify it under
7 : the terms of the GNU General Public License as published by the Free
8 : Software Foundation; either version 3, or (at your option) any later
9 : version.
10 :
11 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 : for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : #ifndef GCC_SREAL_H
21 : #define GCC_SREAL_H
22 :
23 : #define SREAL_PART_BITS 31
24 :
25 : #define UINT64_BITS 64
26 :
27 : #define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
28 : #define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
29 : #define SREAL_MAX_EXP (INT_MAX / 4)
30 :
31 : #define SREAL_BITS SREAL_PART_BITS
32 :
33 : #define SREAL_SIGN(v) (v < 0 ? -1 : 1)
34 : #define SREAL_ABS(v) (v < 0 ? -v : v)
35 :
36 : struct output_block;
37 : class lto_input_block;
38 :
39 : /* Structure for holding a simple real number. */
40 : class sreal
41 : {
42 : public:
43 : /* Construct an uninitialized sreal. */
44 1768882891 : sreal () : m_sig (-1), m_exp (-1) {}
45 :
46 : /* Construct a sreal. */
47 3323654635 : sreal (int64_t sig, int exp = 0)
48 3323654635 : {
49 2853912056 : normalize (sig, exp);
50 1420142 : }
51 :
52 : void dump (FILE *) const;
53 : int64_t to_int () const;
54 : int64_t to_nearest_int () const;
55 : double to_double () const;
56 : void stream_out (struct output_block *);
57 : static sreal stream_in (class lto_input_block *);
58 : sreal operator+ (const sreal &other) const;
59 : sreal operator- (const sreal &other) const;
60 : sreal operator* (const sreal &other) const;
61 : sreal operator/ (const sreal &other) const;
62 :
63 627817408 : bool operator< (const sreal &other) const
64 : {
65 627817408 : if (m_exp == other.m_exp)
66 37928400 : return m_sig < other.m_sig;
67 : else
68 : {
69 589889008 : bool negative = m_sig < 0;
70 589889008 : bool other_negative = other.m_sig < 0;
71 :
72 589889008 : if (negative != other_negative)
73 40392801 : return negative > other_negative;
74 :
75 549496207 : bool r = m_exp < other.m_exp;
76 549496207 : return negative ? !r : r;
77 : }
78 : }
79 :
80 1141980588 : bool operator== (const sreal &other) const
81 : {
82 267548830 : return m_exp == other.m_exp && m_sig == other.m_sig;
83 : }
84 :
85 11234341 : sreal operator- () const
86 : {
87 11234341 : sreal tmp = *this;
88 11234341 : tmp.m_sig *= -1;
89 :
90 11234341 : return tmp;
91 : }
92 :
93 64395554 : sreal shift (int s) const
94 : {
95 : /* Zero needs no shifting. */
96 64395554 : if (!m_sig)
97 6847530 : return *this;
98 57548024 : gcc_checking_assert (s <= SREAL_MAX_EXP);
99 57548024 : gcc_checking_assert (s >= -SREAL_MAX_EXP);
100 :
101 : /* Overflows/drop to 0 could be handled gracefully, but hopefully we do not
102 : need to do so. */
103 57548024 : gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
104 57548024 : gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP);
105 :
106 57548024 : sreal tmp = *this;
107 57548024 : tmp.m_exp += s;
108 :
109 57548024 : return tmp;
110 : }
111 :
112 : /* Global minimum sreal can hold. */
113 1291992 : inline static sreal min ()
114 : {
115 1291992 : sreal min;
116 : /* This never needs normalization. */
117 1291992 : min.m_sig = -SREAL_MAX_SIG;
118 1291992 : min.m_exp = SREAL_MAX_EXP;
119 1291992 : return min;
120 : }
121 :
122 : /* Global minimum sreal can hold. */
123 2937409 : inline static sreal max ()
124 : {
125 2937409 : sreal max;
126 : /* This never needs normalization. */
127 2937409 : max.m_sig = SREAL_MAX_SIG;
128 2937409 : max.m_exp = SREAL_MAX_EXP;
129 519108 : return max;
130 : }
131 :
132 : private:
133 : inline void normalize (int64_t new_sig, signed int new_exp);
134 : inline void normalize_up (int64_t new_sig, signed int new_exp);
135 : inline void normalize_down (int64_t new_sig, signed int new_exp);
136 : void shift_right (int amount);
137 : static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
138 : static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
139 :
140 : int32_t m_sig; /* Significant. */
141 : signed int m_exp; /* Exponent. */
142 : };
143 :
144 : extern void debug (const sreal &ref);
145 : extern void debug (const sreal *ptr);
146 :
147 691551425 : inline sreal &operator+= (sreal &a, const sreal &b)
148 : {
149 690131014 : return a = a + b;
150 : }
151 :
152 595723 : inline sreal &operator-= (sreal &a, const sreal &b)
153 : {
154 595723 : return a = a - b;
155 : }
156 :
157 529889 : inline sreal &operator/= (sreal &a, const sreal &b)
158 : {
159 529889 : return a = a / b;
160 : }
161 :
162 20465204 : inline sreal &operator*= (sreal &a, const sreal &b)
163 : {
164 20465204 : return a = a * b;
165 : }
166 :
167 72427255 : inline bool operator!= (const sreal &a, const sreal &b)
168 : {
169 127490287 : return !(a == b);
170 : }
171 :
172 465006110 : inline bool operator> (const sreal &a, const sreal &b)
173 : {
174 479322139 : return !(a == b || a < b);
175 : }
176 :
177 13655425 : inline bool operator<= (const sreal &a, const sreal &b)
178 : {
179 13655425 : return a < b || a == b;
180 : }
181 :
182 510134567 : inline bool operator>= (const sreal &a, const sreal &b)
183 : {
184 512022218 : return a == b || a > b;
185 : }
186 :
187 3107278 : inline sreal operator<< (const sreal &a, int exp)
188 : {
189 3107278 : return a.shift (exp);
190 : }
191 :
192 50345865 : inline sreal operator>> (const sreal &a, int exp)
193 : {
194 50345865 : return a.shift (-exp);
195 : }
196 :
197 : /* Make significant to be >= SREAL_MIN_SIG.
198 :
199 : Make this separate method so inliner can handle hot path better. */
200 :
201 : inline void
202 1220454692 : sreal::normalize_up (int64_t new_sig, signed int new_exp)
203 : {
204 1220454692 : unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
205 1220454692 : int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
206 :
207 1220454692 : gcc_checking_assert (shift > 0);
208 1220454692 : sig <<= shift;
209 1220454692 : new_exp -= shift;
210 1220454692 : gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
211 :
212 : /* Check underflow. */
213 1220454692 : if (new_exp < -SREAL_MAX_EXP)
214 : {
215 0 : new_exp = -SREAL_MAX_EXP;
216 0 : sig = 0;
217 : }
218 1220454692 : m_exp = new_exp;
219 1220454692 : if (SREAL_SIGN (new_sig) == -1)
220 46371006 : m_sig = -sig;
221 : else
222 1174083686 : m_sig = sig;
223 1220454692 : }
224 :
225 : /* Make significant to be <= SREAL_MAX_SIG.
226 :
227 : Make this separate method so inliner can handle hot path better. */
228 :
229 : inline void
230 1017793493 : sreal::normalize_down (int64_t new_sig, signed int new_exp)
231 : {
232 1017793493 : int last_bit;
233 1017793493 : unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
234 1017793493 : int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
235 :
236 1017793493 : gcc_checking_assert (shift > 0);
237 1017793493 : last_bit = (sig >> (shift-1)) & 1;
238 1017793493 : sig >>= shift;
239 1017793493 : new_exp += shift;
240 1017793493 : gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
241 :
242 : /* Round the number. */
243 1017793493 : sig += last_bit;
244 1017793493 : if (sig > SREAL_MAX_SIG)
245 : {
246 3772905 : sig >>= 1;
247 3772905 : new_exp++;
248 : }
249 :
250 : /* Check overflow. */
251 1017793493 : if (new_exp > SREAL_MAX_EXP)
252 : {
253 0 : new_exp = SREAL_MAX_EXP;
254 0 : sig = SREAL_MAX_SIG;
255 : }
256 1017793493 : m_exp = new_exp;
257 1017793493 : if (SREAL_SIGN (new_sig) == -1)
258 17700011 : m_sig = -sig;
259 : else
260 1000093482 : m_sig = sig;
261 1017793493 : }
262 :
263 : /* Normalize *this; the hot path. */
264 :
265 : inline void
266 3843520210 : sreal::normalize (int64_t new_sig, signed int new_exp)
267 : {
268 3843520210 : unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
269 :
270 3843520210 : if (sig == 0)
271 : {
272 1171368665 : m_sig = 0;
273 1171368665 : m_exp = -SREAL_MAX_EXP;
274 : }
275 2672151545 : else if (sig > SREAL_MAX_SIG)
276 1017793493 : normalize_down (new_sig, new_exp);
277 1654358052 : else if (sig < SREAL_MIN_SIG)
278 1220454692 : normalize_up (new_sig, new_exp);
279 : else
280 : {
281 433903360 : m_sig = new_sig;
282 433903360 : m_exp = new_exp;
283 : }
284 3843520210 : }
285 :
286 : #endif
|