https://gcc.gnu.org/g:80bef0cb12be0c93b54af2c084b6e728626377ff

commit r17-5245-g80bef0cb12be0c93b54af2c084b6e728626377ff
Author: Soumya AR <[email protected]>
Date:   Wed Sep 23 12:30:18 2026 +0000

    aarch64: Use SVE ASRD with vector division using division operator
    
    The SVE ASRD instruction performs signed division by a power of two (an
    arithmetic shift right that rounds towards zero).  The vectorizer already 
uses
    it for such divisions through the sdiv_pow2 optab. This patch additionally
    enables ASRD when dividing vectors using the GNU C division operator.
    
    For example:
    
    int32x4_t
    foo (int32x4_t x)
    {
      return x / 4;
    }
    
    and
    
    svint32_t
    bar (svint32_t x)
    {
      return x / 4;
    }
    
    currently generate an SVE SDIV, but can be done using a single ASRD.
    
    This patch extends aarch64_instruction_selection to rewrite a signed vector
    TRUNC_DIV_EXPR by a positive power-of-two constant into a call to .DIV_POW2,
    which then expands through the sdiv_pow2 optab.
    
    Bootstrapped and regtested on aarch64-linux-gnu, no regressions. OK for 
trunk?
    
    Signed-off-by: Soumya AR <[email protected]>
    
    gcc/ChangeLog:
    
            * config/aarch64/aarch64.cc: Include internal-fn.h.
            (aarch64_try_sdiv_pow2): New function.
            (aarch64_instruction_selection): Call it for TRUNC_DIV_EXPR.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/sve/sve-asrd-2.c: New test.

Diff:
---
 gcc/config/aarch64/aarch64.cc                     | 39 +++++++++++++
 gcc/testsuite/gcc.target/aarch64/sve/sve-asrd-2.c | 70 +++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 5f0556fd5169..5d58491434f6 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -32,6 +32,7 @@
 #include "tree.h"
 #include "memmodel.h"
 #include "gimple.h"
+#include "internal-fn.h"
 #include "cfghooks.h"
 #include "cfgloop.h"
 #include "df.h"
@@ -2332,6 +2333,40 @@ aarch64_try_widen_mult_by_pow2 (const gassign *convert,
   return true;
 }
 
+/* Try to use the sdiv_pow2 optab for signed vector division by a constant
+   power of two.  */
+static bool
+aarch64_try_sdiv_pow2 (const gassign *assign, gimple_stmt_iterator *gsi)
+{
+  tree lhs = gimple_assign_lhs (assign);
+  tree type = TREE_TYPE (lhs);
+
+  if (!VECTOR_INTEGER_TYPE_P (type)
+      || TYPE_UNSIGNED (type)
+      || !direct_internal_fn_supported_p (IFN_DIV_POW2, type,
+                                          OPTIMIZE_FOR_BOTH))
+    return false;
+
+  tree dividend = gimple_assign_rhs1 (assign);
+  tree divisor = uniform_integer_cst_p (gimple_assign_rhs2 (assign));
+
+  /* Check that the divisor is a constant positive power of two.  */
+  if (!divisor
+      || tree_int_cst_sgn (divisor) != 1
+      || !integer_pow2p (divisor))
+    return false;
+
+  tree shift = build_int_cst (TREE_TYPE (type), tree_log2 (divisor));
+  shift = build_vector_from_val (type, shift);
+
+  gcall *call = gimple_build_call_internal (IFN_DIV_POW2, 2,
+                                            dividend, shift);
+  gimple_call_set_lhs (call, lhs);
+  gimple_set_location (call, gimple_location (assign));
+  gsi_replace (gsi, call, false);
+  return true;
+}
+
 /* Implement TARGET_MAX_NOCE_IFCVT_SEQ_COST.  If an explicit max was set then
    honor it, otherwise apply a tuning specific scale to branch costs.  */
 
@@ -4552,6 +4587,10 @@ aarch64_instruction_selection (function *fun, 
gimple_stmt_iterator *gsi)
   if (!assign)
     return false;
 
+  if (gimple_assign_rhs_code (assign) == TRUNC_DIV_EXPR
+      && aarch64_try_sdiv_pow2 (assign, gsi))
+    return true;
+
   if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (assign))
       && aarch64_try_widen_mult_by_pow2 (assign, gsi))
     return true;
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/sve-asrd-2.c 
b/gcc/testsuite/gcc.target/aarch64/sve/sve-asrd-2.c
new file mode 100644
index 000000000000..d4e29ab186ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/sve-asrd-2.c
@@ -0,0 +1,70 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fdump-tree-isel" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+/* { dg-final { scan-tree-dump-times {\.DIV_POW2} 4 "isel" } } */
+
+#include <arm_sve.h>
+
+#define FOO(TYPE) \
+TYPE foo_##TYPE (TYPE x) \
+{ \
+  return x / 8; \
+}
+
+/*
+** foo_int32x4_t:
+**     ptrue   (p[0-7]).b, vl16
+**     asrd    z[0-9]+\.s, \1/m, z[0-9]+\.s, #3
+**     ret
+*/
+FOO (int32x4_t)
+
+/*
+** foo_int64x2_t:
+**     ptrue   (p[0-7]).b, vl16
+**     asrd    z[0-9]+\.d, \1/m, z[0-9]+\.d, #3
+**     ret
+*/
+FOO (int64x2_t)
+
+/*
+** foo_svint32_t:
+**     ptrue   (p[0-7]).b, all
+**     asrd    z[0-9]+\.s, \1/m, z[0-9]+\.s, #3
+**     ret
+*/
+FOO (svint32_t)
+
+/*
+** foo_svint64_t:
+**     ptrue   (p[0-7]).b, all
+**     asrd    z[0-9]+\.d, \1/m, z[0-9]+\.d, #3
+**     ret
+*/
+FOO (svint64_t)
+
+/*
+** foo_nonpow2:
+**     mov     (z[0-9]+\.s), #7
+**     ptrue   (p[0-7]).b, all
+**     sdiv    (z[0-9]+\.s), \2/m, \3, \1
+**     ret
+*/
+svint32_t
+foo_nonpow2 (svint32_t x)
+{
+  return x / 7;
+}
+
+/*
+** foo_unsigned:
+**     mov     (z[0-9]+\.s), #8
+**     ptrue   (p[0-7]).b, all
+**     udiv    (z[0-9]+\.s), \2/m, \3, \1
+**     ret
+*/
+svuint32_t
+foo_unsigned (svuint32_t x)
+{
+  return x / 8;
+}

Reply via email to