https://gcc.gnu.org/g:34e1afc66c3239bf5d5dbe8005f8930d84fa20bf
commit r17-5395-g34e1afc66c3239bf5d5dbe8005f8930d84fa20bf Author: Richard Biener <[email protected]> Date: Tue Oct 20 09:48:15 2026 +0200 tree-optimization/128006 - only decrement constant integer pow exponents When undistributing a factor X out of a multiplication chain, zero_one_operation uses stmt_is_power_of_op to find a pow/powi call with base X and then removes one factor of X via decrement_power. stmt_is_power_of_op only checked the base, but decrement_power assumes a constant integer exponent. For (x * y) * __builtin_pow (x, 2.5) + z * x with -ffast-math the exponent 2.5 was truncated to 2 and decremented to 1, replacing pow (x, 2.5) with x and miscompiling the expression to x * (x * x * y + z). A non-constant exponent ICEd in decrement_power. Make stmt_is_power_of_op require a constant integer exponent so that the factor is removed from elsewhere in the chain instead. PR tree-optimization/128006 * tree-ssa-reassoc.cc (stmt_is_power_of_op): Require a constant integer exponent. * gcc.dg/tree-ssa/reassoc-52.c: New test. * gcc.dg/tree-ssa/reassoc-53.c: New test. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/reassoc-52.c | 19 +++++++++++++++++++ gcc/testsuite/gcc.dg/tree-ssa/reassoc-53.c | 27 +++++++++++++++++++++++++++ gcc/tree-ssa-reassoc.cc | 18 ++++++++++++++++-- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-52.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-52.c new file mode 100644 index 000000000000..d5b9b17a84e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-52.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -ffast-math" } */ + +/* Undistribution must not treat pow (x, 2.5) as x * pow (x, 1.5) + by truncating its exponent. */ + +__attribute__((noipa)) double +f (double x, double y, double z) +{ + return (x * y) * __builtin_pow (x, 2.5) + z * x; +} + +int +main (void) +{ + if (f (4.0, 1.0, 0.0) != 128.0) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/reassoc-53.c b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-53.c new file mode 100644 index 000000000000..818f8583521c --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/reassoc-53.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -ffast-math" } */ + +/* Undistribution must not try to decrement a non-constant exponent + of pow or powi. */ + +__attribute__((noipa)) double +f (double x, double y, double z, double n) +{ + return (x * y) * __builtin_pow (x, n) + z * x; +} + +__attribute__((noipa)) double +g (double x, double y, double z, int n) +{ + return (x * y) * __builtin_powi (x, n) + z * x; +} + +int +main (void) +{ + if (f (4.0, 1.0, 0.0, 3.0) != 256.0) + __builtin_abort (); + if (g (4.0, 1.0, 0.0, 3) != 256.0) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-ssa-reassoc.cc b/gcc/tree-ssa-reassoc.cc index 737d30ba0a4c..ca342ba3d8c8 100644 --- a/gcc/tree-ssa-reassoc.cc +++ b/gcc/tree-ssa-reassoc.cc @@ -1190,7 +1190,7 @@ oecount_cmp (const void *p1, const void *p2) } /* Return TRUE iff STMT represents a builtin call that raises OP - to some exponent. */ + to some constant integer exponent, as required by decrement_power. */ static bool stmt_is_power_of_op (gimple *stmt, tree op) @@ -1201,8 +1201,22 @@ stmt_is_power_of_op (gimple *stmt, tree op) switch (gimple_call_combined_fn (stmt)) { CASE_CFN_POW: + { + tree arg1 = gimple_call_arg (stmt, 1); + if (TREE_CODE (arg1) != REAL_CST) + return false; + REAL_VALUE_TYPE c = TREE_REAL_CST (arg1); + REAL_VALUE_TYPE cint; + real_from_integer (&cint, VOIDmode, real_to_integer (&c), SIGNED); + if (!real_identical (&c, &cint)) + return false; + return operand_equal_p (gimple_call_arg (stmt, 0), op, 0); + } + CASE_CFN_POWI: - return (operand_equal_p (gimple_call_arg (stmt, 0), op, 0)); + if (!tree_fits_shwi_p (gimple_call_arg (stmt, 1))) + return false; + return operand_equal_p (gimple_call_arg (stmt, 0), op, 0); default: return false;
