Like the patch to phiopt (r15-4033-g1f619fe25925a5f7), this adds rewriting of VCE to gimple_with_undefined_signed_overflow/rewrite_to_defined_overflow. In the case of moving VCE of a bool from being conditional to unconditional, it needs to be rewritten to not to use VCE but a normal cast. pr120122-1.c is an example of where LIM needs this rewriting.
This also renames gimple_with_undefined_signed_overflow to gimple_needing_rewrite_undefined and rewrite_to_defined_overflow to rewrite_to_defined_unconditional as they will be doing more than just handling signed overflow. Bootstrappd and tested on x86_64-linux-gnu. PR tree-optimization/120122 PR tree-optimization/116939 gcc/ChangeLog: * gimple-fold.h (gimple_with_undefined_signed_overflow): Rename to .. (rewrite_to_defined_overflow): This. (gimple_needing_rewrite_undefined): Rename to ... (rewrite_to_defined_unconditional): this. * gimple-fold.cc (gimple_with_undefined_signed_overflow): Rename to ... (gimple_needing_rewrite_undefined): This. Return true for VCE with integral types. (rewrite_to_defined_overflow): Rename to ... (rewrite_to_defined_unconditional): This. Handle VCE rewriting to a cast. * tree-if-conv.cc: s/gimple_with_undefined_signed_overflow/gimple_needing_rewrite_undefined/ s/rewrite_to_defined_overflow/rewrite_to_defined_unconditional. * tree-scalar-evolution.cc: Likewise * tree-ssa-ifcombine.cc: Likewise. * tree-ssa-loop-im.cc: Likewise. * tree-ssa-loop-split.cc: Likewise. * tree-ssa-reassoc.cc: Likewise. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr120122-1.c: New test. Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com> --- gcc/gimple-fold.cc | 51 +++++++++++++++++------ gcc/gimple-fold.h | 6 +-- gcc/testsuite/gcc.dg/torture/pr120122-1.c | 51 +++++++++++++++++++++++ gcc/tree-if-conv.cc | 6 +-- gcc/tree-scalar-evolution.cc | 4 +- gcc/tree-ssa-ifcombine.cc | 4 +- gcc/tree-ssa-loop-im.cc | 4 +- gcc/tree-ssa-loop-split.cc | 4 +- gcc/tree-ssa-reassoc.cc | 4 +- 9 files changed, 106 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/torture/pr120122-1.c diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index c060ef81a42..4f45aeb7ff8 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -10588,10 +10588,12 @@ arith_code_with_undefined_signed_overflow (tree_code code) /* Return true if STMT has an operation that operates on a signed integer types involves undefined behavior on overflow and the - operation can be expressed with unsigned arithmetic. */ + operation can be expressed with unsigned arithmetic. + Also returns true if STMT is a VCE that needs to be rewritten + if moved to be executed unconditionally. */ bool -gimple_with_undefined_signed_overflow (gimple *stmt) +gimple_needing_rewrite_undefined (gimple *stmt) { if (!is_gimple_assign (stmt)) return false; @@ -10602,6 +10604,14 @@ gimple_with_undefined_signed_overflow (gimple *stmt) if (!INTEGRAL_TYPE_P (lhs_type) && !POINTER_TYPE_P (lhs_type)) return false; + tree rhs = gimple_assign_rhs1 (stmt); + /* VCE from integral types to another integral types but with + different precisions need to be changed into casts + to be well defined. */ + if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR + && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (rhs, 0))) + && is_gimple_val (TREE_OPERAND (rhs, 0))) + return true; if (!TYPE_OVERFLOW_UNDEFINED (lhs_type)) return false; if (!arith_code_with_undefined_signed_overflow @@ -10621,19 +10631,36 @@ gimple_with_undefined_signed_overflow (gimple *stmt) contain a modified form of STMT itself. */ static gimple_seq -rewrite_to_defined_overflow (gimple_stmt_iterator *gsi, gimple *stmt, - bool in_place) +rewrite_to_defined_unconditional (gimple_stmt_iterator *gsi, gimple *stmt, + bool in_place) { if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "rewriting stmt with undefined signed " - "overflow "); + fprintf (dump_file, "rewriting stmt for being uncondtional defined"); print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); } - + gimple_seq stmts = NULL; + /* VCE from integral types to another integral types but with + different precisions need to be changed into casts + to be well defined. */ + if (gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR) + { + tree rhs = gimple_assign_rhs1 (stmt); + tree new_rhs = TREE_OPERAND (rhs, 0); + gcc_assert (is_gimple_val (new_rhs)); + gimple_assign_set_rhs_code (stmt, NOP_EXPR); + gimple_assign_set_rhs1 (stmt, new_rhs); + if (in_place) + update_stmt (stmt); + else + { + gimple_set_modified (stmt, true); + gimple_seq_add_stmt (&stmts, stmt); + } + return stmts; + } tree lhs = gimple_assign_lhs (stmt); tree type = unsigned_type_for (TREE_TYPE (lhs)); - gimple_seq stmts = NULL; if (gimple_assign_rhs_code (stmt) == ABS_EXPR) gimple_assign_set_rhs_code (stmt, ABSU_EXPR); else @@ -10668,15 +10695,15 @@ rewrite_to_defined_overflow (gimple_stmt_iterator *gsi, gimple *stmt, } void -rewrite_to_defined_overflow (gimple_stmt_iterator *gsi) +rewrite_to_defined_unconditional (gimple_stmt_iterator *gsi) { - rewrite_to_defined_overflow (gsi, gsi_stmt (*gsi), true); + rewrite_to_defined_unconditional (gsi, gsi_stmt (*gsi), true); } gimple_seq -rewrite_to_defined_overflow (gimple *stmt) +rewrite_to_defined_unconditional (gimple *stmt) { - return rewrite_to_defined_overflow (nullptr, stmt, false); + return rewrite_to_defined_unconditional (nullptr, stmt, false); } /* The valueization hook we use for the gimple_build API simplification. diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h index 5fcfdcda81b..afecbb8ceef 100644 --- a/gcc/gimple-fold.h +++ b/gcc/gimple-fold.h @@ -59,9 +59,9 @@ 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 gimple_with_undefined_signed_overflow (gimple *); -extern void rewrite_to_defined_overflow (gimple_stmt_iterator *); -extern gimple_seq rewrite_to_defined_overflow (gimple *); +extern bool gimple_needing_rewrite_undefined (gimple *); +extern void rewrite_to_defined_unconditional (gimple_stmt_iterator *); +extern gimple_seq rewrite_to_defined_unconditional (gimple *); extern void replace_call_with_value (gimple_stmt_iterator *, tree); extern tree tree_vec_extract (gimple_stmt_iterator *, tree, tree, tree, tree); extern void gsi_replace_with_seq_vops (gimple_stmt_iterator *, gimple_seq); diff --git a/gcc/testsuite/gcc.dg/torture/pr120122-1.c b/gcc/testsuite/gcc.dg/torture/pr120122-1.c new file mode 100644 index 00000000000..dde41d8ec06 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr120122-1.c @@ -0,0 +1,51 @@ +/* { dg-do run } */ +/* PR tree-optimization/120122 */ + +#include <stdbool.h> + +struct Value { + int type; + union { + bool boolean; + long long t; + }; +}; + +static struct Value s_item_mem; + +/* truthy was being miscompiled for the value.type==2 case, + because we would have a VCE from unsigned char to bool + that went from being conditional in the value.type==1 case + to unconditional when `value.type!=0`. + The move of the VCE from conditional to unconditional, + needs to changed into a convert (NOP_EXPR). */ +static bool truthy(void) __attribute__((noipa)); +static bool +truthy(void) +{ + bool tt = false; + for(int i = 0; i < 10; i++) + { + struct Value value = s_item_mem; + if (value.type == 0) + tt = tt | 0; + else if (value.type == 1) + tt = tt | value.boolean; + else + tt = tt | 1; + } + return tt; +} + +int +main(void) +{ + s_item_mem.type = 2; + s_item_mem.t = -1; + bool b1 = !truthy(); + s_item_mem.type = 1; + s_item_mem.boolean = b1; + bool b = truthy(); + if (b1 != b) __builtin_abort(); + if (b) __builtin_abort(); +} diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc index fe8aee057b3..636361e7c36 100644 --- a/gcc/tree-if-conv.cc +++ b/gcc/tree-if-conv.cc @@ -1066,7 +1066,7 @@ if_convertible_gimple_assign_stmt_p (gimple *stmt, fprintf (dump_file, "tree could trap...\n"); return false; } - else if (gimple_with_undefined_signed_overflow (stmt)) + else if (gimple_needing_rewrite_undefined (stmt)) /* We have to rewrite stmts with undefined overflow. */ need_to_rewrite_undefined = true; @@ -2881,8 +2881,8 @@ predicate_statements (loop_p loop) gsi_replace (&gsi, new_stmt, true); } - else if (gimple_with_undefined_signed_overflow (stmt)) - rewrite_to_defined_overflow (&gsi); + else if (gimple_needing_rewrite_undefined (stmt)) + rewrite_to_defined_unconditional (&gsi); else if (gimple_vdef (stmt)) { tree lhs = gimple_assign_lhs (stmt); diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc index 9d64d3a8721..43311e52f94 100644 --- a/gcc/tree-scalar-evolution.cc +++ b/gcc/tree-scalar-evolution.cc @@ -3932,8 +3932,8 @@ final_value_replacement_loop (class loop *loop) gsi2 = gsi_start (stmts); while (!gsi_end_p (gsi2)) { - if (gimple_with_undefined_signed_overflow (gsi_stmt (gsi2))) - rewrite_to_defined_overflow (&gsi2); + if (gimple_needing_rewrite_undefined (gsi_stmt (gsi2))) + rewrite_to_defined_unconditional (&gsi2); gsi_next (&gsi2); } } diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index 19990d67202..1fff9234198 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -514,9 +514,9 @@ ifcombine_mark_ssa_name_walk (tree *t, int *, void *data_) static inline void ifcombine_rewrite_to_defined_overflow (gimple_stmt_iterator gsi) { - if (!gimple_with_undefined_signed_overflow (gsi_stmt (gsi))) + if (!gimple_needing_rewrite_undefined (gsi_stmt (gsi))) return; - rewrite_to_defined_overflow (&gsi); + rewrite_to_defined_unconditional (&gsi); } diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc index ae2fd87d589..50d2ee9b99d 100644 --- a/gcc/tree-ssa-loop-im.cc +++ b/gcc/tree-ssa-loop-im.cc @@ -1419,11 +1419,11 @@ move_computations_worker (basic_block bb) when the target loop header is executed and the stmt may invoke undefined integer or pointer overflow rewrite it to unsigned arithmetic. */ - if (gimple_with_undefined_signed_overflow (stmt) + if (gimple_needing_rewrite_undefined (stmt) && (!ALWAYS_EXECUTED_IN (bb) || !(ALWAYS_EXECUTED_IN (bb) == level || flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb), level)))) - gsi_insert_seq_on_edge (e, rewrite_to_defined_overflow (stmt)); + gsi_insert_seq_on_edge (e, rewrite_to_defined_unconditional (stmt)); else gsi_insert_on_edge (e, stmt); } diff --git a/gcc/tree-ssa-loop-split.cc b/gcc/tree-ssa-loop-split.cc index 80f488a4f9a..492abf849b8 100644 --- a/gcc/tree-ssa-loop-split.cc +++ b/gcc/tree-ssa-loop-split.cc @@ -663,8 +663,8 @@ split_loop (class loop *loop1) gsi = gsi_start (stmts2); while (!gsi_end_p (gsi)) { - if (gimple_with_undefined_signed_overflow (gsi_stmt (gsi))) - rewrite_to_defined_overflow (&gsi); + if (gimple_needing_rewrite_undefined (gsi_stmt (gsi))) + rewrite_to_defined_unconditional (&gsi); gsi_next (&gsi); } } diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc index 13bb85c4b71..3c38f3d7a19 100644 --- a/gcc/tree-ssa-reassoc.cc +++ b/gcc/tree-ssa-reassoc.cc @@ -2925,13 +2925,13 @@ update_range_test (struct range_entry *range, struct range_entry *otherrange, !gsi_end_p (gsi); gsi_next (&gsi)) { gimple *stmt = gsi_stmt (gsi); - if (gimple_with_undefined_signed_overflow (stmt)) + if (gimple_needing_rewrite_undefined (stmt)) { gimple_stmt_iterator gsip = gsi; gimple_stmt_iterator gsin = gsi; gsi_prev (&gsip); gsi_next (&gsin); - rewrite_to_defined_overflow (&gsi); + rewrite_to_defined_unconditional (&gsi); unsigned uid = gimple_uid (stmt); if (gsi_end_p (gsip)) gsip = gsi_after_labels (bb); -- 2.34.1