diff --git a/gcc/testsuite/gcc.dg/pr119183.c b/gcc/testsuite/gcc.dg/pr119183.c new file mode 100644 index 00000000000..a98d7790773 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr119183.c @@ -0,0 +1,12 @@ +/* PR c/119183 */ +/* { dg-do compile } */ + +int foo (void); +#define A(x) (1.0f * (1.0f * (1.0f * (1.0f * (1.0f * (1.0f * (1.0f * (1.0f * (x))))))))) + +float +bar (float r) +{ + r += A (A (A (A (A (A (A (A (foo ())))))))); + return r; +} diff --git a/gcc/tree.cc b/gcc/tree.cc index a35b4dbe655..eccfcc89da4 100644 --- a/gcc/tree.cc +++ b/gcc/tree.cc @@ -4105,7 +4105,19 @@ skip_simple_arithmetic (tree expr) expr = TREE_OPERAND (expr, 0); else if (BINARY_CLASS_P (expr)) { - if (tree_invariant_p (TREE_OPERAND (expr, 1))) + /* Before commutative binary operands are canonicalized, + it is quite common to have constants in the first operand. + Check for that common case first so that we don't walk + large expressions with tree_invariant_p unnecessarily. + This can still have terrible compile time complexity, + we should limit the depth of the tree_invariant_p and + skip_simple_arithmetic recursion. */ + if ((TREE_CONSTANT (TREE_OPERAND (expr, 0)) + || (TREE_READONLY (TREE_OPERAND (expr, 0)) + && !TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))) + && tree_invariant_p (TREE_OPERAND (expr, 0))) + expr = TREE_OPERAND (expr, 1); + else if (tree_invariant_p (TREE_OPERAND (expr, 1))) expr = TREE_OPERAND (expr, 0); else if (tree_invariant_p (TREE_OPERAND (expr, 0))) expr = TREE_OPERAND (expr, 1);