1 /* Support routines for vrange storage.
2 Copyright (C) 2022 Free Software Foundation, Inc.
3 Contributed by Aldy Hernandez <aldyh@redhat.com>.
5 This file is part of GCC.
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)
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.
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/>. */
23 #include "coretypes.h"
28 #include "tree-pretty-print.h"
29 #include "fold-const.h"
30 #include "gimple-range.h"
31 #include "value-range-storage.h"
33 // Return a newly allocated slot holding R, or NULL if storing a range
34 // of R's type is not supported.
37 vrange_storage::alloc_slot (const vrange
&r
)
39 gcc_checking_assert (m_alloc
);
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
));
51 vrange_storage::set_vrange (void *slot
, const vrange
&r
)
53 if (is_a
<irange
> (r
))
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
));
59 else if (is_a
<frange
> (r
))
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
));
69 // Restore R from SLOT. TYPE is the type of R.
72 vrange_storage::get_vrange (const void *slot
, vrange
&r
, tree type
)
74 if (is_a
<irange
> (r
))
76 const irange_storage_slot
*s
77 = static_cast <const irange_storage_slot
*> (slot
);
78 s
->get_irange (as_a
<irange
> (r
), type
);
80 else if (is_a
<frange
> (r
))
82 const frange_storage_slot
*s
83 = static_cast <const frange_storage_slot
*> (slot
);
84 s
->get_frange (as_a
<frange
> (r
), type
);
90 // Return TRUE if SLOT can fit R.
93 vrange_storage::fits_p (const void *slot
, const vrange
&r
)
95 if (is_a
<irange
> (r
))
97 const irange_storage_slot
*s
98 = static_cast <const irange_storage_slot
*> (slot
);
99 return s
->fits_p (as_a
<irange
> (r
));
101 if (is_a
<frange
> (r
))
103 const frange_storage_slot
*s
104 = static_cast <const frange_storage_slot
*> (slot
);
105 return s
->fits_p (as_a
<frange
> (r
));
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
115 irange_storage_slot
*
116 irange_storage_slot::alloc_slot (vrange_allocator
&allocator
, const irange
&r
)
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
);
125 // Initialize the current slot with R.
127 irange_storage_slot::irange_storage_slot (const irange
&r
)
129 gcc_checking_assert (!r
.undefined_p ());
131 unsigned prec
= TYPE_PRECISION (r
.type ());
132 unsigned n
= num_wide_ints_needed (r
);
135 int_range
<MAX_PAIRS
> squash (r
);
136 m_ints
.set_precision (prec
, num_wide_ints_needed (squash
));
141 m_ints
.set_precision (prec
, n
);
146 // Store R into the current slot.
149 irange_storage_slot::set_irange (const irange
&r
)
151 gcc_checking_assert (fits_p (r
));
153 m_ints
[0] = r
.get_nonzero_bits ();
155 unsigned pairs
= r
.num_pairs ();
156 for (unsigned i
= 0; i
< pairs
; ++i
)
158 m_ints
[i
*2 + 1] = r
.lower_bound (i
);
159 m_ints
[i
*2 + 2] = r
.upper_bound (i
);
163 // Restore a range of TYPE from the current slot into R.
166 irange_storage_slot::get_irange (irange
&r
, tree type
) const
168 gcc_checking_assert (TYPE_PRECISION (type
) == m_ints
.get_precision ());
171 unsigned nelements
= m_ints
.num_elements ();
172 for (unsigned i
= 1; i
< nelements
; i
+= 2)
174 int_range
<2> tmp (type
, m_ints
[i
], m_ints
[i
+ 1]);
177 r
.set_nonzero_bits (get_nonzero_bits ());
180 // Return the size in bytes to allocate a slot that can hold R.
183 irange_storage_slot::size (const irange
&r
)
185 gcc_checking_assert (!r
.undefined_p ());
187 unsigned prec
= TYPE_PRECISION (r
.type ());
188 unsigned n
= num_wide_ints_needed (r
);
191 return (sizeof (irange_storage_slot
)
192 + trailing_wide_ints
<MAX_INTS
>::extra_size (prec
, n
));
195 // Return the number of wide ints needed to represent R.
198 irange_storage_slot::num_wide_ints_needed (const irange
&r
)
200 return r
.num_pairs () * 2 + 1;
203 // Return TRUE if R fits in the current slot.
206 irange_storage_slot::fits_p (const irange
&r
) const
208 return m_ints
.num_elements () >= num_wide_ints_needed (r
);
211 // Dump the current slot.
214 irange_storage_slot::dump () const
216 fprintf (stderr
, "raw irange_storage_slot:\n");
217 for (unsigned i
= 1; i
< m_ints
.num_elements (); i
+= 2)
220 m_ints
[i
+ 1].dump ();
222 fprintf (stderr
, "NONZERO ");
223 wide_int nz
= get_nonzero_bits ();
228 debug (const irange_storage_slot
&storage
)
231 fprintf (stderr
, "\n");
234 // Implementation of frange_storage_slot.
236 frange_storage_slot
*
237 frange_storage_slot::alloc_slot (vrange_allocator
&allocator
, const frange
&r
)
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
);
247 frange_storage_slot::set_frange (const frange
&r
)
249 gcc_checking_assert (fits_p (r
));
250 gcc_checking_assert (!r
.undefined_p ());
255 m_pos_nan
= r
.m_pos_nan
;
256 m_neg_nan
= r
.m_neg_nan
;
260 frange_storage_slot::get_frange (frange
&r
, tree type
) const
262 gcc_checking_assert (r
.supports_type_p (type
));
264 // Handle explicit NANs.
265 if (m_kind
== VR_NAN
)
267 if (HONOR_NANS (type
))
269 if (m_pos_nan
&& m_neg_nan
)
272 r
.set_nan (type
, m_neg_nan
);
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
285 r
= frange (type
, m_min
, m_max
, m_kind
);
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
);
291 else if (!m_pos_nan
&& !m_neg_nan
)
296 frange_storage_slot::fits_p (const frange
&) const