In theory, it is possible to inline a callee function into a caller
function with incompatible streaming state, if we can prove that the
body of the callee function will behave identically in both streaming
and non-streaming mode.  Unfortunately the existing checks are far too
lenient, so this can result in ICEs or incorrect codegen.

Fixing the checks is non-trivial, so remove them.

If this functionality is to be correctly implemented in future, it would
need to include at least the following incompatibility checks:
- Code in the callee that depends upon the vector length in any way.
- A streaming compatible function called by the callee, that would be
  run under a different mode after inlining.
- An always_inline function called by the callee, that can't be inlined
  into the new caller.
- Intrinsics that have different architecture requirements in streaming
  vs. non-streaming mode (for example, many AdvSIMD intrinsics might be
  unavailable in streaming mode).

gcc/ChangeLog:

        PR target/124416
        * config/aarch64/aarch64.cc (AARCH64_IPA_SM_FIXED): Delete.
        (aarch64_update_ipa_fn_target_info): Don't set
        AARCH64_IPA_SM_FIXED.
        (aarch64_can_inline_p): Remove AARCH64_IPA_SM_FIXED uses.

gcc/testsuite/ChangeLog:

        PR target/124416
        * gcc.target/aarch64/sme/inlining_16.c: New test.
        * gcc.target/aarch64/sme/inlining_17.c: New test.
        * gcc.target/aarch64/sme/inlining_18.c: New test.


diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 
7f4effc0901f86ca62908692a9ee35bf6a047fd4..53830308de2fc566da80237f68423a7318db4668
 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -22255,11 +22255,6 @@ aarch64_tribools_ok_for_inlining_p (int caller, int 
callee,
 
 /* Bit allocations for ipa_fn_summary::target_info.  */
 
-/* Set if the function contains a stmt that relies on the function's
-   choice of PSTATE.SM setting (0 for non-streaming, 1 for streaming).
-   Not meaningful for streaming-compatible functions.  */
-constexpr auto AARCH64_IPA_SM_FIXED = 1U << 0;
-
 /* Set if the function clobbers ZA and ZT0.  Not meaningful for functions that
    have ZA state.  */
 constexpr auto AARCH64_IPA_CLOBBERS_ZA = 1U << 1;
@@ -22282,9 +22277,6 @@ aarch64_update_ipa_fn_target_info (unsigned int &info, 
const gimple *stmt)
 {
   if (auto *ga = dyn_cast<const gasm *> (stmt))
     {
-      /* We don't know what the asm does, so conservatively assume that
-        it requires the function's current SM mode.  */
-      info |= AARCH64_IPA_SM_FIXED;
       for (unsigned int i = 0; i < gimple_asm_nclobbers (ga); ++i)
        {
          tree op = gimple_asm_clobber_op (ga, i);
@@ -22295,18 +22287,6 @@ aarch64_update_ipa_fn_target_info (unsigned int &info, 
const gimple *stmt)
            info |= AARCH64_IPA_CLOBBERS_ZT0;
        }
     }
-  if (auto *call = dyn_cast<const gcall *> (stmt))
-    {
-      if (gimple_call_builtin_p (call, BUILT_IN_MD))
-       {
-         /* The attributes on AArch64 builtins are supposed to be accurate.
-            If the function isn't marked streaming-compatible then it
-            needs whichever SM mode it selects.  */
-         tree decl = gimple_call_fndecl (call);
-         if (aarch64_fndecl_pstate_sm (decl) != 0)
-           info |= AARCH64_IPA_SM_FIXED;
-       }
-    }
   return true;
 }
 
@@ -22362,17 +22342,11 @@ aarch64_can_inline_p (tree caller, tree callee)
 
   /* Streaming-compatible code can be inlined into functions with any
      PSTATE.SM mode.  Otherwise the caller and callee must agree on
-     PSTATE.SM mode, unless we can prove that the callee is naturally
-     streaming-compatible with behaviour that is independent of streaming
-     state.  If the callee is marked as always inline, then this last
-     exception doesn't apply, to ensure that error reporting is unaffected
-     by differing optimisations.  */
+     PSTATE.SM mode.  */
 
   auto caller_sm = (aarch64_get_isa_flags (caller_opts) & AARCH64_FL_SM_STATE);
   auto callee_sm = (aarch64_get_isa_flags (callee_opts) & AARCH64_FL_SM_STATE);
-  if (callee_sm
-      && caller_sm != callee_sm
-      && (always_inline || callee_has_property (AARCH64_IPA_SM_FIXED)))
+  if (callee_sm && caller_sm != callee_sm)
     return false;
 
   /* aarch64_function_attribute_inlinable_p prevents new-ZA and new-ZT0
diff --git a/gcc/testsuite/gcc.target/aarch64/sme/inlining_16.c 
b/gcc/testsuite/gcc.target/aarch64/sme/inlining_16.c
new file mode 100644
index 
0000000000000000000000000000000000000000..5f54683e4e796dc1fba1e7b2d343755fe9b64228
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme/inlining_16.c
@@ -0,0 +1,51 @@
+/* { dg-options "-O3" } */
+#include <arm_sme.h>
+
+#pragma GCC target "+sve"
+
+static inline int callee_ns (void)
+{
+  return svcntw ();
+}
+
+int caller1_s(void) __arm_streaming
+{
+  return callee_ns () + svcntw ();
+}
+
+int caller1_sc(void) __arm_streaming_compatible
+{
+  return callee_ns () + svcntw ();
+}
+
+static inline int callee_s (void) __arm_streaming
+{
+  return svcntw ();
+}
+
+int caller2_ns(void)
+{
+  return callee_s () + svcntw ();
+}
+
+int caller2_sc(void) __arm_streaming_compatible
+{
+  return callee_s () + svcntw ();
+}
+
+static inline int callee_ls (void) __arm_streaming
+{
+  return svcntw ();
+}
+
+int caller3_ns(void)
+{
+  return callee_ls () + svcntw ();
+}
+
+int caller3_sc(void) __arm_streaming_compatible
+{
+  return callee_ls () + svcntw ();
+}
+
+/* { dg-final { scan-assembler-not {cnth} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sme/inlining_17.c 
b/gcc/testsuite/gcc.target/aarch64/sme/inlining_17.c
new file mode 100644
index 
0000000000000000000000000000000000000000..7f132798c44015a318b83a8fe375aa9f17c7b2eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme/inlining_17.c
@@ -0,0 +1,91 @@
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sme.h>
+
+#pragma GCC target "+sve"
+
+int child_sc (void) __arm_streaming_compatible;
+
+
+static inline int callee_ns (void)
+{
+  return child_sc ();
+}
+
+/*
+** caller1_s:
+**     ...
+**     bl      callee_ns
+**     ...
+*/
+int caller1_s(void) __arm_streaming
+{
+  return callee_ns ();
+}
+
+/*
+** caller1_sc:
+**     ...
+**     bl      callee_ns
+**     ...
+*/
+int caller1_sc(void) __arm_streaming_compatible
+{
+  return callee_ns ();
+}
+
+static inline int callee_s (void) __arm_streaming
+{
+  return child_sc ();
+}
+
+/*
+** caller2_ns:
+**     ...
+**     bl      callee_s
+**     ...
+*/
+int caller2_ns(void)
+{
+  return callee_s ();
+}
+
+/*
+** caller2_sc:
+**     ...
+**     bl      callee_s
+**     ...
+*/
+int caller2_sc(void) __arm_streaming_compatible
+{
+  return callee_s ();
+}
+
+__arm_locally_streaming
+static inline int callee_ls (void)
+{
+  return child_sc ();
+}
+
+/*
+** caller3_ns:
+**     ...
+**     b       callee_ls
+**     ...
+*/
+int caller3_ns(void)
+{
+  return callee_ls ();
+}
+
+/*
+** caller3_sc:
+**     ...
+**     bl      callee_ls
+**     ...
+*/
+int caller3_sc(void) __arm_streaming_compatible
+{
+  return callee_ls ();
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sme/inlining_18.c 
b/gcc/testsuite/gcc.target/aarch64/sme/inlining_18.c
new file mode 100644
index 
0000000000000000000000000000000000000000..d967d037740f2fc989471dce99d0cbe609aaed21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme/inlining_18.c
@@ -0,0 +1,100 @@
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sme.h>
+
+#pragma GCC target "+sve"
+
+__attribute__((always_inline))
+static inline int child_ns (void)
+{
+  return svcntw ();
+}
+
+__attribute__((always_inline))
+static inline int child_s (void) __arm_streaming
+{
+  return svcntw ();
+}
+
+static inline int callee_ns (void)
+{
+  return child_ns ();
+}
+
+/*
+** caller1_s:
+**     ...
+**     bl      callee_ns
+**     ...
+*/
+int caller1_s(void) __arm_streaming
+{
+  return callee_ns ();
+}
+
+/*
+** caller1_sc:
+**     ...
+**     bl      callee_ns
+**     ...
+*/
+int caller1_sc(void) __arm_streaming_compatible
+{
+  return callee_ns ();
+}
+
+static inline int callee_s (void) __arm_streaming
+{
+  return child_s ();
+}
+
+/*
+** caller2_ns:
+**     ...
+**     bl      callee_s
+**     ...
+*/
+int caller2_ns(void)
+{
+  return callee_s ();
+}
+
+/*
+** caller2_sc:
+**     ...
+**     bl      callee_s
+**     ...
+*/
+int caller2_sc(void) __arm_streaming_compatible
+{
+  return callee_s ();
+}
+
+__arm_locally_streaming
+static inline int callee_ls (void)
+{
+  return child_s ();
+}
+
+/*
+** caller3_ns:
+**     ...
+**     b       callee_ls
+**     ...
+*/
+int caller3_ns(void)
+{
+  return callee_ls ();
+}
+
+/*
+** caller3_sc:
+**     ...
+**     bl      callee_ls
+**     ...
+*/
+int caller3_sc(void) __arm_streaming_compatible
+{
+  return callee_ls ();
+}

Reply via email to