unicode, libcpp: Optimize cpp_is_{combining,printable}_char

Message ID ar333Dz0K4cXYfdy@tucnak
State New
Headers
Series unicode, libcpp: Optimize cpp_is_{combining,printable}_char |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply

Commit Message

Jakub Jelinek Oct. 1, 2026, 6:04 a.m. UTC
  Hi!

The following patch is on top of the
https://gcc.gnu.org/pipermail/gcc-patches/2026-September/732488.html
patch adds a small optimization.
The 2 scripts (and gen_wcwidth.py too) emit 2 arrays each, rather than
one.  The first array contains various unicode code points after which
some property changes and the second array contains the values the
function should return for the corresponding range.
Now, the type of the wcwidth result is an integer, where we need values
0, 1, 2, so the current way of representing it as an array of unsigned char
is somewhat reasonable (we could with some effort shrink it by storing
say 4 ranges in one byte).
The 2 properties this patch deals with are boolean only, and the arrays
emitted are:
static const bool is_combining[] = {
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
...
  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
};
and similarly for is_printable.  Given the boolean result, it actually
has to be an array of alternating boolean values because the only possible
change in the property is going from false to true or going from true to
false, if there are multiple code points with true or with false adjacent to
each other, they are merged.
So, the following patch takes advantage of this and simply optimizes away
the two arrays:
    36: 0000000000002600   415 OBJECT  LOCAL  DEFAULT    9 _ZL12is_combining
...
    38: 00000000000008e0  1481 OBJECT  LOCAL  DEFAULT    9 _ZL12is_printable
and thus saves 415+1481 bytes in libcpp .rodata section.  The value of the
property can be reliably computed, instead of reading
range_values[begin]
we return
(default_value ^ (begin & 1))
Now, the patch implements this as a template option just to help it being
optimized out properly and not actually tested at runtime (compile time
of other programs), though perhaps at least when building with optimizations
it might be optimized anyway (the wcwidth case and these 2 use different
instantiation of the template, and these 2 cases would pass identical
nullptr for range_values and false for default_value arguments, so IPA-VRP
or IPA-CP could optimize those.  On the other side, the default_value could
be also turned into template parameter.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2026-10-01  Jakub Jelinek  <jakub@redhat.com>

	* unicode/gen-combining-chars.py: Remove printing of is_combining
	array.
	* unicode/gen-printable-chars.py: Remove printing of is_printable
	array.

	* combining-chars.inc: Regenerated.
	* printable-chars.inc: Regenerated.
	* charset.cc (get_cppchar_property): Add another template argument,
	if true, don't use range_values argument but instead assume it points
	to alternating values.
	(cpp_wcwidth, cpp_is_combining_char, cpp_is_printable_char): Adjust
	callers.


	Jakub
  

Patch

--- a/contrib/unicode/gen-combining-chars.py	2026-09-30 09:59:04.869903583 +0200
+++ b/contrib/unicode/gen-combining-chars.py	2026-09-30 09:59:55.980633676 +0200
@@ -89,14 +89,3 @@  for i, r in enumerate(ranges):
         print("\n  ", end="")
     print("0x%x," % r.end, end="")
 print("\n};\n")
-print("static const bool is_combining[] = {", end="")
-for i, r in enumerate(ranges):
-    if i % 24:
-        print(" ", end="")
-    else:
-        print("\n  ", end="")
-    if r.value:
-        print("1,", end="")
-    else:
-        print("0,", end="")
-print("\n};")
--- a/contrib/unicode/gen-printable-chars.py	2026-09-30 09:59:04.869316342 +0200
+++ b/contrib/unicode/gen-printable-chars.py	2026-09-30 10:00:04.300522552 +0200
@@ -89,14 +89,3 @@  for i, r in enumerate(ranges):
         print("\n  ", end="")
     print("0x%x," % r.end, end="")
 print("\n};\n")
-print("static const bool is_printable[] = {", end="")
-for i, r in enumerate(ranges):
-    if i % 24:
-        print(" ", end="")
-    else:
-        print("\n  ", end="")
-    if r.value:
-        print("1,", end="")
-    else:
-        print("0,", end="")
-print("\n};")
--- a/libcpp/combining-chars.inc	2026-09-30 09:59:04.870216645 +0200
+++ b/libcpp/combining-chars.inc	2026-09-30 10:00:40.566038170 +0200
@@ -56,23 +56,3 @@  static const cppchar_t combining_range_e
   0x1e6f4, 0x1e6f5, 0x1e8cf, 0x1e8d6, 0x1e943, 0x1e94a, 0x10fffe,
 };
 
-static const bool is_combining[] = {
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0,
-};
--- a/libcpp/printable-chars.inc	2026-09-30 09:59:04.870568225 +0200
+++ b/libcpp/printable-chars.inc	2026-09-30 10:00:22.587278302 +0200
@@ -190,67 +190,3 @@  static const cppchar_t printable_range_e
   0x10fffe,
 };
 
-static const bool is_printable[] = {
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
-  0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
-};
--- a/libcpp/charset.cc	2026-08-06 11:45:03.613723745 +0200
+++ b/libcpp/charset.cc	2026-09-30 10:08:26.021820149 +0200
@@ -3510,7 +3510,7 @@  cpp_display_column_to_byte_column (const
   return dw.bytes_processed () + MAX (0, display_col - avail_display);
 }
 
-template <typename PropertyType>
+template <typename PropertyType, bool ImplicitValues>
 PropertyType
 get_cppchar_property (cppchar_t c,
 		      const cppchar_t *range_ends,
@@ -3518,8 +3518,11 @@  get_cppchar_property (cppchar_t c,
 		      size_t num_ranges,
 		      PropertyType default_value)
 {
+  /* If ImplicitValues is true, range_values is not present
+     and assumed to contain alternating
+     { default_value, !default_value, default_value, !default_value, ... }.  */
   if (__builtin_expect (c <= range_ends[0], true))
-    return range_values[0];
+    return ImplicitValues ? default_value : range_values[0];
 
   /* Binary search the tables.  */
   int begin = 1;
@@ -3539,7 +3542,8 @@  get_cppchar_property (cppchar_t c,
     } while (len);
 
   if (__builtin_expect (begin != end, true))
-    return range_values[begin];
+    return (ImplicitValues ? (default_value ^ (begin & 1))
+	    : range_values[begin]);
 
   return default_value;
 }
@@ -3563,11 +3567,9 @@  cpp_wcwidth (cppchar_t c)
 {
   const size_t num_ranges
     = sizeof wcwidth_range_ends / sizeof (*wcwidth_range_ends);
-  return get_cppchar_property<unsigned char > (c,
-					       &wcwidth_range_ends[0],
-					       &wcwidth_widths[0],
-					       num_ranges,
-					       1);
+  return get_cppchar_property<unsigned char, false> (c, &wcwidth_range_ends[0],
+						     &wcwidth_widths[0],
+						     num_ranges, 1);
 }
 
 #include "combining-chars.inc"
@@ -3577,11 +3579,8 @@  cpp_is_combining_char (cppchar_t c)
 {
   const size_t num_ranges
     = sizeof combining_range_ends / sizeof (*combining_range_ends);
-  return get_cppchar_property<bool> (c,
-				     &combining_range_ends[0],
-				     &is_combining[0],
-				     num_ranges,
-				     false);
+  return get_cppchar_property<bool, true> (c, &combining_range_ends[0],
+					   nullptr, num_ranges, false);
 }
 
 #include "printable-chars.inc"
@@ -3591,9 +3590,6 @@  cpp_is_printable_char (cppchar_t c)
 {
   const size_t num_ranges
     = sizeof printable_range_ends / sizeof (*printable_range_ends);
-  return get_cppchar_property<bool> (c,
-				     &printable_range_ends[0],
-				     &is_printable[0],
-				     num_ranges,
-				     false);
+  return get_cppchar_property<bool, true> (c, &printable_range_ends[0],
+					   nullptr, num_ranges, false);
 }