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