Hi,
the testcase causes inline context cache to go out of sync because I
forgot to update used flags of parameters in one path of
update_indirect_edges_after_inlining.

While debugging it I also added better consistency check to
ipa-inline-analysis and turned ipa-inline test from ifdef to -fchecking.
This uncovered yet another missed upate in recursive inliner.

Bootstrapped/regtested x86_64-linux, comitted.

        PR c++/92421
        * ipa-prop.c (update_indirect_edges_after_inlining):
        Mark parameter as used.
        * ipa-inline.c (recursive_inlining): Reset node cache
        after inlining.
        (inline_small_functions): Remove checking ifdef.
        * ipa-inline-analysis.c (do_estimate_edge_time): Verify
        cache consistency.
        * g++.dg/torture/pr92421.C: New testcase.
Index: ipa-prop.c
===================================================================
--- ipa-prop.c  (revision 278151)
+++ ipa-prop.c  (working copy)
@@ -3537,6 +3537,11 @@ update_indirect_edges_after_inlining (st
              if (ici->polymorphic
                  && !ipa_get_jf_ancestor_type_preserved (jfunc))
                ici->vptr_changed = true;
+             ipa_set_param_used_by_indirect_call (new_root_info,
+                                                  ici->param_index, true);
+             if (ici->polymorphic)
+               ipa_set_param_used_by_polymorphic_call (new_root_info,
+                                                       ici->param_index, true);
            }
        }
       else
Index: ipa-inline.c
===================================================================
--- ipa-inline.c        (revision 278151)
+++ ipa-inline.c        (working copy)
@@ -1633,6 +1633,7 @@ recursive_inlining (struct cgraph_edge *
        }
 
       inline_call (curr, false, new_edges, &overall_size, true);
+      reset_node_cache (node);
       lookup_recursive_calls (node, curr->callee, &heap);
       n++;
     }
@@ -1982,11 +1983,10 @@ inline_small_functions (void)
       if (!edge->inline_failed || !edge->callee->analyzed)
        continue;
 
-#if CHECKING_P
       /* Be sure that caches are maintained consistent.
         This check is affected by scaling roundoff errors when compiling for
         IPA this we skip it in that case.  */
-      if (!edge->callee->count.ipa_p ()
+      if (flag_checking && !edge->callee->count.ipa_p ()
          && (!max_count.initialized_p () || !max_count.nonzero_p ()))
        {
          sreal cached_badness = edge_badness (edge, false);
@@ -1997,6 +1997,9 @@ inline_small_functions (void)
 
          if (edge_growth_cache != NULL)
            edge_growth_cache->remove (edge);
+         reset_node_cache (edge->caller->inlined_to
+                           ? edge->caller->inlined_to
+                           : edge->caller);
          gcc_assert (old_size_est == estimate_edge_size (edge));
          gcc_assert (old_time_est == estimate_edge_time (edge));
          /* FIXME:
@@ -2021,9 +2024,6 @@ inline_small_functions (void)
        }
       else
         current_badness = edge_badness (edge, false);
-#else
-      current_badness = edge_badness (edge, false);
-#endif
       if (current_badness != badness)
        {
          if (edge_heap.min () && current_badness > edge_heap.min_key ())
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c       (revision 278151)
+++ ipa-inline-analysis.c       (working copy)
@@ -210,6 +210,19 @@ do_estimate_edge_time (struct cgraph_edg
          time = e->entry.time;
          nonspec_time = e->entry.nonspec_time;
          hints = e->entry.hints;
+         if (flag_checking)
+           {
+             sreal chk_time, chk_nonspec_time;
+             int chk_size, chk_min_size;
+
+             ipa_hints chk_hints;
+             ctx.estimate_size_and_time (&chk_size, &chk_min_size,
+                                         &chk_time, &chk_nonspec_time,
+                                         &chk_hints);
+             gcc_assert (chk_size == size && chk_time == time
+                         && chk_nonspec_time == nonspec_time
+                         && chk_hints == hints);
+           }
        }
       else
        {
Index: testsuite/g++.dg/torture/pr92421.C
===================================================================
--- testsuite/g++.dg/torture/pr92421.C  (nonexistent)
+++ testsuite/g++.dg/torture/pr92421.C  (working copy)
@@ -0,0 +1,174 @@
+/* { dg-do compile } */
+typedef long a;
+void *b, *c;
+template <typename, typename> class d {};
+template <typename e, typename f> bool operator!=(d<e, f>, d<e, f>);
+class g {
+public:
+  g(char *);
+};
+class j {
+public:
+  j();
+  void h();
+  void i();
+  void aj();
+};
+class m {
+public:
+  m(bool);
+};
+class n {
+public:
+  operator a();
+};
+class o {
+public:
+  long am();
+};
+class H {
+public:
+  class p {};
+  virtual bool accept(const char *, unsigned long, p *, bool);
+};
+class q : H {
+public:
+  class r {
+  public:
+    enum at { au, av, aw };
+  };
+  enum { ax };
+  virtual void ay(char *, int, const char *, r::at, char *);
+  virtual bool az(const g &, unsigned = ax);
+  virtual bool ba(const int &, p *, bool);
+  void bb(char *bc, long bd, char *, long be) {
+    class bf : public p {
+    public:
+      bf(long);
+    } bg(be);
+    accept(bc, bd, &bg, true);
+  }
+};
+class s {
+  q *bi;
+  bool bj();
+};
+template <class bk> class t : q {
+  bool accept(const char *, unsigned long bd, p *bg, bool) {
+    bool k(bp || bq), cl = false, err = false;
+    if (br)
+      ay("", 1, __func__, r::au, "");
+    if (bs)
+      ay("", 6, __func__, r::av, "");
+    char bt[1], cd[1];
+    long bu = sizeof(int) + bd, ce = sizeof(L) + bd;
+    char *bw = bu > sizeof(bt) ? new char : bt,
+         *cf = ce > sizeof(cd) ? new char : cd;
+    __builtin___memcpy_chk(b, c, bd, 0);
+    a by[1];
+    int bz = 0;
+    u cb = *cc((int *)bw, true, by, &bz);
+    ay("", 1, __func__, r::aw, "");
+    if (bw != bt)
+      delete bw;
+    __builtin___memcpy_chk(b, c, bd, 0);
+    cb.ch.i();
+    bool ci = cj((L *)cf, bg);
+    bool atran = bq && bp && cb.ck;
+    if (atran && !ci && cm(&cb))
+      if (cn > co) {
+        int cp = cb.cq % 6;
+        v cs = *(ct + cp);
+        if (cu(&cs))
+          cl = true;
+      }
+    if (ci)
+      if (k)
+        cv.aj();
+    cv.h();
+    b = cc((int *)bw, false, by, &bz);
+    if (b)
+      if (cw(&cb, by, bz))
+        if (atran && bp && cx())
+          cv.aj();
+    if (cl)
+      if (k)
+        cv.aj();
+    cv.h();
+    int cp = cb.cq % 6;
+    v cs = *(ct + cp);
+    if (cy())
+      err = true;
+    O da = *(db + cp);
+    if (da.dc->am() > cs.dc->am() + cs.dd->am() + 1 && de(&da))
+      cv.aj();
+    return !err;
+  }
+  bool ba(const int &, p *, bool) {
+    d<int, int> kit, df;
+    while (kit != df)
+      ;
+    cx();
+  }
+  bool az(const g &, unsigned) {
+    t dj;
+    int cur;
+    while (cur) {
+      int dk, dl;
+      char dbuf;
+      dj.bb(&dbuf, dl, &dbuf, dk);
+    }
+  }
+  struct L {};
+  struct u {
+    j ch;
+    a cq;
+    bool ck;
+  };
+  struct v {
+    o *dd;
+    o *dc;
+  };
+  struct O {
+    o *dc;
+  };
+  bool cy();
+  bool cu(v *);
+  bool cj(L *, p *);
+  bool de(O *);
+  u *cc(int *, bool, a *, int *);
+  bool cw(u *, a *, int);
+  bool cx() {
+    dm.dn();
+    bool err = false;
+    if (dm.l())
+      err = true;
+    return !err;
+  }
+  bool cm(u *);
+  j cv;
+  int br;
+  bool bs;
+  bool bq;
+  bk dm;
+  a co;
+  n cn;
+  v ct[6];
+  O db[6];
+  bool bp;
+};
+class w : q {
+public:
+  void dn();
+  bool l() {
+    m(true);
+    if (br)
+      ay("", 1087, __func__, r::au, "");
+    return false;
+  }
+  int br;
+};
+bool s::bj() {
+  bi->az("");
+  new t<w>;
+}

Reply via email to