The following testcase shows a problem in how we query valitity for equivalences on edges when the edge is a backedge and thus refering to a block thats later in the iteration order we use for VN. That causes the dominated_by_p_w_unex helper to look at edge executable state that's not yet computed and thus still at optimistic not executable state.
The following makes sure to use a plain dominance check in these cases. Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. PR tree-optimization/109342 * tree-ssa-sccvn.cc (vn_nary_op_get_predicated_value): New overload for edge. When that edge is a backedge use dominated_by_p directly. * g++.dg/torture/pr109342.C: New testcase. --- gcc/testsuite/g++.dg/torture/pr109342.C | 33 ++++++++++++++++++++++ gcc/tree-ssa-sccvn.cc | 37 ++++++++++++++++++------- 2 files changed, 60 insertions(+), 10 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/pr109342.C diff --git a/gcc/testsuite/g++.dg/torture/pr109342.C b/gcc/testsuite/g++.dg/torture/pr109342.C new file mode 100644 index 00000000000..2cdfa764faf --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/pr109342.C @@ -0,0 +1,33 @@ +// { dg-do run } + +unsigned long int var_4 = 42; +unsigned long int var_14 = 10; +unsigned char var_16 = 1; +unsigned short var_18 = 0; +short var_75; + +inline const int &foo(const int &b, const int &c) +{ + return b < c ? c : b; +} +inline unsigned long &bar(unsigned long &b, unsigned long &c) +{ + return !c ? c : b; +} + +void __attribute__((noipa)) +test(unsigned long var_4, unsigned long var_14, + unsigned char var_16, unsigned short var_18) +{ + for (bool h = 0; h < (bool)foo(var_16 ? -7 : 4, var_4 ? var_4 : var_18); + h = 2) + var_75 = bar(var_4, var_14); +} + +int main() +{ + test(var_4, var_14, var_16, var_18); + if (var_75 != 42) + __builtin_abort(); + return 0; +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 6b8d38b270c..99609538f54 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -4583,22 +4583,39 @@ static bool dominated_by_p_w_unex (basic_block bb1, basic_block bb2, bool); static tree -vn_nary_op_get_predicated_value (vn_nary_op_t vno, basic_block bb) +vn_nary_op_get_predicated_value (vn_nary_op_t vno, basic_block bb, + edge e = NULL) { if (! vno->predicated_values) return vno->u.result; for (vn_pval *val = vno->u.values; val; val = val->next) for (unsigned i = 0; i < val->n; ++i) - /* Do not handle backedge executability optimistically since - when figuring out whether to iterate we do not consider - changed predication. */ - if (dominated_by_p_w_unex - (bb, BASIC_BLOCK_FOR_FN (cfun, val->valid_dominated_by_p[i]), - false)) - return val->result; + { + basic_block cand + = BASIC_BLOCK_FOR_FN (cfun, val->valid_dominated_by_p[i]); + /* Do not handle backedge executability optimistically since + when figuring out whether to iterate we do not consider + changed predication. + When asking for predicated values on an edge avoid looking + at edge executability for edges forward in our iteration + as well. */ + if (e && (e->flags & EDGE_DFS_BACK)) + { + if (dominated_by_p (CDI_DOMINATORS, bb, cand)) + return val->result; + } + else if (dominated_by_p_w_unex (bb, cand, false)) + return val->result; + } return NULL_TREE; } +static tree +vn_nary_op_get_predicated_value (vn_nary_op_t vno, edge e) +{ + return vn_nary_op_get_predicated_value (vno, e->src, e); +} + /* Insert the rhs of STMT into the current hash table with a value number of RESULT. */ @@ -5928,7 +5945,7 @@ visit_phi (gimple *phi, bool *inserted, bool backedges_varying_p) ops, &vnresult); if (! val && vnresult && vnresult->predicated_values) { - val = vn_nary_op_get_predicated_value (vnresult, e->src); + val = vn_nary_op_get_predicated_value (vnresult, e); if (val && integer_truep (val) && !(sameval_e && (sameval_e->flags & EDGE_DFS_BACK))) { @@ -5947,7 +5964,7 @@ visit_phi (gimple *phi, bool *inserted, bool backedges_varying_p) we can change sameval to def. */ if (EDGE_COUNT (bb->preds) == 2 && (val = vn_nary_op_get_predicated_value - (vnresult, EDGE_PRED (bb, 0)->src)) + (vnresult, EDGE_PRED (bb, 0))) && integer_truep (val) && !(e->flags & EDGE_DFS_BACK)) { -- 2.35.3