From 51920967ba71213231c1462305d76faac336c2d0 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 13 Sep 2018 19:57:27 -0400
Subject: [PATCH 7/9] {NEEDS B&R}: Add pp_humanized_limit and
 pp_humanized_range

gcc/ChangeLog:
	* pretty-print.c (get_power_of_two): New function.
	(struct relative_to_power_of_2): New struct.
	(pp_humanized_limit): New function.
	(pp_humanized_range): New function.
	(selftest::assert_pp_humanized_limit): New function.
	(ASSERT_PP_HUMANIZED_LIMIT): New macro.
	(selftest::assert_pp_humanized_range): New function.
	(ASSERT_PP_HUMANIZED_RANGE): New macro.
	(selftest::test_get_power_of_two): New function.
	(selftest::test_humanized_printing): New function.
	(selftest::pretty_print_c_tests): Call them.
	* pretty-print.h (pp_humanized_limit): New function.
	(pp_humanized_range): New function.
---
 gcc/pretty-print.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/pretty-print.h |   4 ++
 2 files changed, 185 insertions(+)

diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index 7dd900b..7a2cd30 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -1799,6 +1799,107 @@ pp_end_quote (pretty_printer *pp, bool show_color)
   pp_string (pp, close_quote);
 }
 
+/* Get the largest power of two that is less that or equal to VAL.
+
+   FIXME: does this exist in stdlib (e.g. log2l in C99)?  */
+
+static unsigned
+get_power_of_two (unsigned HOST_WIDE_INT val)
+{
+  int power_of_two = 0;
+  while (val >= 2)
+    {
+      val >>= 1;
+      power_of_two++;
+    }
+  return power_of_two;
+}
+
+/* A way to express a number in terms of an offset from a power of two.  */
+
+struct relative_to_power_of_2
+{
+  relative_to_power_of_2 (unsigned HOST_WIDE_INT val)
+  {
+    m_shift = get_power_of_two (val);
+    m_offset = val - (1ul << m_shift);
+
+    if (m_shift > 1)
+      if (m_offset > (1l << (m_shift - 1)))
+	{
+	  m_shift++;
+	  m_offset = val - (1ul << m_shift);
+	}
+  }
+
+  void print (pretty_printer *pp) const
+  {
+    if (m_offset > 0)
+      pp_printf (pp, "(1<<%u)+%wd", m_shift, m_offset);
+    else if (m_offset < 0)
+      pp_printf (pp, "(1<<%u)-%wd", m_shift, -m_offset);
+    else
+      pp_printf (pp, "1<<%u", m_shift);
+  }
+
+  unsigned m_shift;
+  HOST_WIDE_INT m_offset;
+};
+
+/* Print VAL to PP, in a "humanized" way.
+   Small numbers are printed in decimal form (e.g. "42").
+   Large numbers close to a power of two are printed relative to a
+   power of two.  For example, 4294967295 is printed as "(1<<32)-1".  */
+
+void
+pp_humanized_limit (pretty_printer *pp, unsigned HOST_WIDE_INT val)
+{
+  /* For large numbers near a power of two, print them symbolically.
+     "65536" is about the most I can recognize by eye (dmalcolm),
+     1<<17 is where I can't tell at a glance if it is indeed 1<<17.  */
+  const unsigned threshold = 1 << 16;
+  if (val > threshold)
+    {
+      relative_to_power_of_2 rel2 (val);
+
+      /* How near to the large power of two should they be to be
+	 printed in terms of it?  */
+      const unsigned threshold_2 = 100;
+      if (abs (rel2.m_offset) <= threshold_2)
+	{
+	  rel2.print (pp);
+	  return;
+	}
+    }
+
+  /* Otherwise, just print the value as a decimal.  */
+  pp_printf (pp, "%wu", val);
+}
+
+/* Print the range MIN to MAX to PP, in a "humanized" way.
+   For example if MIN == MAX, just one number is printed.
+
+   Return true if both values are 1, false otherwise.
+   FIXME: how do plural forms work for *ranges*?  */
+
+bool
+pp_humanized_range (pretty_printer *pp, unsigned HOST_WIDE_INT min,
+		    unsigned HOST_WIDE_INT max)
+{
+  if (min == max)
+    {
+      pp_humanized_limit (pp, min);
+      return min == 1;
+    }
+  else
+    {
+      pp_humanized_limit (pp, min);
+      pp_string (pp, "...");
+      pp_humanized_limit (pp, max);
+      return false;
+    }
+}
+
 
 /* The string starting at P has LEN (at least 1) bytes left; if they
    start with a valid UTF-8 sequence, return the length of that
@@ -2211,6 +2312,84 @@ test_pp_format ()
 		    "problem with %qs at line %i", "bar", 10);
 }
 
+/* Implementation detail of ASSERT_PP_HUMANIZED_LIMIT.  */
+
+static void
+assert_pp_humanized_limit (const location &loc, unsigned HOST_WIDE_INT val,
+			   const char *expected)
+{
+  pretty_printer pp;
+  pp_humanized_limit (&pp, val);
+  ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
+}
+
+/* Verify that pp_humanized_limit (pp, VAL) is EXPECTED.  */
+
+#define ASSERT_PP_HUMANIZED_LIMIT(VAL, EXPECTED)			\
+  SELFTEST_BEGIN_STMT							\
+    assert_pp_humanized_limit ((SELFTEST_LOCATION), (VAL), (EXPECTED)); \
+  SELFTEST_END_STMT
+
+/* Implementation detail of ASSERT_PP_HUMANIZED_RANGE.  */
+
+static void
+assert_pp_humanized_range (const location &loc, unsigned HOST_WIDE_INT min,
+			   unsigned HOST_WIDE_INT max, const char *expected)
+{
+  pretty_printer pp;
+  pp_humanized_range (&pp, min, max);
+  ASSERT_STREQ_AT (loc, expected, pp_formatted_text (&pp));
+}
+
+/* Verify that pp_humanized_range (pp, MIN, MAX) is EXPECTED.  */
+
+#define ASSERT_PP_HUMANIZED_RANGE(MIN, MAX, EXPECTED)			\
+  SELFTEST_BEGIN_STMT							\
+    assert_pp_humanized_range ((SELFTEST_LOCATION), (MIN), (MAX), (EXPECTED)); \
+  SELFTEST_END_STMT
+
+/* Verify that get_power_of_two works as expected.  */
+
+static void
+test_get_power_of_two ()
+{
+  ASSERT_EQ (get_power_of_two (0), 0);
+  ASSERT_EQ (get_power_of_two (1), 0);
+  ASSERT_EQ (get_power_of_two (2), 1);
+
+  ASSERT_EQ (get_power_of_two (7), 2);
+  ASSERT_EQ (get_power_of_two (8), 3);
+  ASSERT_EQ (get_power_of_two (9), 3);
+
+  ASSERT_EQ (get_power_of_two (65535), 15);
+  ASSERT_EQ (get_power_of_two (65536), 16);
+}
+
+/* Verify that pp_humanized_limit and pp_humanized_range work as expected.  */
+
+static void
+test_humanized_printing ()
+{
+  ASSERT_PP_HUMANIZED_LIMIT (0, "0");
+  ASSERT_PP_HUMANIZED_LIMIT (1, "1");
+  ASSERT_PP_HUMANIZED_LIMIT (2, "2");
+  ASSERT_PP_HUMANIZED_LIMIT (3, "3");
+  ASSERT_PP_HUMANIZED_LIMIT (4, "4");
+  ASSERT_PP_HUMANIZED_LIMIT (42, "42");
+  ASSERT_PP_HUMANIZED_LIMIT (256, "256");
+  ASSERT_PP_HUMANIZED_LIMIT (1<<16, "65536");
+  ASSERT_PP_HUMANIZED_LIMIT ((1<<16) + 1, "(1<<16)+1");
+  ASSERT_PP_HUMANIZED_LIMIT (100000, "100000");
+  ASSERT_PP_HUMANIZED_LIMIT (1<<17, "1<<17");
+  ASSERT_PP_HUMANIZED_LIMIT ((1<<17) - 1, "(1<<17)-1");
+  ASSERT_PP_HUMANIZED_LIMIT ((1<<17) + 1, "(1<<17)+1");
+  ASSERT_PP_HUMANIZED_LIMIT (4294967295, "(1<<32)-1");
+
+  ASSERT_PP_HUMANIZED_RANGE (0, 0, "0");
+  ASSERT_PP_HUMANIZED_RANGE (0, 1, "0...1");
+  ASSERT_PP_HUMANIZED_RANGE ((1<<16), (1<<17), "65536...1<<17");
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -2218,6 +2397,8 @@ pretty_print_c_tests ()
 {
   test_basic_printing ();
   test_pp_format ();
+  test_get_power_of_two ();
+  test_humanized_printing ();
 }
 
 } // namespace selftest
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index 2decc51..e4a8c97 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -416,4 +416,8 @@ pp_wide_integer (pretty_printer *pp, HOST_WIDE_INT i)
 template<unsigned int N, typename T>
 void pp_wide_integer (pretty_printer *pp, const poly_int_pod<N, T> &);
 
+extern void pp_humanized_limit (pretty_printer *, unsigned HOST_WIDE_INT);
+extern bool pp_humanized_range (pretty_printer *, unsigned HOST_WIDE_INT,
+				unsigned HOST_WIDE_INT);
+
 #endif /* GCC_PRETTY_PRINT_H */
-- 
1.8.5.3

