Hi,
this patch fixed ICE that was introduced by Richard Standiford's change to 
reorder
can and want_inline predicates to reduce amount of work done to verify inlining 
limits.
This bypasses check that the function is optimized that makes inliner to ICE 
because
function summary is missing.

This patch breaks out the expensive limits checking from can predicate to new 
one
which makes code bit more convoluted but I hope to clean things up next stage1.

Bootstrapped/regtested x86_64-linux, will commit it later today.

Honza

        PR ipa/81360
        * ipa-inline.c (can_inline_edge_p): Break out late tests to...
        (can_inline_edge_by_limits_p): ... here.
        (can_early_inline_edge_p, check_callers,
        update_caller_keys, update_callee_keys, recursive_inlining,
        add_new_edges_to_heap, speculation_useful_p,
        inline_small_functions,
        inline_small_functions, flatten_function,
        inline_to_all_callers_1): Update.

        * g++.dg/torture/pr81360.C: New testcase
Index: ipa-inline.c
===================================================================
--- ipa-inline.c        (revision 257174)
+++ ipa-inline.c        (working copy)
@@ -289,18 +289,16 @@ sanitize_attrs_match_for_inline_p (const
       (opts_for_fn (caller->decl)->x_##flag            \
        != opts_for_fn (callee->decl)->x_##flag)
 
- /* Decide if we can inline the edge and possibly update
+/* Decide if we can inline the edge and possibly update
    inline_failed reason.  
    We check whether inlining is possible at all and whether
    caller growth limits allow doing so.  
 
-   if REPORT is true, output reason to the dump file.  
-
-   if DISREGARD_LIMITS is true, ignore size limits.*/
+   if REPORT is true, output reason to the dump file. */
 
 static bool
 can_inline_edge_p (struct cgraph_edge *e, bool report,
-                  bool disregard_limits = false, bool early = false)
+                  bool early = false)
 {
   gcc_checking_assert (e->inline_failed);
 
@@ -316,9 +314,6 @@ can_inline_edge_p (struct cgraph_edge *e
   cgraph_node *caller = e->caller->global.inlined_to
                        ? e->caller->global.inlined_to : e->caller;
   cgraph_node *callee = e->callee->ultimate_alias_target (&avail, caller);
-  tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl);
-  tree callee_tree
-    = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL;
 
   if (!callee->definition)
     {
@@ -379,12 +374,47 @@ can_inline_edge_p (struct cgraph_edge *e
       e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
       inlinable = false;
     }
+  if (!inlinable && report)
+    report_inline_failed_reason (e);
+  return inlinable;
+}
+
+/* Decide if we can inline the edge and possibly update
+   inline_failed reason.  
+   We check whether inlining is possible at all and whether
+   caller growth limits allow doing so.  
+
+   if REPORT is true, output reason to the dump file.
+
+   if DISREGARD_LIMITS is true, ignore size limits.  */
+
+static bool
+can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report,
+                            bool disregard_limits = false, bool early = false)
+{
+  gcc_checking_assert (e->inline_failed);
+
+  if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
+    {
+      if (report)
+        report_inline_failed_reason (e);
+      return false;
+    }
+
+  bool inlinable = true;
+  enum availability avail;
+  cgraph_node *caller = e->caller->global.inlined_to
+                       ? e->caller->global.inlined_to : e->caller;
+  cgraph_node *callee = e->callee->ultimate_alias_target (&avail, caller);
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl);
+  tree callee_tree
+    = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL;
   /* Check if caller growth allows the inlining.  */
-  else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
-          && !disregard_limits
-          && !lookup_attribute ("flatten",
-                                DECL_ATTRIBUTES (caller->decl))
-           && !caller_growth_limits (e))
+  if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
+      && !disregard_limits
+      && !lookup_attribute ("flatten",
+                DECL_ATTRIBUTES (caller->decl))
+      && !caller_growth_limits (e))
     inlinable = false;
   /* Don't inline a function with a higher optimization level than the
      caller.  FIXME: this is really just tip of iceberg of handling
@@ -541,7 +571,8 @@ can_early_inline_edge_p (struct cgraph_e
        fprintf (dump_file, "  edge not inlinable: not in SSA form\n");
       return false;
     }
-  if (!can_inline_edge_p (e, true, false, true))
+  if (!can_inline_edge_p (e, true, true)
+      || !can_inline_edge_by_limits_p (e, true, false, true))
     return false;
   return true;
 }
@@ -925,6 +956,8 @@ check_callers (struct cgraph_node *node,
          return true;
        if (e->recursive_p ())
         return true;
+       if (!can_inline_edge_by_limits_p (e, true))
+         return true;
        if (!(*(bool *)has_hot_call) && e->maybe_hot_p ())
         *(bool *)has_hot_call = true;
      }
@@ -1317,8 +1350,9 @@ update_caller_keys (edge_heap_t *heap, s
         if (!check_inlinablity_for
            || check_inlinablity_for == edge)
          {
-           if (want_inline_small_function_p (edge, false)
-               && can_inline_edge_p (edge, false))
+           if (can_inline_edge_p (edge, false)
+               && want_inline_small_function_p (edge, false)
+               && can_inline_edge_by_limits_p (edge, false))
              update_edge_key (heap, edge);
            else if (edge->aux)
              {
@@ -1361,8 +1395,9 @@ update_callee_keys (edge_heap_t *heap, s
            && avail >= AVAIL_AVAILABLE
            && !bitmap_bit_p (updated_nodes, callee->uid))
          {
-           if (want_inline_small_function_p (e, false)
-               && can_inline_edge_p (e, false))
+           if (can_inline_edge_p (e, false)
+               && want_inline_small_function_p (e, false)
+               && can_inline_edge_by_limits_p (e, false))
              update_edge_key (heap, e);
            else if (e->aux)
              {
@@ -1449,7 +1484,8 @@ recursive_inlining (struct cgraph_edge *
       struct cgraph_edge *curr = heap.extract_min ();
       struct cgraph_node *cnode, *dest = curr->callee;
 
-      if (!can_inline_edge_p (curr, true))
+      if (!can_inline_edge_p (curr, true)
+         || can_inline_edge_by_limits_p (curr, true))
        continue;
 
       /* MASTER_CLONE is produced in the case we already started modified
@@ -1569,7 +1605,8 @@ add_new_edges_to_heap (edge_heap_t *heap
       gcc_assert (!edge->aux);
       if (edge->inline_failed
          && can_inline_edge_p (edge, true)
-         && want_inline_small_function_p (edge, true))
+         && want_inline_small_function_p (edge, true)
+         && can_inline_edge_by_limits_p (edge, true))
         edge->aux = heap->insert (edge_badness (edge, false), edge);
     }
 }
@@ -1630,7 +1667,9 @@ speculation_useful_p (struct cgraph_edge
   if (!anticipate_inlining && e->inline_failed && !target->local.local)
     return false;
   /* For overwritable targets there is not much to do.  */
-  if (e->inline_failed && !can_inline_edge_p (e, false, true))
+  if (e->inline_failed
+      && (!can_inline_edge_p (e, false)
+         || !can_inline_edge_by_limits_p (e, false, true)))
     return false;
   /* OK, speculation seems interesting.  */
   return true;
@@ -1790,6 +1829,7 @@ inline_small_functions (void)
              && !edge->aux
              && can_inline_edge_p (edge, true)
              && want_inline_small_function_p (edge, true)
+             && can_inline_edge_by_limits_p (edge, true)
              && edge->inline_failed)
            {
              gcc_assert (!edge->aux);
@@ -1890,7 +1930,8 @@ inline_small_functions (void)
            badness = current_badness;
        }
 
-      if (!can_inline_edge_p (edge, true))
+      if (!can_inline_edge_p (edge, true)
+         || !can_inline_edge_by_limits_p (edge, true))
        {
          resolve_noninline_speculation (&edge_heap, edge);
          continue;
@@ -2101,6 +2142,7 @@ flatten_function (struct cgraph_node *no
         too.  */
       if (!early
          ? !can_inline_edge_p (e, true)
+           && !can_inline_edge_by_limits_p (e, true)
          : !can_early_inline_edge_p (e))
        continue;
 
@@ -2155,6 +2197,7 @@ inline_to_all_callers_1 (struct cgraph_n
       struct cgraph_node *caller = node->callers->caller;
 
       if (!can_inline_edge_p (node->callers, true)
+         || !can_inline_edge_by_limits_p (node->callers, true)
          || node->callers->recursive_p ())
        {
          if (dump_file)
Index: testsuite/g++.dg/torture/pr81360.C
===================================================================
--- testsuite/g++.dg/torture/pr81360.C  (revision 0)
+++ testsuite/g++.dg/torture/pr81360.C  (working copy)
@@ -0,0 +1,79 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-early-inlining"  } */
+
+template <int dim> class B;
+template <int, int dim> class TriaObjectAccessor;
+template <int, typename Accessor> class A;
+template <int dim> class TriaDimensionInfo {
+public:
+  typedef A<3, TriaObjectAccessor<2, 3> > raw_quad_iterator;
+  typedef A<3, B<3> > raw_hex_iterator;
+  typedef raw_hex_iterator raw_cell_iterator;
+};
+template <int dim> class Triangulation : public TriaDimensionInfo<1> {
+  public:
+  typedef typename TriaDimensionInfo<dim>::raw_quad_iterator raw_quad_iterator;
+  TriaDimensionInfo::raw_cell_iterator end() const;
+  raw_quad_iterator end_quad() const {
+    return raw_quad_iterator(const_cast<Triangulation *>(this), 0, 0);
+  }
+};
+template <int dim> class TriaAccessor {
+public:
+  typedef void AccessorData;
+  TriaAccessor(const Triangulation<dim> * = 0);
+  Triangulation<1> *tria;
+
+  int a, b, c;
+};
+template <int dim> class TriaObjectAccessor<2, dim> : public TriaAccessor<dim> 
{
+public:
+  typedef typename TriaAccessor<dim>::AccessorData AccessorData;
+  TriaObjectAccessor(const Triangulation<dim> * = 0);
+};
+template <int dim> class TriaObjectAccessor<3, dim> : public TriaAccessor<dim> 
{
+public:
+  typedef typename TriaAccessor<dim>::AccessorData AccessorData;
+  TriaObjectAccessor(const Triangulation<dim> * = 0);
+};
+template <int dim> class B : public TriaObjectAccessor<dim, dim> {
+public:
+  typedef typename TriaObjectAccessor<dim, dim>::AccessorData AccessorData;
+  B(const Triangulation<dim> * = 0);
+};
+template <int dim, typename Accessor> class A {
+public:
+  A(const A &);
+  A(const Triangulation<dim> *, int, int);
+  Accessor accessor;
+};
+template class Triangulation<3>;
+template <int dim, typename Accessor>
+A<dim, Accessor>::A(const Triangulation<dim> *, int, int) {}
+template <int dim>
+TriaAccessor<dim>::TriaAccessor(const Triangulation<dim> *)
+    : tria(), a(-1), b(-2), c(-3) {}
+template <int dim>
+TriaObjectAccessor<2, dim>::TriaObjectAccessor(const Triangulation<dim> *) {}
+template <int dim>
+TriaObjectAccessor<3, dim>::TriaObjectAccessor(const Triangulation<dim> *) {}
+template <int dim> B<dim>::B(const Triangulation<dim> *) {}
+template <>
+TriaDimensionInfo<3>::raw_cell_iterator Triangulation<3>::end() const {
+  return raw_hex_iterator(const_cast<Triangulation *>(this), 0, 0);
+}
+
+#pragma GCC optimize ("-O0")
+int main()
+{
+  Triangulation <3> t;
+  Triangulation<3>::raw_quad_iterator i1 = t.end_quad();
+  TriaDimensionInfo<3>::raw_cell_iterator i2 = t.end();
+
+  if(i2.accessor.c != -3)
+    return 1;
+
+  return 0;
+}
+
+/* { dg-final { scan-ipa-dump "Equal symbols: 0" "icf"  } } */

Reply via email to