blob: 3a3b4b44cbdb229523c3ce79f4d53b397e96ac15 [file] [log] [blame]
/* 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");
}
}