Hi,
this is variant of patch I am testing (thanks Jakub for the hard analysis).
The dataflow was supposed to be monotonous by keeping the rule that oldvalue
imply new value at each step.  This is broken by the approximation done by
and/or operations.

Instead of dropping to true, it seems easier to simply or the result before
updating.  This operation should be no-op until we hit the clause limit.

Bootstrapping/regtesting x86_64-linux, will commit if it passes.

Honza

        * ipa-inline-analysis.c (compute_bb_predicates): Ensure monotonicity
        of the dataflow.

        gcc.dg/pr60013.c: New testcase.
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c       (revision 207514)
+++ ipa-inline-analysis.c       (working copy)
@@ -310,7 +310,7 @@ add_clause (conditions conditions, struc
   if (false_predicate_p (p))
     return;
 
-  /* No one should be sily enough to add false into nontrivial clauses.  */
+  /* No one should be silly enough to add false into nontrivial clauses.  */
   gcc_checking_assert (!(clause & (1 << predicate_false_condition)));
 
   /* Look where to insert the clause.  At the same time prune out
@@ -1035,7 +1035,7 @@ inline_node_removal_hook (struct cgraph_
   memset (info, 0, sizeof (inline_summary_t));
 }
 
-/* Remap predicate P of former function to be predicate of duplicated functoin.
+/* Remap predicate P of former function to be predicate of duplicated function.
    POSSIBLE_TRUTHS is clause of possible truths in the duplicated node,
    INFO is inline summary of the duplicated node.  */
 
@@ -1887,8 +1887,15 @@ compute_bb_predicates (struct cgraph_nod
                }
              else if (!predicates_equal_p (&p, (struct predicate *) bb->aux))
                {
-                 done = false;
-                 *((struct predicate *) bb->aux) = p;
+                 /* This OR operation is needed to ensure monotonous data flow
+                    in the case we hit the limit on number of clauses and the
+                    and/or operations above give approximate answers.  */
+                 p = or_predicates (summary->conds, &p, (struct predicate 
*)bb->aux);
+                 if (!predicates_equal_p (&p, (struct predicate *) bb->aux))
+                   {
+                     done = false;
+                     *((struct predicate *) bb->aux) = p;
+                   }
                }
            }
        }
Index: testsuite/gcc.dg/pr60013.c
===================================================================
--- testsuite/gcc.dg/pr60013.c  (revision 0)
+++ testsuite/gcc.dg/pr60013.c  (revision 0)
@@ -0,0 +1,47 @@
+/* PR ipa/60013 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef long int jmp_buf[64];
+extern int _setjmp (jmp_buf) __attribute__ ((__nothrow__));
+struct S { int a, b, c; };
+extern struct S *baz (struct S *);
+static jmp_buf j;
+
+static inline int
+bar (int b, int d)
+{
+  return (b & d) < 0;
+}
+
+struct S *
+foo (int a, struct S *b, struct S *c, struct S *d)
+{
+  if (b->a == 0)
+    {
+      switch (a)
+       {
+       case 8:
+         return baz (b);
+       case 7:
+         bar (b->c, c->b);
+         return 0;
+       case 6:
+       case 5:
+       case 4:
+         return baz (c);
+       case 3:
+       case 2:
+         return baz (d);
+       }
+      return 0;
+    }
+  if (b->a == 1)
+    {
+      if (baz (c))
+       return c;
+      else if (_setjmp (j))
+       baz (b);
+    }
+  return 0;
+}

Reply via email to