https://gcc.gnu.org/g:c6b38a75fc811f87b1beae1d95b86f613352e3da

commit r14-11466-gc6b38a75fc811f87b1beae1d95b86f613352e3da
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Tue Mar 11 11:01:55 2025 +0100

    tree: Improve skip_simple_arithmetic [PR119183]
    
    The following testcase takes very long time to compile, because
    skip_simple_arithmetic decides to first call tree_invariant_p on
    the second argument (and indirectly recurse there).  I think before
    canonicalization of operands for commutative binary expressions
    (and for non-commutative ones always) it is pretty common that the
    first operand is a constant, something which tree_invariant_p handles
    immediately, so the following patch special cases that; I've added
    there a tree_invariant_p call too after the checks, while it is not
    really needed currently, tree_invariant_p has the same checks, I wanted
    to be prepared in case tree_invariant_p changes.  But if you think
    I should avoid it, I can drop it too.
    
    This is just a partial fix, I think one can certainly construct a testcase
    which will still have horrible compile time complexity (but I've tried and
    haven't managed to do so), so perhaps we should just limit the recursion
    depth through skip_simple_arithmetic/tree_invariant_p with some defaulted
    argument.
    
    2025-03-11  Jakub Jelinek  <ja...@redhat.com>
    
            PR c/119183
            * tree.cc (skip_simple_arithmetic): If first operand of binary
            expr is TREE_CONSTANT or TREE_READONLY with no side-effects, call
            tree_invariant_p on that operand first instead of on the second.
    
            * gcc.dg/pr119183.c: New test.
    
    (cherry picked from commit 20e5aa9cc1519f871cce25dbfdc149d9d60da779)

Diff:
---
 gcc/testsuite/gcc.dg/pr119183.c | 12 ++++++++++++
 gcc/tree.cc                     | 14 +++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/gcc/testsuite/gcc.dg/pr119183.c b/gcc/testsuite/gcc.dg/pr119183.c
new file mode 100644
index 000000000000..a98d77907731
--- /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 6564b002dc1a..d716d7ccfe31 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -4006,7 +4006,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);

Reply via email to