https://gcc.gnu.org/g:dbb05d561df3c1a70c23f47a4531abff456e4247

commit r17-5734-gdbb05d561df3c1a70c23f47a4531abff456e4247
Author: liuhongt <[email protected]>
Date:   Tue Oct 27 20:24:18 2026 -0700

    vect: Vectorize exact division by a power of two as a shift
    
    vect_recog_divmod_pattern expanded EXACT_DIV_EXPR by a power of two like
    TRUNC_DIV_EXPR, adding the divisor minus one to negative dividends
    before the arithmetic shift.  The pattern only handles positive
    divisors, and the dividend of an exact division is a multiple of the
    divisor, so the arithmetic shift alone gives the result, also for
    negative dividends: the rounding adjustment only matters when there is
    a remainder.  For pointer differences, which are exact divisions by the
    element size, this removes a compare, an and and an add per vector.
    
    gcc/ChangeLog:
    
            * tree-vect-patterns.cc (vect_recog_divmod_pattern): Use a plain
            arithmetic shift for EXACT_DIV_EXPR by a positive power of two.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/i386/vect-exact-div-pow2.c: New test.

Diff:
---
 gcc/testsuite/gcc.target/i386/vect-exact-div-pow2.c | 16 ++++++++++++++++
 gcc/tree-vect-patterns.cc                           | 14 +++++++++++++-
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.target/i386/vect-exact-div-pow2.c 
b/gcc/testsuite/gcc.target/i386/vect-exact-div-pow2.c
new file mode 100644
index 000000000000..374ad2eb81a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/vect-exact-div-pow2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -mavx2 -mno-avx512f -fdump-tree-vect-details" } */
+
+/* An exact division by a power of two, such as a pointer difference, is
+   vectorized as an arithmetic shift without the rounding adjustment of
+   negative dividends needed for truncating division.  */
+
+void
+f (long *__restrict out, int **__restrict p, int **__restrict q)
+{
+  for (int i = 0; i < 1024; i++)
+    out[i] = p[i] - q[i];
+}
+
+/* { dg-final { scan-tree-dump "divmod pattern recognized" "vect" } } */
+/* { dg-final { scan-assembler-not "vpcmp" } } */
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 49c85c703033..79e984af0244 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -5420,6 +5420,19 @@ vect_recog_divmod_pattern (vec_info *vinfo,
 
       *type_out = vectype;
 
+      /* OPRND1 is a positive power of two here and the dividend of an
+        exact division is a multiple of it, so the right shift is exact
+        also for negative dividends and needs no rounding fixup.  */
+      if (rhs_code == EXACT_DIV_EXPR)
+       {
+         tree shift = build_int_cst (itype, tree_log2 (oprnd1));
+         pattern_stmt
+           = gimple_build_assign (vect_recog_temp_ssa_var (itype, NULL),
+                                  RSHIFT_EXPR, oprnd0, shift);
+         gimple_set_location (pattern_stmt, gimple_location (last_stmt));
+         return pattern_stmt;
+       }
+
       /* Check if the target supports this internal function.  */
       internal_fn ifn = IFN_DIV_POW2;
       if (!TYPE_UNSIGNED (itype)
@@ -5465,7 +5478,6 @@ vect_recog_divmod_pattern (vec_info *vinfo,
                              truth_type_for (vectype), itype);
       tree div_result = NULL_TREE;
       if (rhs_code == TRUNC_DIV_EXPR
-         || rhs_code == EXACT_DIV_EXPR
          || rhs_code == FLOOR_DIV_EXPR
          || rhs_code == CEIL_DIV_EXPR
          || rhs_code == ROUND_DIV_EXPR)

Reply via email to