From: Kyrylo Tkachov <[email protected]>

This is an alternative to 
https://gcc.gnu.org/pipermail/gcc-patches/2026-November/738271.html
after feedback from various folks.

get_attributes builds an attribute list for every function decl registered by
the arm_neon.h and arm_sve.h pragmas, interning the same few attribute names
through get_identifier and consing the same few nodes tens of thousands of
times.  The list depends only on the streaming mode, the kind of global state
the function accesses, whether it can trap and which of the ZA and ZT0 state
it reads and writes, so there are only a few distinct lists.

Build each distinct list once, cache it in a small array indexed by those
inputs and share it between the decls that need it.  The middle end already
shares attribute lists between decls.  decl_attributes conses its own nodes
onto a decl's attribute list, and the only in-place rewrite of an attribute's
arguments, in aarch64_merge_string_arguments, sorts the ZA and ZT0 state
strings of the in, out and inout attributes, which is idempotent.

Instructions retired for -fsyntax-only on a file that includes just the
header, on top of the preceding table-sizing patch, cc1 built with
--enable-checking=release:

                     arm_neon.h   arm_sve.h   both
  this patch               -0.2%      -13.2%  -3.0%
  cumulative               -0.3%      -14.7%  -3.3%

Bootstrapped and tested on aarch64-none-linux.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

        * config/aarch64/aarch64-acle-builtins.cc (attribute_cache): New
        variable.
        (function_builder::get_attributes): Cache the attribute list for each
        distinct combination of inputs.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/config/aarch64/aarch64-acle-builtins.cc | 55 ++++++++++++++-------
 1 file changed, 37 insertions(+), 18 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-acle-builtins.cc 
b/gcc/config/aarch64/aarch64-acle-builtins.cc
index a3f967e7971..30d5d3f2d41 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.cc
+++ b/gcc/config/aarch64/aarch64-acle-builtins.cc
@@ -756,39 +756,58 @@ add_shared_state_attribute (const char *name, bool is_in, 
bool is_out,
   return attrs;
 }
 
+/* The attribute lists that get_attributes has built so far, indexed by the
+   values that determine their contents.  See get_attributes for how the index
+   is formed.  */
+static GTY(()) tree attribute_cache[2 * 3 * 3 * 16];
+
 /* Return the appropriate function attributes for INSTANCE, which requires
-   the architecture extensions in REQUIRED_EXTENSIONS.  */
+   the architecture extensions in REQUIRED_EXTENSIONS.  The result depends only
+   on the streaming mode, the kind of global state that INSTANCE accesses,
+   whether it can trap and which of the ZA and ZT0 state it reads and writes,
+   so there are only a few distinct lists.  Build each one once and share it
+   between all the decls that need it.  */
 tree
 function_builder::get_attributes (const function_instance &instance,
                                  aarch64_required_extensions
                                    required_extensions)
 {
+  unsigned int flags = instance.call_properties ();
+  unsigned int streaming = (required_extensions.sm_off == 0 ? 0
+                           : required_extensions.sm_on != 0 ? 1 : 2);
+  unsigned int memory = (instance.modifies_global_state_p () ? 2
+                        : instance.reads_global_state_p () ? 1 : 0);
+  bool nothrow = !flag_non_call_exceptions || !instance.could_trap_p ();
+  unsigned int state = (((flags & CP_READ_ZA) ? 1 : 0)
+                       | ((flags & CP_WRITE_ZA) ? 2 : 0)
+                       | ((flags & CP_READ_ZT0) ? 4 : 0)
+                       | ((flags & CP_WRITE_ZT0) ? 8 : 0));
+  tree &cached = attribute_cache[((streaming * 3 + memory) * 2 + nothrow) * 16
+                                + state];
+  if (cached)
+    return cached;
+
   tree attrs = NULL_TREE;
 
-  if (required_extensions.sm_off == 0)
+  if (streaming == 0)
     attrs = add_attribute ("arm", "streaming", NULL_TREE, attrs);
-  else if (required_extensions.sm_on != 0)
+  else if (streaming == 1)
     attrs = add_attribute ("arm", "streaming_compatible", NULL_TREE, attrs);
 
-  attrs = add_shared_state_attribute ("in", true, false,
-                                     instance.call_properties (), attrs);
-  attrs = add_shared_state_attribute ("out", false, true,
-                                     instance.call_properties (), attrs);
-  attrs = add_shared_state_attribute ("inout", true, true,
-                                     instance.call_properties (), attrs);
+  attrs = add_shared_state_attribute ("in", true, false, flags, attrs);
+  attrs = add_shared_state_attribute ("out", false, true, flags, attrs);
+  attrs = add_shared_state_attribute ("inout", true, true, flags, attrs);
 
-  if (!instance.modifies_global_state_p ())
-    {
-      if (instance.reads_global_state_p ())
-       attrs = add_attribute ("pure", attrs);
-      else
-       attrs = add_attribute ("const", attrs);
-    }
+  if (memory == 0)
+    attrs = add_attribute ("const", attrs);
+  else if (memory == 1)
+    attrs = add_attribute ("pure", attrs);
 
-  if (!flag_non_call_exceptions || !instance.could_trap_p ())
+  if (nothrow)
     attrs = add_attribute ("nothrow", attrs);
 
-  return add_attribute ("leaf", attrs);
+  cached = add_attribute ("leaf", attrs);
+  return cached;
 }
 
 /* Add a function called NAME with type FNTYPE and attributes ATTRS.
-- 
2.54.0 (Apple Git-157)

Reply via email to