1 /* Definitions for simple data type for real numbers.
2    Copyright (C) 2002-2018 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 /* SREAL_PART_BITS has to be an even number.  */
24 #define SREAL_PART_BITS 32
25 
26 #define UINT64_BITS	64
27 
28 #define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
29 #define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
30 #define SREAL_MAX_EXP (INT_MAX / 4)
31 
32 #define SREAL_BITS SREAL_PART_BITS
33 
34 #define SREAL_SIGN(v) (v < 0 ? -1: 1)
35 #define SREAL_ABS(v) (v < 0 ? -v: v)
36 
37 struct output_block;
38 struct lto_input_block;
39 
40 /* Structure for holding a simple real number.  */
41 class sreal
42 {
43 public:
44   /* Construct an uninitialized sreal.  */
sreal()45   sreal () : m_sig (-1), m_exp (-1) {}
46 
47   /* Construct a sreal.  */
m_sig(sig)48   sreal (int64_t sig, int exp = 0) : m_sig (sig), m_exp (exp)
49   {
50     normalize ();
51   }
52 
53   void dump (FILE *) const;
54   int64_t to_int () const;
55   double to_double () const;
56   void stream_out (struct output_block *);
57   static sreal stream_in (struct 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   bool operator< (const sreal &other) const
64   {
65     if (m_exp == other.m_exp)
66       return m_sig < other.m_sig;
67     else
68     {
69       bool negative = m_sig < 0;
70       bool other_negative = other.m_sig < 0;
71 
72       if (negative != other_negative)
73         return negative > other_negative;
74 
75       bool r = m_exp < other.m_exp;
76       return negative ? !r : r;
77     }
78   }
79 
80   bool operator== (const sreal &other) const
81   {
82     return m_exp == other.m_exp && m_sig == other.m_sig;
83   }
84 
85   sreal operator- () const
86   {
87     sreal tmp = *this;
88     tmp.m_sig *= -1;
89 
90     return tmp;
91   }
92 
shift(int s)93   sreal shift (int s) const
94   {
95     /* Zero needs no shifting.  */
96     if (!m_sig)
97       return *this;
98     gcc_checking_assert (s <= SREAL_MAX_EXP);
99     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     gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
104     gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP);
105 
106     sreal tmp = *this;
107     tmp.m_exp += s;
108 
109     return tmp;
110   }
111 
112   /* Global minimum sreal can hold.  */
min()113   inline static sreal min ()
114   {
115     sreal min;
116     /* This never needs normalization.  */
117     min.m_sig = -SREAL_MAX_SIG;
118     min.m_exp = SREAL_MAX_EXP;
119     return min;
120   }
121 
122   /* Global minimum sreal can hold.  */
max()123   inline static sreal max ()
124   {
125     sreal max;
126     /* This never needs normalization.  */
127     max.m_sig = SREAL_MAX_SIG;
128     max.m_exp = SREAL_MAX_EXP;
129     return max;
130   }
131 
132 private:
133   inline void normalize ();
134   inline void normalize_up ();
135   inline void normalize_down ();
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   int64_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 inline sreal &operator+= (sreal &a, const sreal &b)
148 {
149   return a = a + b;
150 }
151 
152 inline sreal &operator-= (sreal &a, const sreal &b)
153 {
154   return a = a - b;
155 }
156 
157 inline sreal &operator/= (sreal &a, const sreal &b)
158 {
159   return a = a / b;
160 }
161 
162 inline sreal &operator*= (sreal &a, const sreal &b)
163 {
164   return a = a  * b;
165 }
166 
167 inline bool operator!= (const sreal &a, const sreal &b)
168 {
169   return !(a == b);
170 }
171 
172 inline bool operator> (const sreal &a, const sreal &b)
173 {
174   return !(a == b || a < b);
175 }
176 
177 inline bool operator<= (const sreal &a, const sreal &b)
178 {
179   return a < b || a == b;
180 }
181 
182 inline bool operator>= (const sreal &a, const sreal &b)
183 {
184   return a == b || a > b;
185 }
186 
187 inline sreal operator<< (const sreal &a, int exp)
188 {
189   return a.shift (exp);
190 }
191 
192 inline sreal operator>> (const sreal &a, int exp)
193 {
194   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
normalize_up()202 sreal::normalize_up ()
203 {
204   unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
205   int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
206 
207   gcc_checking_assert (shift > 0);
208   sig <<= shift;
209   m_exp -= shift;
210   gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
211 
212   /* Check underflow.  */
213   if (m_exp < -SREAL_MAX_EXP)
214     {
215       m_exp = -SREAL_MAX_EXP;
216       sig = 0;
217     }
218   if (SREAL_SIGN (m_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()229 sreal::normalize_down ()
230 {
231   int last_bit;
232   unsigned HOST_WIDE_INT sig = absu_hwi (m_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   m_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       m_exp++;
247     }
248 
249   /* Check overflow.  */
250   if (m_exp > SREAL_MAX_EXP)
251     {
252       m_exp = SREAL_MAX_EXP;
253       sig = SREAL_MAX_SIG;
254     }
255   if (SREAL_SIGN (m_sig) == -1)
256     m_sig = -sig;
257   else
258     m_sig = sig;
259 }
260 
261 /* Normalize *this; the hot path.  */
262 
263 inline void
normalize()264 sreal::normalize ()
265 {
266   unsigned HOST_WIDE_INT sig = absu_hwi (m_sig);
267 
268   if (sig == 0)
269     m_exp = -SREAL_MAX_EXP;
270   else if (sig > SREAL_MAX_SIG)
271     normalize_down ();
272   else if (sig < SREAL_MIN_SIG)
273     normalize_up ();
274 }
275 
276 #endif
277