Line data Source code
1 : /* Pretty print support for value ranges.
2 : Copyright (C) 2019-2026 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-pretty-print.h"
32 :
33 : static void
34 84214 : print_int_bound (pretty_printer *pp, const wide_int &bound, tree type)
35 : {
36 84214 : wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
37 84214 : wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
38 :
39 84214 : if (INTEGRAL_TYPE_P (type)
40 81564 : && !TYPE_UNSIGNED (type)
41 24258 : && bound == type_min
42 84609 : && TYPE_PRECISION (type) != 1)
43 395 : pp_string (pp, "-INF");
44 83819 : else if (bound == type_max && TYPE_PRECISION (type) != 1)
45 12493 : pp_string (pp, "+INF");
46 : else
47 71326 : pp_wide_int (pp, bound, TYPE_SIGN (type));
48 84214 : }
49 :
50 : static void
51 39229 : print_irange_bitmasks (pretty_printer *pp, const irange_bitmask &bm)
52 : {
53 39229 : if (bm.unknown_p ())
54 31405 : return;
55 :
56 7824 : pp_string (pp, " MASK ");
57 7824 : char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p;
58 7824 : unsigned len_mask, len_val;
59 15648 : if (print_hex_buf_size (bm.mask (), &len_mask)
60 7824 : | print_hex_buf_size (bm.value (), &len_val))
61 0 : p = XALLOCAVEC (char, MAX (len_mask, len_val));
62 : else
63 : p = buf;
64 7824 : print_hex (bm.mask (), p);
65 7824 : pp_string (pp, p);
66 7824 : pp_string (pp, " VALUE ");
67 7824 : print_hex (bm.value (), p);
68 7824 : pp_string (pp, p);
69 : }
70 :
71 : void
72 577 : vrange_printer::visit (const unsupported_range &r) const
73 : {
74 577 : pp_string (pp, "[unsupported_range] ");
75 577 : if (r.undefined_p ())
76 : {
77 0 : pp_string (pp, "UNDEFINED");
78 0 : return;
79 : }
80 577 : if (r.varying_p ())
81 : {
82 577 : pp_string (pp, "VARYING");
83 577 : return;
84 : }
85 0 : gcc_unreachable ();
86 : }
87 :
88 : void
89 38912 : vrange_printer::visit (const irange &r) const
90 : {
91 38912 : pp_string (pp, "[irange] ");
92 38912 : if (r.undefined_p ())
93 : {
94 16 : pp_string (pp, "UNDEFINED");
95 16 : return;
96 : }
97 38896 : dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false);
98 38896 : pp_character (pp, ' ');
99 38896 : if (r.varying_p ())
100 : {
101 992 : pp_string (pp, "VARYING");
102 992 : return;
103 : }
104 78686 : for (unsigned i = 0; i < r.num_pairs (); ++i)
105 : {
106 40782 : pp_character (pp, '[');
107 40782 : print_int_bound (pp, r.lower_bound (i), r.type ());
108 40782 : pp_string (pp, ", ");
109 40782 : print_int_bound (pp, r.upper_bound (i), r.type ());
110 40782 : pp_character (pp, ']');
111 : }
112 37904 : print_irange_bitmasks (pp, r.m_bitmask);
113 : }
114 :
115 : void
116 1325 : vrange_printer::print_pt (const prange &r) const
117 : {
118 1325 : bool points_to_p = false;
119 1325 : tree pt = r.pt_invariant ();
120 : if (pt)
121 : points_to_p = true;
122 : else
123 890 : pt = r.pt_invariant_away ();
124 :
125 : if (pt)
126 : {
127 435 : if (points_to_p)
128 435 : pp_string (pp, " -> ");
129 : else
130 0 : pp_string (pp, " ! -> ");
131 435 : dump_generic_node (pp, pt, 0, TDF_NONE | TDF_NOUID, false);
132 435 : if (points_to_p)
133 : {
134 435 : int_range_max sz;
135 435 : int_range_max off;
136 435 : tree b;
137 435 : b = r.pt_base ();
138 435 : r.pt_offset(off);
139 435 : r.pt_size (sz);
140 435 : pp_string (pp, " { Base: ");
141 435 : dump_generic_node (pp, b, 0, TDF_NONE | TDF_NOUID, false);
142 435 : if (!off.varying_p () && !off.undefined_p () && !off.zero_p ())
143 : {
144 0 : pp_string (pp, " ; Off: ");
145 0 : visit (off);
146 : }
147 435 : if (!sz.varying_p () && !sz.undefined_p ())
148 : {
149 435 : pp_string (pp, " ; Size: ");
150 435 : visit (sz);
151 : }
152 435 : pp_string (pp, " }");
153 435 : }
154 :
155 : }
156 1325 : }
157 :
158 : void
159 1433 : vrange_printer::visit (const prange &r) const
160 : {
161 1433 : pp_string (pp, "[prange] ");
162 1433 : if (r.undefined_p ())
163 : {
164 6 : pp_string (pp, "UNDEFINED");
165 6 : return;
166 : }
167 1427 : dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false);
168 1427 : pp_character (pp, ' ');
169 1427 : if (r.varying_p ())
170 : {
171 102 : pp_string (pp, "VARYING");
172 102 : return;
173 : }
174 :
175 1325 : pp_character (pp, '[');
176 1325 : print_int_bound (pp, r.lower_bound (), r.type ());
177 1325 : pp_string (pp, ", ");
178 1325 : print_int_bound (pp, r.upper_bound (), r.type ());
179 1325 : pp_character (pp, ']');
180 1325 : print_irange_bitmasks (pp, r.m_bitmask);
181 : // Dump the points to field if there is one.
182 1325 : print_pt (r);
183 : }
184 :
185 : void
186 324 : vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const
187 : {
188 324 : char s[100];
189 324 : real_to_decimal_for_mode (s, &r, sizeof (s), 0, 1, TYPE_MODE (type));
190 324 : pp_string (pp, s);
191 324 : if (!DECIMAL_FLOAT_TYPE_P (type)
192 : // real_to_hexadecimal prints infinities and NAN as text. No
193 : // need to print them twice.
194 324 : && !real_isinf (&r)
195 559 : && !real_isnan (&r))
196 : {
197 235 : real_to_hexadecimal (s, &r, sizeof (s), 0, 1);
198 235 : pp_printf (pp, " (%s)", s);
199 : }
200 324 : }
201 :
202 : // Print an frange.
203 :
204 : void
205 226 : vrange_printer::visit (const frange &r) const
206 : {
207 226 : pp_string (pp, "[frange] ");
208 226 : if (r.undefined_p ())
209 : {
210 5 : pp_string (pp, "UNDEFINED");
211 5 : return;
212 : }
213 221 : tree type = r.type ();
214 221 : dump_generic_node (pp, type, 0, TDF_NONE, false);
215 221 : pp_string (pp, " ");
216 221 : if (r.varying_p ())
217 : {
218 69 : pp_string (pp, "VARYING");
219 69 : print_frange_nan (r);
220 69 : return;
221 : }
222 152 : if (r.known_isnan ())
223 3 : pp_string (pp, "[]");
224 : else
225 311 : for (unsigned i = 0; i < r.num_pairs (); ++i)
226 : {
227 162 : pp_character (pp, '[');
228 162 : print_real_value (type, r.lower_bound (i));
229 162 : pp_string (pp, ", ");
230 162 : print_real_value (type, r.upper_bound (i));
231 162 : pp_character (pp, ']');
232 : }
233 152 : print_frange_nan (r);
234 : }
235 :
236 : // Print the NAN info for an frange.
237 :
238 : void
239 221 : vrange_printer::print_frange_nan (const frange &r) const
240 : {
241 359 : if (r.maybe_isnan ())
242 : {
243 83 : if (r.m_pos_nan && r.m_neg_nan)
244 : {
245 70 : pp_string (pp, " +-NAN");
246 70 : return;
247 : }
248 13 : bool nan_sign = r.m_neg_nan;
249 13 : if (nan_sign)
250 0 : pp_string (pp, " -NAN");
251 : else
252 13 : pp_string (pp, " +NAN");
253 : }
254 : }
|