1 | /* Pretty print support for value ranges. |
2 | Copyright (C) 2019-2024 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 | void |
34 | vrange_printer::visit (const unsupported_range &r) const |
35 | { |
36 | pp_string (pp, "[unsupported_range] " ); |
37 | if (r.undefined_p ()) |
38 | { |
39 | pp_string (pp, "UNDEFINED" ); |
40 | return; |
41 | } |
42 | if (r.varying_p ()) |
43 | { |
44 | pp_string (pp, "VARYING" ); |
45 | return; |
46 | } |
47 | gcc_unreachable (); |
48 | } |
49 | |
50 | void |
51 | vrange_printer::visit (const irange &r) const |
52 | { |
53 | pp_string (pp, "[irange] " ); |
54 | if (r.undefined_p ()) |
55 | { |
56 | pp_string (pp, "UNDEFINED" ); |
57 | return; |
58 | } |
59 | dump_generic_node (pp, r.type (), 0, TDF_NONE | TDF_NOUID, false); |
60 | pp_character (pp, ' '); |
61 | if (r.varying_p ()) |
62 | { |
63 | pp_string (pp, "VARYING" ); |
64 | return; |
65 | } |
66 | for (unsigned i = 0; i < r.num_pairs (); ++i) |
67 | { |
68 | pp_character (pp, '['); |
69 | print_irange_bound (w: r.lower_bound (pair: i), type: r.type ()); |
70 | pp_string (pp, ", " ); |
71 | print_irange_bound (w: r.upper_bound (pair: i), type: r.type ()); |
72 | pp_character (pp, ']'); |
73 | } |
74 | print_irange_bitmasks (r); |
75 | } |
76 | |
77 | void |
78 | vrange_printer::print_irange_bound (const wide_int &bound, tree type) const |
79 | { |
80 | wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); |
81 | wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); |
82 | |
83 | if (INTEGRAL_TYPE_P (type) |
84 | && !TYPE_UNSIGNED (type) |
85 | && bound == type_min |
86 | && TYPE_PRECISION (type) != 1) |
87 | pp_string (pp, "-INF" ); |
88 | else if (bound == type_max && TYPE_PRECISION (type) != 1) |
89 | pp_string (pp, "+INF" ); |
90 | else |
91 | pp_wide_int (pp, w: bound, TYPE_SIGN (type)); |
92 | } |
93 | |
94 | void |
95 | vrange_printer::print_irange_bitmasks (const irange &r) const |
96 | { |
97 | irange_bitmask bm = r.m_bitmask; |
98 | if (bm.unknown_p ()) |
99 | return; |
100 | |
101 | pp_string (pp, " MASK " ); |
102 | char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p; |
103 | unsigned len_mask, len_val; |
104 | if (print_hex_buf_size (wi: bm.mask (), len: &len_mask) |
105 | | print_hex_buf_size (wi: bm.value (), len: &len_val)) |
106 | p = XALLOCAVEC (char, MAX (len_mask, len_val)); |
107 | else |
108 | p = buf; |
109 | print_hex (wi: bm.mask (), buf: p); |
110 | pp_string (pp, p); |
111 | pp_string (pp, " VALUE " ); |
112 | print_hex (wi: bm.value (), buf: p); |
113 | pp_string (pp, p); |
114 | } |
115 | |
116 | void |
117 | vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const |
118 | { |
119 | char s[100]; |
120 | real_to_decimal_for_mode (s, &r, sizeof (s), 0, 1, TYPE_MODE (type)); |
121 | pp_string (pp, s); |
122 | if (!DECIMAL_FLOAT_TYPE_P (type) |
123 | // real_to_hexadecimal prints infinities and NAN as text. No |
124 | // need to print them twice. |
125 | && !real_isinf (&r) |
126 | && !real_isnan (&r)) |
127 | { |
128 | real_to_hexadecimal (s, &r, sizeof (s), 0, 1); |
129 | pp_printf (pp, " (%s)" , s); |
130 | } |
131 | } |
132 | |
133 | // Print an frange. |
134 | |
135 | void |
136 | vrange_printer::visit (const frange &r) const |
137 | { |
138 | pp_string (pp, "[frange] " ); |
139 | if (r.undefined_p ()) |
140 | { |
141 | pp_string (pp, "UNDEFINED" ); |
142 | return; |
143 | } |
144 | tree type = r.type (); |
145 | dump_generic_node (pp, type, 0, TDF_NONE, false); |
146 | pp_string (pp, " " ); |
147 | if (r.varying_p ()) |
148 | { |
149 | pp_string (pp, "VARYING" ); |
150 | print_frange_nan (r); |
151 | return; |
152 | } |
153 | pp_character (pp, '['); |
154 | bool has_endpoints = !r.known_isnan (); |
155 | if (has_endpoints) |
156 | { |
157 | print_real_value (type, r: r.lower_bound ()); |
158 | pp_string (pp, ", " ); |
159 | print_real_value (type, r: r.upper_bound ()); |
160 | } |
161 | pp_character (pp, ']'); |
162 | print_frange_nan (r); |
163 | } |
164 | |
165 | // Print the NAN info for an frange. |
166 | |
167 | void |
168 | vrange_printer::print_frange_nan (const frange &r) const |
169 | { |
170 | if (r.maybe_isnan ()) |
171 | { |
172 | if (r.m_pos_nan && r.m_neg_nan) |
173 | { |
174 | pp_string (pp, " +-NAN" ); |
175 | return; |
176 | } |
177 | bool nan_sign = r.m_neg_nan; |
178 | if (nan_sign) |
179 | pp_string (pp, " -NAN" ); |
180 | else |
181 | pp_string (pp, " +NAN" ); |
182 | } |
183 | } |
184 | |