https://gcc.gnu.org/g:3182e95eda4a1d612b910b3248c997c8acc7add3

commit r16-3328-g3182e95eda4a1d612b910b3248c997c8acc7add3
Author: Richard Biener <rguent...@suse.de>
Date:   Thu Jan 23 14:29:26 2025 +0100

    tree-optimization/111494 - reduction vectorization with signed UB
    
    The following makes sure to pun arithmetic that's used in vectorized
    reduction to unsigned when overflow invokes undefined behavior.
    
            PR tree-optimization/111494
            * gimple-fold.h (arith_code_with_undefined_signed_overflow): 
Declare.
            * gimple-fold.cc (arith_code_with_undefined_signed_overflow): 
Export.
            * tree-vect-stmts.cc (vectorizable_operation): Use unsigned
            arithmetic for operations participating in a reduction.

Diff:
---
 gcc/gimple-fold.cc     |  2 +-
 gcc/gimple-fold.h      |  1 +
 gcc/tree-vect-stmts.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 85319b334928..03130ce84301 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -10484,7 +10484,7 @@ gimple_fold_indirect_ref (tree t)
    integer types involves undefined behavior on overflow and the
    operation can be expressed with unsigned arithmetic.  */
 
-static bool
+bool
 arith_code_with_undefined_signed_overflow (tree_code code)
 {
   switch (code)
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index b678502f2fca..3f617d1c4cd7 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -58,6 +58,7 @@ extern tree gimple_get_virt_method_for_vtable (HOST_WIDE_INT, 
tree,
 extern tree gimple_fold_indirect_ref (tree);
 extern bool gimple_fold_builtin_sprintf (gimple_stmt_iterator *);
 extern bool gimple_fold_builtin_snprintf (gimple_stmt_iterator *);
+extern bool arith_code_with_undefined_signed_overflow (tree_code);
 extern bool gimple_needing_rewrite_undefined (gimple *);
 extern void rewrite_to_defined_unconditional (gimple_stmt_iterator *);
 extern gimple_seq rewrite_to_defined_unconditional (gimple *);
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 3c0a40f940ab..47cd29fb1b89 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -6562,6 +6562,20 @@ vectorizable_operation (vec_info *vinfo,
       vec_dest = vect_create_destination_var (scalar_dest, vectype);
       vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
     }
+  /* For reduction operations with undefined overflow behavior make sure to
+     pun them to unsigned since we change the order of evaluation.
+     ???  Avoid for in-order reductions?  */
+  else if (arith_code_with_undefined_signed_overflow (orig_code)
+          && ANY_INTEGRAL_TYPE_P (vectype)
+          && TYPE_OVERFLOW_UNDEFINED (vectype)
+          && STMT_VINFO_REDUC_IDX (stmt_info) != -1)
+    {
+      gcc_assert (orig_code == PLUS_EXPR || orig_code == MINUS_EXPR
+                 || orig_code == MULT_EXPR || orig_code == POINTER_PLUS_EXPR);
+      vec_cvt_dest = vect_create_destination_var (scalar_dest, vectype_out);
+      vectype = unsigned_type_for (vectype);
+      vec_dest = vect_create_destination_var (scalar_dest, vectype);
+    }
   /* Handle def.  */
   else
     vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
@@ -6575,6 +6589,46 @@ vectorizable_operation (vec_info *vinfo,
       vop1 = ((op_type == binary_op || op_type == ternary_op)
              ? vec_oprnds1[i] : NULL_TREE);
       vop2 = ((op_type == ternary_op) ? vec_oprnds2[i] : NULL_TREE);
+
+      if (vec_cvt_dest
+         && !useless_type_conversion_p (vectype, TREE_TYPE (vop0)))
+       {
+         new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop0);
+         new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
+                                         new_temp);
+         new_temp = make_ssa_name (vec_dest, new_stmt);
+         gimple_assign_set_lhs (new_stmt, new_temp);
+         vect_finish_stmt_generation (vinfo, stmt_info,
+                                      new_stmt, gsi);
+         vop0 = new_temp;
+       }
+      if (vop1
+         && vec_cvt_dest
+         && !useless_type_conversion_p (vectype, TREE_TYPE (vop1)))
+       {
+         new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop1);
+         new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
+                                         new_temp);
+         new_temp = make_ssa_name (vec_dest, new_stmt);
+         gimple_assign_set_lhs (new_stmt, new_temp);
+         vect_finish_stmt_generation (vinfo, stmt_info,
+                                      new_stmt, gsi);
+         vop1 = new_temp;
+       }
+      if (vop2
+         && vec_cvt_dest
+         && !useless_type_conversion_p (vectype, TREE_TYPE (vop2)))
+       {
+         new_temp = build1 (VIEW_CONVERT_EXPR, vectype, vop2);
+         new_stmt = gimple_build_assign (vec_dest, VIEW_CONVERT_EXPR,
+                                         new_temp);
+         new_temp = make_ssa_name (vec_dest, new_stmt);
+         gimple_assign_set_lhs (new_stmt, new_temp);
+         vect_finish_stmt_generation (vinfo, stmt_info,
+                                      new_stmt, gsi);
+         vop2 = new_temp;
+       }
+
       if (using_emulated_vectors_p)
        {
          /* Lower the operation.  This follows vector lowering.  */

Reply via email to