]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64: Recognise svundef idiom [PR114577]
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 4 Apr 2024 13:15:49 +0000 (14:15 +0100)
committerRichard Sandiford <richard.sandiford@arm.com>
Thu, 4 Apr 2024 13:15:49 +0000 (14:15 +0100)
GCC 14 adds the header file arm_neon_sve_bridge.h to help interface
SVE and Advanced SIMD code.  One of the defined idioms is:

  svset_neonq (svundef_TYPE (), advsimd_vector)

which simply reinterprets advsimd_vector as an SVE vector without
regard for what's in the upper bits.

GCC was failing to recognise this idiom, which was likely to
significantly hamper adoption.

There is (AFAIK) no good way of representing an extension with
undefined bits in gimple.  We could add an internal-only builtin
to represent it, but the current framework makes that somewhat
awkward.  It also doesn't seem very forward-looking.

This patch instead goes for the simpler approach of recognising
undefined arguments at expansion time.

gcc/
PR target/114577
* config/aarch64/aarch64-sve-builtins.h (aarch64_sve::lookup_fndecl):
Declare.
* config/aarch64/aarch64-sve-builtins.cc (aarch64_sve::lookup_fndecl):
New function.
* config/aarch64/aarch64-sve-builtins-base.cc (is_undef): Likewise.
(svset_neonq_impl::expand): Optimise expansions whose first argument
is undefined.

gcc/testsuite/
PR target/114577
* gcc.target/aarch64/sve/acle/general/pr114577_1.c: New test.
* gcc.target/aarch64/sve/acle/general/pr114577_2.c: Likewise.

gcc/config/aarch64/aarch64-sve-builtins-base.cc
gcc/config/aarch64/aarch64-sve-builtins.cc
gcc/config/aarch64/aarch64-sve-builtins.h
gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_2.c [new file with mode: 0644]

index a8c3f84a70b5353f48ddd34d9a5e9200a3882cba..257ca5bf6adcddfd426262e31d69aa1c6b8890b7 100644 (file)
 #include "aarch64-builtins.h"
 #include "ssa.h"
 #include "gimple-fold.h"
+#include "tree-ssa.h"
 
 using namespace aarch64_sve;
 
 namespace {
 
+/* Return true if VAL is an undefined value.  */
+static bool
+is_undef (tree val)
+{
+  if (TREE_CODE (val) == SSA_NAME)
+    {
+      if (ssa_undefined_value_p (val, false))
+       return true;
+
+      gimple *def = SSA_NAME_DEF_STMT (val);
+      if (gcall *call = dyn_cast<gcall *> (def))
+       if (tree fndecl = gimple_call_fndecl (call))
+         if (const function_instance *instance = lookup_fndecl (fndecl))
+           if (instance->base == functions::svundef)
+             return true;
+    }
+  return false;
+}
+
 /* Return the UNSPEC_CMLA* unspec for rotation amount ROT.  */
 static int
 unspec_cmla (int rot)
@@ -1142,6 +1162,13 @@ public:
   expand (function_expander &e) const override
   {
     machine_mode mode = e.vector_mode (0);
+
+    /* If the SVE argument is undefined, we just need to reinterpret the
+       Advanced SIMD argument as an SVE vector.  */
+    if (!BYTES_BIG_ENDIAN
+       && is_undef (CALL_EXPR_ARG (e.call_expr, 0)))
+      return simplify_gen_subreg (mode, e.args[1], GET_MODE (e.args[1]), 0);
+
     rtx_vector_builder builder (VNx16BImode, 16, 2);
     for (unsigned int i = 0; i < 16; i++)
       builder.quick_push (CONST1_RTX (BImode));
index 11f5c5c500c8331094933cb1c1205a1360eca79b..e124d1f90a586029502605e360a8bd1e6453ff81 100644 (file)
@@ -1055,6 +1055,22 @@ get_vector_type (sve_type type)
   return acle_vector_types[type.num_vectors - 1][vector_type];
 }
 
+/* If FNDECL is an SVE builtin, return its function instance, otherwise
+   return null.  */
+const function_instance *
+lookup_fndecl (tree fndecl)
+{
+  if (!fndecl_built_in_p (fndecl, BUILT_IN_MD))
+    return nullptr;
+
+  unsigned int code = DECL_MD_FUNCTION_CODE (fndecl);
+  if ((code & AARCH64_BUILTIN_CLASS) != AARCH64_BUILTIN_SVE)
+    return nullptr;
+
+  unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT;
+  return &(*registered_functions)[subcode]->instance;
+}
+
 /* Report an error against LOCATION that the user has tried to use
    function FNDECL when extension EXTENSION is disabled.  */
 static void
index e66729ed63532811b3b16ab57ae11cb10518caca..053006776a985d56e55834c839c6e78acff3f4cf 100644 (file)
@@ -810,6 +810,7 @@ extern tree acle_svprfop;
 
 bool vector_cst_all_same (tree, unsigned int);
 bool is_ptrue (tree, unsigned int);
+const function_instance *lookup_fndecl (tree);
 
 /* Try to find a mode with the given mode_suffix_info fields.  Return the
    mode on success or MODE_none on failure.  */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_1.c
new file mode 100644 (file)
index 0000000..2566c2d
--- /dev/null
@@ -0,0 +1,94 @@
+/* { dg-options "-O" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_neon_sve_bridge.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+svint32_t svundef_foo ();
+
+/*
+** f1:         { target aarch64_little_endian }
+**     ldr     q0, \[x0\]
+**     ret
+*/
+svint32_t
+f1 (int *a)
+{
+  return svset_neonq (svundef_s32 (), vld1q_s32 (a));
+}
+
+/*
+** f2:         { target aarch64_little_endian }
+**     ldr     q0, \[x0\]
+**     ret
+*/
+svint32_t
+f2 (int *a)
+{
+  svint32_t undef;
+  return svset_neonq (undef, vld1q_s32 (a));
+}
+
+/*
+** f3:         { target aarch64_little_endian }
+**     mov     [vz]0.[^\n]+, [vz]1.[^\n]+
+**     ret
+*/
+svint32_t
+f3 (int32x4_t v0, int32x4_t v1)
+{
+  return svset_neonq (svundef_s32 (), v1);
+}
+
+/*
+** f4:         { target aarch64_little_endian }
+**     uzp1    z([0-9]+)\.s, z0\.s, z1\.s
+**     ldr     q([0-9]+), \[x0\]
+**     ptrue   p([0-7])\.s, vl4
+**     sel     z0\.s, p\3, z\2\.s, z\1\.s
+**     ret
+*/
+svint32_t
+f4 (int *a, svint32_t x, svint32_t y)
+{
+  x = svuzp1 (x, y);
+  int32x4_t z = vld1q_s32 (a);
+  return svset_neonq (x, z);
+}
+
+/*
+** f5:
+**     ...
+**     bl      svundef_foo
+**     ...
+**     sel     z0\.s, [^\n]+
+**     ...
+**     ret
+*/
+svint32_t
+f5 (int *a)
+{
+  return svset_neonq (svundef_foo (), vld1q_s32 (a));
+}
+
+/*
+** f6:
+**     ...
+**     blr     x[0-9]+
+**     ...
+**     sel     z0\.s, [^\n]+
+**     ...
+**     ret
+*/
+svint32_t
+f6 (int *a, svint32_t (*svundef_s32) ())
+{
+  return svset_neonq (svundef_s32 (), vld1q_s32 (a));
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr114577_2.c
new file mode 100644 (file)
index 0000000..0775162
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-options "-O -msve-vector-bits=256" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_neon_sve_bridge.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** f1:         { target aarch64_little_endian }
+**     ldr     q0, \[x0\]
+**     ret
+*/
+svint32_t
+f1 (int *a)
+{
+  return svset_neonq (svundef_s32 (), vld1q_s32 (a));
+}
+
+/*
+** f2:         { target aarch64_little_endian }
+**     ldr     q0, \[x0\]
+**     ret
+*/
+svint32_t
+f2 (int *a)
+{
+  svint32_t undef;
+  return svset_neonq (undef, vld1q_s32 (a));
+}
+
+/*
+** f3:         { target aarch64_little_endian }
+**     mov     [vz]0.[^\n]+, [vz]1.[^\n]+
+**     ret
+*/
+svint32_t
+f3 (int32x4_t v0, int32x4_t v1)
+{
+  return svset_neonq (svundef_s32 (), v1);
+}
+
+#ifdef __cplusplus
+}
+#endif