diff options
author | Richard Biener <rguenther@suse.de> | 2025-01-23 14:29:26 +0100 |
---|---|---|
committer | Richard Biener <rguenth@gcc.gnu.org> | 2025-08-21 13:53:02 +0200 |
commit | 3182e95eda4a1d612b910b3248c997c8acc7add3 (patch) | |
tree | 0c765a1cd2b00f4fcc6908bda478811c139c0c52 | |
parent | 7dfb3a59fea4a9f423d62d8c604b6bd87cea6095 (diff) | |
download | gcc-3182e95eda4a1d612b910b3248c997c8acc7add3.zip gcc-3182e95eda4a1d612b910b3248c997c8acc7add3.tar.gz gcc-3182e95eda4a1d612b910b3248c997c8acc7add3.tar.bz2 |
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.
-rw-r--r-- | gcc/gimple-fold.cc | 2 | ||||
-rw-r--r-- | gcc/gimple-fold.h | 1 | ||||
-rw-r--r-- | gcc/tree-vect-stmts.cc | 54 |
3 files changed, 56 insertions, 1 deletions
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 85319b3..03130ce 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 b678502..3f617d1 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 3c0a40f..47cd29f 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. */ |