1 /* Definitions for simple data type for real numbers.
2    Copyright (C) 2002-2020 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.  */
sreal()44   sreal () : m_sig (-1), m_exp (-1) {}
45 
46   /* Construct a sreal.  */
47   sreal (int64_t sig, int exp = 0)
48   {
49     normalize (sig, exp);
50   }
51 
52   void dump (FILE *) const;
53   int64_t to_int () const;
54   double to_double () const;
55   void stream_out (struct output_block *);
56   static sreal stream_in (class lto_input_block *);
57   sreal operator+ (const sreal &other) const;
58   sreal operator- (const sreal &other) const;
59   sreal operator* (const sreal &other) const;
60   sreal operator/ (const sreal &other) const;
61 
62   bool operator< (const sreal &other) const
63   {
64     if (m_exp == other.m_exp)
65       return m_sig < other.m_sig;
66     else
67     {
68       bool negative = m_sig < 0;
69       bool other_negative = other.m_sig < 0;
70 
71       if (negative != other_negative)
72         return negative > other_negative;
73 
74       bool r = m_exp < other.m_exp;
75       return negative ? !r : r;
76     }
77   }
78 
79   bool operator== (const sreal &other) const
80   {
81     return m_exp == other.m_exp && m_sig == other.m_sig;
82   }
83 
84   sreal operator- () const
85   {
86     sreal tmp = *this;
87     tmp.m_sig *= -1;
88 
89     return tmp;
90   }
91 
shift(int s)92   sreal shift (int s) const
93   {
94     /* Zero needs no shifting.  */
95     if (!m_sig)
96       return *this;
97     gcc_checking_assert (s <= SREAL_MAX_EXP);
98     gcc_checking_assert (s >= -SREAL_MAX_EXP);
99 
100     /* Overflows/drop to 0 could be handled gracefully, but hopefully we do not
101        need to do so.  */
102     gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
103     gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP);
104 
105     sreal tmp = *this;
106     tmp.m_exp += s;
107 
108     return tmp;
109   }
110 
111   /* Global minimum sreal can hold.  */
min()112   inline static sreal min ()
113   {
114     sreal min;
115     /* This never needs normalization.  */
116     min.m_sig = -SREAL_MAX_SIG;
117     min.m_exp = SREAL_MAX_EXP;
118     return min;
119   }
120 
121   /* Global minimum sreal can hold.  */
max()122   inline static sreal max ()
123   {
124     sreal max;
125     /* This never needs normalization.  */
126     max.m_sig = SREAL_MAX_SIG;
127     max.m_exp = SREAL_MAX_EXP;
128     return max;
129   }
130 
131 private:
132   inline void normalize (int64_t new_sig, signed int new_exp);
133   inline void normalize_up (int64_t new_sig, signed int new_exp);
134   inline void normalize_down (int64_t new_sig, signed int new_exp);
135   void shift_right (int amount);
136   static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
137   static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
138 
139   int32_t m_sig;			/* Significant.  */
140   signed int m_exp;			/* Exponent.  */
141 };
142 
143 extern void debug (const sreal &ref);
144 extern void debug (const sreal *ptr);
145 
146 inline sreal &operator+= (sreal &a, const sreal &b)
147 {
148   return a = a + b;
149 }
150 
151 inline sreal &operator-= (sreal &a, const sreal &b)
152 {
153   return a = a - b;
154 }
155 
156 inline sreal &operator/= (sreal &a, const sreal &b)
157 {
158   return a = a / b;
159 }
160 
161 inline sreal &operator*= (sreal &a, const sreal &b)
162 {
163   return a = a  * b;
164 }
165 
166 inline bool operator!= (const sreal &a, const sreal &b)
167 {
168   return !(a == b);
169 }
170 
171 inline bool operator> (const sreal &a, const sreal &b)
172 {
173   return !(a == b || a < b);
174 }
175 
176 inline bool operator<= (const sreal &a, const sreal &b)
177 {
178   return a < b || a == b;
179 }
180 
181 inline bool operator>= (const sreal &a, const sreal &b)
182 {
183   return a == b || a > b;
184 }
185 
186 inline sreal operator<< (const sreal &a, int exp)
187 {
188   return a.shift (exp);
189 }
190 
191 inline sreal operator>> (const sreal &a, int exp)
192 {
193   return a.shift (-exp);
194 }
195 
196 /* Make significant to be >= SREAL_MIN_SIG.
197 
198    Make this separate method so inliner can handle hot path better.  */
199 
200 inline void
normalize_up(int64_t new_sig,signed int new_exp)201 sreal::normalize_up (int64_t new_sig, signed int new_exp)
202 {
203   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
204   int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
205 
206   gcc_checking_assert (shift > 0);
207   sig <<= shift;
208   new_exp -= shift;
209   gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
210 
211   /* Check underflow.  */
212   if (new_exp < -SREAL_MAX_EXP)
213     {
214       new_exp = -SREAL_MAX_EXP;
215       sig = 0;
216     }
217   m_exp = new_exp;
218   if (SREAL_SIGN (new_sig) == -1)
219     m_sig = -sig;
220   else
221     m_sig = sig;
222 }
223 
224 /* Make significant to be <= SREAL_MAX_SIG.
225 
226    Make this separate method so inliner can handle hot path better.  */
227 
228 inline void
normalize_down(int64_t new_sig,signed int new_exp)229 sreal::normalize_down (int64_t new_sig, signed int new_exp)
230 {
231   int last_bit;
232   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
233   int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
234 
235   gcc_checking_assert (shift > 0);
236   last_bit = (sig >> (shift-1)) & 1;
237   sig >>= shift;
238   new_exp += shift;
239   gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
240 
241   /* Round the number.  */
242   sig += last_bit;
243   if (sig > SREAL_MAX_SIG)
244     {
245       sig >>= 1;
246       new_exp++;
247     }
248 
249   /* Check overflow.  */
250   if (new_exp > SREAL_MAX_EXP)
251     {
252       new_exp = SREAL_MAX_EXP;
253       sig = SREAL_MAX_SIG;
254     }
255   m_exp = new_exp;
256   if (SREAL_SIGN (new_sig) == -1)
257     m_sig = -sig;
258   else
259     m_sig = sig;
260 }
261 
262 /* Normalize *this; the hot path.  */
263 
264 inline void
normalize(int64_t new_sig,signed int new_exp)265 sreal::normalize (int64_t new_sig, signed int new_exp)
266 {
267   unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
268 
269   if (sig == 0)
270     {
271       m_sig = 0;
272       m_exp = -SREAL_MAX_EXP;
273     }
274   else if (sig > SREAL_MAX_SIG)
275     normalize_down (new_sig, new_exp);
276   else if (sig < SREAL_MIN_SIG)
277     normalize_up (new_sig, new_exp);
278   else
279     {
280       m_sig = new_sig;
281       m_exp = new_exp;
282     }
283 }
284 
285 #endif
286