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