]>
Commit | Line | Data |
---|---|---|
a26f3eb2 | 1 | /* Support routines for vrange storage. |
aeee4812 | 2 | Copyright (C) 2022-2023 Free Software Foundation, Inc. |
a26f3eb2 AH |
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 | ||
0a7e721a AH |
33 | // Return a newly allocated slot holding R, or NULL if storing a range |
34 | // of R's type is not supported. | |
a26f3eb2 AH |
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)); | |
5f7e187e AH |
43 | if (is_a <frange> (r)) |
44 | return frange_storage_slot::alloc_slot (*m_alloc, as_a <frange> (r)); | |
a26f3eb2 AH |
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 | } | |
5f7e187e AH |
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 | } | |
a26f3eb2 AH |
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 | } | |
5f7e187e AH |
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 | } | |
a26f3eb2 AH |
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 | } | |
5f7e187e AH |
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 | } | |
a26f3eb2 AH |
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 | ||
7df3693f | 153 | m_ints[0] = r.get_nonzero_bits (); |
4e82205b | 154 | |
a26f3eb2 AH |
155 | unsigned pairs = r.num_pairs (); |
156 | for (unsigned i = 0; i < pairs; ++i) | |
157 | { | |
158 | m_ints[i*2 + 1] = r.lower_bound (i); | |
159 | m_ints[i*2 + 2] = r.upper_bound (i); | |
160 | } | |
161 | } | |
162 | ||
163 | // Restore a range of TYPE from the current slot into R. | |
164 | ||
165 | void | |
166 | irange_storage_slot::get_irange (irange &r, tree type) const | |
167 | { | |
168 | gcc_checking_assert (TYPE_PRECISION (type) == m_ints.get_precision ()); | |
169 | ||
170 | r.set_undefined (); | |
171 | unsigned nelements = m_ints.num_elements (); | |
172 | for (unsigned i = 1; i < nelements; i += 2) | |
173 | { | |
174 | int_range<2> tmp (type, m_ints[i], m_ints[i + 1]); | |
175 | r.union_ (tmp); | |
176 | } | |
4e82205b | 177 | r.set_nonzero_bits (get_nonzero_bits ()); |
a26f3eb2 AH |
178 | } |
179 | ||
180 | // Return the size in bytes to allocate a slot that can hold R. | |
181 | ||
182 | size_t | |
183 | irange_storage_slot::size (const irange &r) | |
184 | { | |
185 | gcc_checking_assert (!r.undefined_p ()); | |
186 | ||
187 | unsigned prec = TYPE_PRECISION (r.type ()); | |
188 | unsigned n = num_wide_ints_needed (r); | |
189 | if (n > MAX_INTS) | |
190 | n = MAX_INTS; | |
191 | return (sizeof (irange_storage_slot) | |
192 | + trailing_wide_ints<MAX_INTS>::extra_size (prec, n)); | |
193 | } | |
194 | ||
195 | // Return the number of wide ints needed to represent R. | |
196 | ||
197 | unsigned int | |
198 | irange_storage_slot::num_wide_ints_needed (const irange &r) | |
199 | { | |
200 | return r.num_pairs () * 2 + 1; | |
201 | } | |
202 | ||
203 | // Return TRUE if R fits in the current slot. | |
204 | ||
205 | bool | |
206 | irange_storage_slot::fits_p (const irange &r) const | |
207 | { | |
208 | return m_ints.num_elements () >= num_wide_ints_needed (r); | |
209 | } | |
210 | ||
211 | // Dump the current slot. | |
212 | ||
213 | void | |
214 | irange_storage_slot::dump () const | |
215 | { | |
216 | fprintf (stderr, "raw irange_storage_slot:\n"); | |
217 | for (unsigned i = 1; i < m_ints.num_elements (); i += 2) | |
218 | { | |
219 | m_ints[i].dump (); | |
220 | m_ints[i + 1].dump (); | |
221 | } | |
222 | fprintf (stderr, "NONZERO "); | |
223 | wide_int nz = get_nonzero_bits (); | |
224 | nz.dump (); | |
225 | } | |
226 | ||
227 | DEBUG_FUNCTION void | |
228 | debug (const irange_storage_slot &storage) | |
229 | { | |
230 | storage.dump (); | |
231 | fprintf (stderr, "\n"); | |
232 | } | |
5f7e187e AH |
233 | |
234 | // Implementation of frange_storage_slot. | |
235 | ||
236 | frange_storage_slot * | |
237 | frange_storage_slot::alloc_slot (vrange_allocator &allocator, const frange &r) | |
238 | { | |
239 | size_t size = sizeof (frange_storage_slot); | |
240 | frange_storage_slot *p | |
241 | = static_cast <frange_storage_slot *> (allocator.alloc (size)); | |
242 | new (p) frange_storage_slot (r); | |
243 | return p; | |
244 | } | |
245 | ||
246 | void | |
247 | frange_storage_slot::set_frange (const frange &r) | |
248 | { | |
249 | gcc_checking_assert (fits_p (r)); | |
250 | gcc_checking_assert (!r.undefined_p ()); | |
251 | ||
91746147 | 252 | m_kind = r.m_kind; |
25dd2768 AH |
253 | m_min = r.m_min; |
254 | m_max = r.m_max; | |
91746147 AH |
255 | m_pos_nan = r.m_pos_nan; |
256 | m_neg_nan = r.m_neg_nan; | |
5f7e187e AH |
257 | } |
258 | ||
259 | void | |
260 | frange_storage_slot::get_frange (frange &r, tree type) const | |
261 | { | |
262 | gcc_checking_assert (r.supports_type_p (type)); | |
263 | ||
2b1fb720 AH |
264 | // Handle explicit NANs. |
265 | if (m_kind == VR_NAN) | |
266 | { | |
267 | if (HONOR_NANS (type)) | |
268 | { | |
269 | if (m_pos_nan && m_neg_nan) | |
270 | r.set_nan (type); | |
271 | else | |
272 | r.set_nan (type, m_neg_nan); | |
273 | } | |
274 | else | |
275 | r.set_undefined (); | |
276 | return; | |
277 | } | |
278 | ||
4eadbe80 AH |
279 | // We use the constructor to create the new range instead of writing |
280 | // out the bits into the frange directly, because the global range | |
281 | // being read may be being inlined into a function with different | |
282 | // restrictions as when it was originally written. We want to make | |
283 | // sure the resulting range is canonicalized correctly for the new | |
284 | // consumer. | |
2b1fb720 AH |
285 | r = frange (type, m_min, m_max, m_kind); |
286 | ||
287 | // The constructor will set the NAN bits for HONOR_NANS, but we must | |
288 | // make sure to set the NAN sign if known. | |
289 | if (HONOR_NANS (type) && (m_pos_nan ^ m_neg_nan) == 1) | |
290 | r.update_nan (m_neg_nan); | |
4eadbe80 AH |
291 | else if (!m_pos_nan && !m_neg_nan) |
292 | r.clear_nan (); | |
5f7e187e AH |
293 | } |
294 | ||
295 | bool | |
296 | frange_storage_slot::fits_p (const frange &) const | |
297 | { | |
298 | return true; | |
299 | } |