Commit 9a4841a3 by Jan Hubicka Committed by Jan Hubicka

re PR ipa/81360 (ice in estimate_edge_growth, at ipa-inline.h:86)


	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

From-SVN: r257184
parent 44c945e6
2018-01-30 Jan Hubicka <hubicka@ucw.cz> 2018-01-30 Jan Hubicka <hubicka@ucw.cz>
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.
2018-01-30 Jan Hubicka <hubicka@ucw.cz>
* profile-count.c (profile_count::combine_with_ipa_count): Handle * profile-count.c (profile_count::combine_with_ipa_count): Handle
zeros correctly. zeros correctly.
......
...@@ -289,18 +289,16 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee) ...@@ -289,18 +289,16 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee)
(opts_for_fn (caller->decl)->x_##flag \ (opts_for_fn (caller->decl)->x_##flag \
!= opts_for_fn (callee->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. inline_failed reason.
We check whether inlining is possible at all and whether We check whether inlining is possible at all and whether
caller growth limits allow doing so. caller growth limits allow doing so.
if REPORT is true, output reason to the dump file. if REPORT is true, output reason to the dump file. */
if DISREGARD_LIMITS is true, ignore size limits.*/
static bool static bool
can_inline_edge_p (struct cgraph_edge *e, bool report, 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); gcc_checking_assert (e->inline_failed);
...@@ -316,9 +314,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -316,9 +314,6 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
cgraph_node *caller = e->caller->global.inlined_to cgraph_node *caller = e->caller->global.inlined_to
? e->caller->global.inlined_to : e->caller; ? e->caller->global.inlined_to : e->caller;
cgraph_node *callee = e->callee->ultimate_alias_target (&avail, 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) if (!callee->definition)
{ {
...@@ -379,12 +374,47 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, ...@@ -379,12 +374,47 @@ can_inline_edge_p (struct cgraph_edge *e, bool report,
e->inline_failed = CIF_ATTRIBUTE_MISMATCH; e->inline_failed = CIF_ATTRIBUTE_MISMATCH;
inlinable = false; 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. */ /* Check if caller growth allows the inlining. */
else if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl) if (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
&& !disregard_limits && !disregard_limits
&& !lookup_attribute ("flatten", && !lookup_attribute ("flatten",
DECL_ATTRIBUTES (caller->decl)) DECL_ATTRIBUTES (caller->decl))
&& !caller_growth_limits (e)) && !caller_growth_limits (e))
inlinable = false; inlinable = false;
/* Don't inline a function with a higher optimization level than the /* Don't inline a function with a higher optimization level than the
caller. FIXME: this is really just tip of iceberg of handling caller. FIXME: this is really just tip of iceberg of handling
...@@ -541,7 +571,8 @@ can_early_inline_edge_p (struct cgraph_edge *e) ...@@ -541,7 +571,8 @@ can_early_inline_edge_p (struct cgraph_edge *e)
fprintf (dump_file, " edge not inlinable: not in SSA form\n"); fprintf (dump_file, " edge not inlinable: not in SSA form\n");
return false; 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 false;
return true; return true;
} }
...@@ -925,6 +956,8 @@ check_callers (struct cgraph_node *node, void *has_hot_call) ...@@ -925,6 +956,8 @@ check_callers (struct cgraph_node *node, void *has_hot_call)
return true; return true;
if (e->recursive_p ()) if (e->recursive_p ())
return true; return true;
if (!can_inline_edge_by_limits_p (e, true))
return true;
if (!(*(bool *)has_hot_call) && e->maybe_hot_p ()) if (!(*(bool *)has_hot_call) && e->maybe_hot_p ())
*(bool *)has_hot_call = true; *(bool *)has_hot_call = true;
} }
...@@ -1317,8 +1350,9 @@ update_caller_keys (edge_heap_t *heap, struct cgraph_node *node, ...@@ -1317,8 +1350,9 @@ update_caller_keys (edge_heap_t *heap, struct cgraph_node *node,
if (!check_inlinablity_for if (!check_inlinablity_for
|| check_inlinablity_for == edge) || check_inlinablity_for == edge)
{ {
if (want_inline_small_function_p (edge, false) if (can_inline_edge_p (edge, false)
&& 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); update_edge_key (heap, edge);
else if (edge->aux) else if (edge->aux)
{ {
...@@ -1361,8 +1395,9 @@ update_callee_keys (edge_heap_t *heap, struct cgraph_node *node, ...@@ -1361,8 +1395,9 @@ update_callee_keys (edge_heap_t *heap, struct cgraph_node *node,
&& avail >= AVAIL_AVAILABLE && avail >= AVAIL_AVAILABLE
&& !bitmap_bit_p (updated_nodes, callee->uid)) && !bitmap_bit_p (updated_nodes, callee->uid))
{ {
if (want_inline_small_function_p (e, false) if (can_inline_edge_p (e, false)
&& 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); update_edge_key (heap, e);
else if (e->aux) else if (e->aux)
{ {
...@@ -1449,7 +1484,8 @@ recursive_inlining (struct cgraph_edge *edge, ...@@ -1449,7 +1484,8 @@ recursive_inlining (struct cgraph_edge *edge,
struct cgraph_edge *curr = heap.extract_min (); struct cgraph_edge *curr = heap.extract_min ();
struct cgraph_node *cnode, *dest = curr->callee; 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; continue;
/* MASTER_CLONE is produced in the case we already started modified /* MASTER_CLONE is produced in the case we already started modified
...@@ -1569,7 +1605,8 @@ add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges) ...@@ -1569,7 +1605,8 @@ add_new_edges_to_heap (edge_heap_t *heap, vec<cgraph_edge *> new_edges)
gcc_assert (!edge->aux); gcc_assert (!edge->aux);
if (edge->inline_failed if (edge->inline_failed
&& can_inline_edge_p (edge, true) && 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); edge->aux = heap->insert (edge_badness (edge, false), edge);
} }
} }
...@@ -1630,7 +1667,9 @@ speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining) ...@@ -1630,7 +1667,9 @@ speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining)
if (!anticipate_inlining && e->inline_failed && !target->local.local) if (!anticipate_inlining && e->inline_failed && !target->local.local)
return false; return false;
/* For overwritable targets there is not much to do. */ /* 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; return false;
/* OK, speculation seems interesting. */ /* OK, speculation seems interesting. */
return true; return true;
...@@ -1790,6 +1829,7 @@ inline_small_functions (void) ...@@ -1790,6 +1829,7 @@ inline_small_functions (void)
&& !edge->aux && !edge->aux
&& can_inline_edge_p (edge, true) && 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->inline_failed) && edge->inline_failed)
{ {
gcc_assert (!edge->aux); gcc_assert (!edge->aux);
...@@ -1890,7 +1930,8 @@ inline_small_functions (void) ...@@ -1890,7 +1930,8 @@ inline_small_functions (void)
badness = current_badness; 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); resolve_noninline_speculation (&edge_heap, edge);
continue; continue;
...@@ -2101,6 +2142,7 @@ flatten_function (struct cgraph_node *node, bool early) ...@@ -2101,6 +2142,7 @@ flatten_function (struct cgraph_node *node, bool early)
too. */ too. */
if (!early if (!early
? !can_inline_edge_p (e, true) ? !can_inline_edge_p (e, true)
&& !can_inline_edge_by_limits_p (e, true)
: !can_early_inline_edge_p (e)) : !can_early_inline_edge_p (e))
continue; continue;
...@@ -2155,6 +2197,7 @@ inline_to_all_callers_1 (struct cgraph_node *node, void *data, ...@@ -2155,6 +2197,7 @@ inline_to_all_callers_1 (struct cgraph_node *node, void *data,
struct cgraph_node *caller = node->callers->caller; struct cgraph_node *caller = node->callers->caller;
if (!can_inline_edge_p (node->callers, true) if (!can_inline_edge_p (node->callers, true)
|| !can_inline_edge_by_limits_p (node->callers, true)
|| node->callers->recursive_p ()) || node->callers->recursive_p ())
{ {
if (dump_file) if (dump_file)
......
2018-01-30 Jan Hubicka <hubicka@ucw.cz> 2018-01-30 Jan Hubicka <hubicka@ucw.cz>
PR ipa/81360
* g++.dg/torture/pr81360.C: New testcase.
2018-01-30 Jan Hubicka <hubicka@ucw.cz>
PR lto/83954 PR lto/83954
* gcc.dg/lto/pr83954.h: New testcase. * gcc.dg/lto/pr83954.h: New testcase.
* gcc.dg/lto/pr83954_0.c: New testcase. * gcc.dg/lto/pr83954_0.c: New testcase.
......
/* { 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" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment