https://gcc.gnu.org/g:92044aadb3037c59ea124c0b23f8437c9e48b2fd
commit r16-6882-g92044aadb3037c59ea124c0b23f8437c9e48b2fd Author: Andrew Pinski <[email protected]> Date: Sat Jan 17 12:55:04 2026 -0800 phiopt: Rewrite cond_removal_in_builtin_zero_pattern canonicalization args code [PR123645] The canonicalization of args code was originally thinking edges e1/e2 were edges out going from the cond block but they were the edges coming into the join block. This rewrites the canonicalization of arg0/1 args to correct that mistake. And it fixes the wrong code that would happen in this case. PR tree-optimization/123645 gcc/ChangeLog: * tree-ssa-phiopt.cc (cond_removal_in_builtin_zero_pattern): Rewrite the canonicalization of the args code based on e1/e2 being edges into the join block. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr123645-1.c: New test. * gcc.dg/torture/pr123645-2.c: New test. Signed-off-by: Andrew Pinski <[email protected]> Diff: --- gcc/testsuite/gcc.dg/torture/pr123645-1.c | 24 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/torture/pr123645-2.c | 24 +++++++++++++++++++++++ gcc/tree-ssa-phiopt.cc | 32 +++++++++++++++++++++++++------ 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/gcc/testsuite/gcc.dg/torture/pr123645-1.c b/gcc/testsuite/gcc.dg/torture/pr123645-1.c new file mode 100644 index 000000000000..c183cd31d41e --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr123645-1.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ + +/* PR tree-optimization/123645 */ +/* Phi-opt was transforming f into __builtin_popcount which was incorrect. */ + +__attribute__((noinline)) +int f(unsigned a) +{ + return a < 1 ? __builtin_popcount(a) : 0; +} + +int main() +{ + if (f(1) != 0) + __builtin_abort(); + if (f(0) != 0) + __builtin_abort(); + if (f(2) != 0) + __builtin_abort(); + if (f(3) != 0) + __builtin_abort(); + if (f(-1) != 0) + __builtin_abort(); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr123645-2.c b/gcc/testsuite/gcc.dg/torture/pr123645-2.c new file mode 100644 index 000000000000..8c488acfbeca --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr123645-2.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ + +/* PR tree-optimization/123645 */ +/* Phi-opt was transforming f into __builtin_bswap which was incorrect. */ + +__attribute__((noinline)) +int f(unsigned a) +{ + return a < 1 ? __builtin_bswap32(a) : 0; +} + +int main() +{ + if (f(1) != 0) + __builtin_abort(); + if (f(0) != 0) + __builtin_abort(); + if (f(2) != 0) + __builtin_abort(); + if (f(3) != 0) + __builtin_abort(); + if (f(-1) != 0) + __builtin_abort(); +} diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc index 9ce240673771..167b86b3accb 100644 --- a/gcc/tree-ssa-phiopt.cc +++ b/gcc/tree-ssa-phiopt.cc @@ -2627,16 +2627,36 @@ cond_removal_in_builtin_zero_pattern (basic_block cond_bb, || arg != gimple_cond_lhs (cond)) return false; - /* Canonicalize. */ - if ((e2->flags & EDGE_TRUE_VALUE - && gimple_cond_code (cond) == NE_EXPR) - || (e1->flags & EDGE_TRUE_VALUE - && gimple_cond_code (cond) == EQ_EXPR)) + edge true_edge, false_edge; + /* We need to know which is the true edge and which is the false + edge so that we know when to invert the condition below. */ + extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); + + /* Forward the edges over the middle basic block. */ + if (true_edge->dest == middle_bb) + true_edge = EDGE_SUCC (true_edge->dest, 0); + if (false_edge->dest == middle_bb) + false_edge = EDGE_SUCC (false_edge->dest, 0); + + /* Canonicalize the args with respect to the edges, + arg0 is from the true edge and arg1 is from the + false edge. + That is `cond ? arg0 : arg1`.*/ + if (true_edge == e1) + gcc_assert (false_edge == e2); + else { + gcc_assert (false_edge == e1); + gcc_assert (true_edge == e2); std::swap (arg0, arg1); - std::swap (e1, e2); } + /* Canonicalize the args such that we get: + `arg != 0 ? arg0 : arg1`. So swap arg0/arg1 + around if cond was an equals. */ + if (gimple_cond_code (cond) == EQ_EXPR) + std::swap (arg0, arg1); + /* Check PHI arguments. */ if (lhs != arg0 || TREE_CODE (arg1) != INTEGER_CST)
