| /* Pretty print support for value ranges. |
| Copyright (C) 2019-2022 Free Software Foundation, Inc. |
| Contributed by Aldy Hernandez <aldyh@redhat.com>. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "ssa.h" |
| #include "tree-pretty-print.h" |
| #include "fold-const.h" |
| #include "gimple-range.h" |
| #include "value-range-pretty-print.h" |
| |
| void |
| vrange_printer::visit (const unsupported_range &r) const |
| { |
| pp_string (pp, "[unsupported_range] "); |
| if (r.undefined_p ()) |
| { |
| pp_string (pp, "UNDEFINED"); |
| return; |
| } |
| if (r.varying_p ()) |
| { |
| pp_string (pp, "VARYING"); |
| return; |
| } |
| gcc_unreachable (); |
| } |
| |
| void |
| vrange_printer::visit (const irange &r) const |
| { |
| pp_string (pp, "[irange] "); |
| if (r.undefined_p ()) |
| { |
| pp_string (pp, "UNDEFINED"); |
| return; |
| } |
| dump_generic_node (pp, r.type (), 0, TDF_NONE, false); |
| pp_character (pp, ' '); |
| if (r.varying_p ()) |
| { |
| pp_string (pp, "VARYING"); |
| return; |
| } |
| // Handle legacy symbolics. |
| if (!r.constant_p ()) |
| { |
| if (r.kind () == VR_ANTI_RANGE) |
| pp_character (pp, '~'); |
| pp_character (pp, '['); |
| dump_generic_node (pp, r.min (), 0, TDF_NONE, false); |
| pp_string (pp, ", "); |
| dump_generic_node (pp, r.max (), 0, TDF_NONE, false); |
| pp_character (pp, ']'); |
| print_irange_bitmasks (r); |
| return; |
| } |
| for (unsigned i = 0; i < r.num_pairs (); ++i) |
| { |
| pp_character (pp, '['); |
| print_irange_bound (r.lower_bound (i), r.type ()); |
| pp_string (pp, ", "); |
| print_irange_bound (r.upper_bound (i), r.type ()); |
| pp_character (pp, ']'); |
| } |
| print_irange_bitmasks (r); |
| } |
| |
| void |
| vrange_printer::print_irange_bound (const wide_int &bound, tree type) const |
| { |
| wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); |
| wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); |
| |
| if (INTEGRAL_TYPE_P (type) |
| && !TYPE_UNSIGNED (type) |
| && bound == type_min |
| && TYPE_PRECISION (type) != 1) |
| pp_string (pp, "-INF"); |
| else if (bound == type_max && TYPE_PRECISION (type) != 1) |
| pp_string (pp, "+INF"); |
| else |
| pp_wide_int (pp, bound, TYPE_SIGN (type)); |
| } |
| |
| void |
| vrange_printer::print_irange_bitmasks (const irange &r) const |
| { |
| wide_int nz = r.get_nonzero_bits (); |
| if (nz == -1) |
| return; |
| |
| pp_string (pp, " NONZERO "); |
| char buf[WIDE_INT_PRINT_BUFFER_SIZE]; |
| print_hex (nz, buf); |
| pp_string (pp, buf); |
| } |
| |
| void |
| vrange_printer::print_real_value (tree type, const REAL_VALUE_TYPE &r) const |
| { |
| char s[100]; |
| real_to_decimal_for_mode (s, &r, sizeof (s), 0, 1, TYPE_MODE (type)); |
| pp_string (pp, s); |
| if (!DECIMAL_FLOAT_TYPE_P (type) |
| // real_to_hexadecimal prints infinities and NAN as text. No |
| // need to print them twice. |
| && !real_isinf (&r) |
| && !real_isnan (&r)) |
| { |
| real_to_hexadecimal (s, &r, sizeof (s), 0, 1); |
| pp_printf (pp, " (%s)", s); |
| } |
| } |
| |
| // Print an frange. |
| |
| void |
| vrange_printer::visit (const frange &r) const |
| { |
| pp_string (pp, "[frange] "); |
| if (r.undefined_p ()) |
| { |
| pp_string (pp, "UNDEFINED"); |
| return; |
| } |
| tree type = r.type (); |
| dump_generic_node (pp, type, 0, TDF_NONE, false); |
| pp_string (pp, " "); |
| if (r.varying_p ()) |
| { |
| pp_string (pp, "VARYING"); |
| print_frange_nan (r); |
| return; |
| } |
| pp_character (pp, '['); |
| bool has_endpoints = !r.known_isnan (); |
| if (has_endpoints) |
| { |
| print_real_value (type, r.lower_bound ()); |
| pp_string (pp, ", "); |
| print_real_value (type, r.upper_bound ()); |
| } |
| pp_character (pp, ']'); |
| print_frange_nan (r); |
| } |
| |
| // Print the NAN info for an frange. |
| |
| void |
| vrange_printer::print_frange_nan (const frange &r) const |
| { |
| if (r.maybe_isnan ()) |
| { |
| if (r.m_pos_nan && r.m_neg_nan) |
| { |
| pp_string (pp, " +-NAN"); |
| return; |
| } |
| bool nan_sign = r.m_neg_nan; |
| if (nan_sign) |
| pp_string (pp, " -NAN"); |
| else |
| pp_string (pp, " +NAN"); |
| } |
| } |