(root)/
gcc-13.2.0/
gcc/
value-range-pretty-print.cc
/* Pretty print support for value ranges.
   Copyright (C) 2019-2023 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");
    }
}