]> gcc.gnu.org Git - gcc.git/blob - gcc/value-range-storage.cc
Rewrite NAN and sign handling in frange
[gcc.git] / gcc / value-range-storage.cc
1 /* Support routines for vrange storage.
2 Copyright (C) 2022 Free Software Foundation, Inc.
3 Contributed by Aldy Hernandez <aldyh@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "tree.h"
26 #include "gimple.h"
27 #include "ssa.h"
28 #include "tree-pretty-print.h"
29 #include "fold-const.h"
30 #include "gimple-range.h"
31 #include "value-range-storage.h"
32
33 // Return a newly allocated slot holding R, or NULL if storing a range
34 // of R's type is not supported.
35
36 void *
37 vrange_storage::alloc_slot (const vrange &r)
38 {
39 gcc_checking_assert (m_alloc);
40
41 if (is_a <irange> (r))
42 return irange_storage_slot::alloc_slot (*m_alloc, as_a <irange> (r));
43 if (is_a <frange> (r))
44 return frange_storage_slot::alloc_slot (*m_alloc, as_a <frange> (r));
45 return NULL;
46 }
47
48 // Set SLOT to R.
49
50 void
51 vrange_storage::set_vrange (void *slot, const vrange &r)
52 {
53 if (is_a <irange> (r))
54 {
55 irange_storage_slot *s = static_cast <irange_storage_slot *> (slot);
56 gcc_checking_assert (s->fits_p (as_a <irange> (r)));
57 s->set_irange (as_a <irange> (r));
58 }
59 else if (is_a <frange> (r))
60 {
61 frange_storage_slot *s = static_cast <frange_storage_slot *> (slot);
62 gcc_checking_assert (s->fits_p (as_a <frange> (r)));
63 s->set_frange (as_a <frange> (r));
64 }
65 else
66 gcc_unreachable ();
67 }
68
69 // Restore R from SLOT. TYPE is the type of R.
70
71 void
72 vrange_storage::get_vrange (const void *slot, vrange &r, tree type)
73 {
74 if (is_a <irange> (r))
75 {
76 const irange_storage_slot *s
77 = static_cast <const irange_storage_slot *> (slot);
78 s->get_irange (as_a <irange> (r), type);
79 }
80 else if (is_a <frange> (r))
81 {
82 const frange_storage_slot *s
83 = static_cast <const frange_storage_slot *> (slot);
84 s->get_frange (as_a <frange> (r), type);
85 }
86 else
87 gcc_unreachable ();
88 }
89
90 // Return TRUE if SLOT can fit R.
91
92 bool
93 vrange_storage::fits_p (const void *slot, const vrange &r)
94 {
95 if (is_a <irange> (r))
96 {
97 const irange_storage_slot *s
98 = static_cast <const irange_storage_slot *> (slot);
99 return s->fits_p (as_a <irange> (r));
100 }
101 if (is_a <frange> (r))
102 {
103 const frange_storage_slot *s
104 = static_cast <const frange_storage_slot *> (slot);
105 return s->fits_p (as_a <frange> (r));
106 }
107 gcc_unreachable ();
108 return false;
109 }
110
111 // Factory that creates a new irange_storage_slot object containing R.
112 // This is the only way to construct an irange slot as stack creation
113 // is disallowed.
114
115 irange_storage_slot *
116 irange_storage_slot::alloc_slot (vrange_allocator &allocator, const irange &r)
117 {
118 size_t size = irange_storage_slot::size (r);
119 irange_storage_slot *p
120 = static_cast <irange_storage_slot *> (allocator.alloc (size));
121 new (p) irange_storage_slot (r);
122 return p;
123 }
124
125 // Initialize the current slot with R.
126
127 irange_storage_slot::irange_storage_slot (const irange &r)
128 {
129 gcc_checking_assert (!r.undefined_p ());
130
131 unsigned prec = TYPE_PRECISION (r.type ());
132 unsigned n = num_wide_ints_needed (r);
133 if (n > MAX_INTS)
134 {
135 int_range<MAX_PAIRS> squash (r);
136 m_ints.set_precision (prec, num_wide_ints_needed (squash));
137 set_irange (squash);
138 }
139 else
140 {
141 m_ints.set_precision (prec, n);
142 set_irange (r);
143 }
144 }
145
146 // Store R into the current slot.
147
148 void
149 irange_storage_slot::set_irange (const irange &r)
150 {
151 gcc_checking_assert (fits_p (r));
152
153 // Avoid calling unsupported get_nonzero_bits on legacy.
154 if (r.legacy_mode_p ())
155 m_ints[0] = -1;
156 else
157 m_ints[0] = r.get_nonzero_bits ();
158
159 unsigned pairs = r.num_pairs ();
160 for (unsigned i = 0; i < pairs; ++i)
161 {
162 m_ints[i*2 + 1] = r.lower_bound (i);
163 m_ints[i*2 + 2] = r.upper_bound (i);
164 }
165 }
166
167 // Restore a range of TYPE from the current slot into R.
168
169 void
170 irange_storage_slot::get_irange (irange &r, tree type) const
171 {
172 gcc_checking_assert (TYPE_PRECISION (type) == m_ints.get_precision ());
173
174 r.set_undefined ();
175 unsigned nelements = m_ints.num_elements ();
176 for (unsigned i = 1; i < nelements; i += 2)
177 {
178 int_range<2> tmp (type, m_ints[i], m_ints[i + 1]);
179 r.union_ (tmp);
180 }
181 r.set_nonzero_bits (get_nonzero_bits ());
182 }
183
184 // Return the size in bytes to allocate a slot that can hold R.
185
186 size_t
187 irange_storage_slot::size (const irange &r)
188 {
189 gcc_checking_assert (!r.undefined_p ());
190
191 unsigned prec = TYPE_PRECISION (r.type ());
192 unsigned n = num_wide_ints_needed (r);
193 if (n > MAX_INTS)
194 n = MAX_INTS;
195 return (sizeof (irange_storage_slot)
196 + trailing_wide_ints<MAX_INTS>::extra_size (prec, n));
197 }
198
199 // Return the number of wide ints needed to represent R.
200
201 unsigned int
202 irange_storage_slot::num_wide_ints_needed (const irange &r)
203 {
204 return r.num_pairs () * 2 + 1;
205 }
206
207 // Return TRUE if R fits in the current slot.
208
209 bool
210 irange_storage_slot::fits_p (const irange &r) const
211 {
212 return m_ints.num_elements () >= num_wide_ints_needed (r);
213 }
214
215 // Dump the current slot.
216
217 void
218 irange_storage_slot::dump () const
219 {
220 fprintf (stderr, "raw irange_storage_slot:\n");
221 for (unsigned i = 1; i < m_ints.num_elements (); i += 2)
222 {
223 m_ints[i].dump ();
224 m_ints[i + 1].dump ();
225 }
226 fprintf (stderr, "NONZERO ");
227 wide_int nz = get_nonzero_bits ();
228 nz.dump ();
229 }
230
231 DEBUG_FUNCTION void
232 debug (const irange_storage_slot &storage)
233 {
234 storage.dump ();
235 fprintf (stderr, "\n");
236 }
237
238 // Implementation of frange_storage_slot.
239
240 frange_storage_slot *
241 frange_storage_slot::alloc_slot (vrange_allocator &allocator, const frange &r)
242 {
243 size_t size = sizeof (frange_storage_slot);
244 frange_storage_slot *p
245 = static_cast <frange_storage_slot *> (allocator.alloc (size));
246 new (p) frange_storage_slot (r);
247 return p;
248 }
249
250 void
251 frange_storage_slot::set_frange (const frange &r)
252 {
253 gcc_checking_assert (fits_p (r));
254 gcc_checking_assert (!r.undefined_p ());
255
256 m_kind = r.m_kind;
257 m_min = r.m_min;
258 m_max = r.m_max;
259 m_pos_nan = r.m_pos_nan;
260 m_neg_nan = r.m_neg_nan;
261 }
262
263 void
264 frange_storage_slot::get_frange (frange &r, tree type) const
265 {
266 gcc_checking_assert (r.supports_type_p (type));
267
268 r.set_undefined ();
269 r.m_kind = m_kind;
270 r.m_type = type;
271 r.m_min = m_min;
272 r.m_max = m_max;
273 r.m_pos_nan = m_pos_nan;
274 r.m_neg_nan = m_neg_nan;
275 r.normalize_kind ();
276
277 if (flag_checking)
278 r.verify_range ();
279 }
280
281 bool
282 frange_storage_slot::fits_p (const frange &) const
283 {
284 return true;
285 }
This page took 0.045745 seconds and 5 git commands to generate.