[PATCH, PR 45572] Fix two minor issues with indirect inlining
Martin Jambor
mjambor@suse.cz
Wed Sep 22 16:40:00 GMT 2010
Hi,
PR 45572 has three testcases which exhibit two different bugs:
1) ipa_make_edge_direct_to_target can inadvertently lazily create new
cgraph nodes when looking up a node for a decl with cgraph_node
function. This node then has an uid which is larger than size of
ipa_node_params_vector, causing index out of bounds assert. The
function should not create new nodes and so I replaced the call with a
call to cgraph_get_node.
2) If recursive indirect edges are discovered during recursive
inlining, they are added to new_edges but
cgraph_decide_recursive_inlining then looks them itself and processes
them immediately. When edges from new_edges are processed, it
attempts to inline recursively them again which leads to all sorts of
weird consequences. Fixed by teaching the indirect inlining machinery
not to add recursive edges when doing recursive inlining, which is
flagged by new parameters of ipa_propagate_indirect_call_infos and
unfortunately also of cgraph_mark_inline_edge.
Bootstrapped and tested on x86_64-linux, OK for trunk?
Thanks,
Martin
2010-09-21 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/45572
* ipa-prop.c (ipa_make_edge_direct_to_target): Use cgraph_get_node
instead of cgraph_node.
(update_indirect_edges_after_inlining): New parameter ignore.
(propagate_info_to_inlined_callees): Likewise.
(ipa_propagate_indirect_call_infos): New parameter new_recursive.
* ipa-inline.c (cgraph_mark_inline_edge): New parameter new_recursive.
Updated all callers.
* testsuite/g++.dg/torture/pr45572-1.C: New test.
* testsuite/g++.dg/torture/pr45572-2.C: Likewise.
Index: icln/gcc/ipa-inline.c
===================================================================
--- icln.orig/gcc/ipa-inline.c
+++ icln/gcc/ipa-inline.c
@@ -305,11 +305,13 @@ cgraph_clone_inlined_nodes (struct cgrap
/* Mark edge E as inlined and update callgraph accordingly. UPDATE_ORIGINAL
specify whether profile of original function should be updated. If any new
indirect edges are discovered in the process, add them to NEW_EDGES, unless
- it is NULL. Return true iff any new callgraph edges were discovered as a
- result of inlining. */
+ it is NULL. NEW_RECURSIVE should be set to false iff new recursive edges
+ should not be added to NEW_EDGES. Return true iff any new callgraph edges
+ were discovered as a result of inlining. */
static bool
cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
+ bool new_recursive,
VEC (cgraph_edge_p, heap) **new_edges)
{
int old_size = 0, new_size = 0;
@@ -343,7 +345,7 @@ cgraph_mark_inline_edge (struct cgraph_e
/* FIXME: We should remove the optimize check after we ensure we never run
IPA passes when not optimizng. */
if (flag_indirect_inlining && optimize)
- return ipa_propagate_indirect_call_infos (curr, new_edges);
+ return ipa_propagate_indirect_call_infos (curr, new_recursive, new_edges);
else
return false;
}
@@ -365,7 +367,7 @@ cgraph_mark_inline (struct cgraph_edge *
next = e->next_caller;
if (e->caller == to && e->inline_failed)
{
- cgraph_mark_inline_edge (e, true, NULL);
+ cgraph_mark_inline_edge (e, true, false, NULL);
if (e == edge)
edge = next;
}
@@ -960,7 +962,7 @@ cgraph_decide_recursive_inlining (struct
fprintf (dump_file, "\n");
}
cgraph_redirect_edge_callee (curr, master_clone);
- cgraph_mark_inline_edge (curr, false, new_edges);
+ cgraph_mark_inline_edge (curr, false, false, new_edges);
lookup_recursive_calls (node, curr->callee, heap);
n++;
}
@@ -1245,7 +1247,7 @@ cgraph_decide_inlining_of_small_function
}
callee = edge->callee;
gcc_checking_assert (!callee->global.inlined_to);
- cgraph_mark_inline_edge (edge, true, &new_indirect_edges);
+ cgraph_mark_inline_edge (edge, true, true, &new_indirect_edges);
if (flag_indirect_inlining)
add_new_edges_to_heap (heap, new_indirect_edges);
@@ -1409,7 +1411,7 @@ cgraph_flatten (struct cgraph_node *node
cgraph_node_name (e->callee),
cgraph_node_name (e->caller));
orig_callee = e->callee;
- cgraph_mark_inline_edge (e, true, NULL);
+ cgraph_mark_inline_edge (e, true, false, NULL);
if (e->callee != orig_callee)
orig_callee->aux = (void *)(size_t) INLINE_ALL;
cgraph_flatten (e->callee);
Index: icln/gcc/ipa-prop.c
===================================================================
--- icln.orig/gcc/ipa-prop.c
+++ icln/gcc/ipa-prop.c
@@ -1444,7 +1444,7 @@ ipa_make_edge_direct_to_target (struct c
target = TREE_OPERAND (target, 0);
if (TREE_CODE (target) != FUNCTION_DECL)
return NULL;
- callee = cgraph_node (target);
+ callee = cgraph_get_node (target);
if (!callee)
return NULL;
@@ -1543,6 +1543,7 @@ try_make_edge_direct_virtual_call (struc
static bool
update_indirect_edges_after_inlining (struct cgraph_edge *cs,
struct cgraph_node *node,
+ struct cgraph_node *ignore,
VEC (cgraph_edge_p, heap) **new_edges)
{
struct ipa_edge_args *top;
@@ -1594,7 +1595,7 @@ update_indirect_edges_after_inlining (st
if (new_direct_edge)
{
new_direct_edge->indirect_inlining_edge = 1;
- if (new_edges)
+ if (new_edges && new_direct_edge->callee != ignore)
{
VEC_safe_push (cgraph_edge_p, heap, *new_edges,
new_direct_edge);
@@ -1612,22 +1613,24 @@ update_indirect_edges_after_inlining (st
update_indirect_edges_after_inlining on all nodes and
update_jump_functions_after_inlining on all non-inlined edges that lead out
of this subtree. Newly discovered indirect edges will be added to
- *NEW_EDGES, unless NEW_EDGES is NULL. Return true iff a new edge(s) were
- created. */
+ *NEW_EDGES except when NEW_EDGES is NULL or the edge leads to the node
+ IGNORE. Return true iff a new edge(s) were added to the vector. */
static bool
propagate_info_to_inlined_callees (struct cgraph_edge *cs,
struct cgraph_node *node,
+ struct cgraph_node *ignore,
VEC (cgraph_edge_p, heap) **new_edges)
{
struct cgraph_edge *e;
bool res;
- res = update_indirect_edges_after_inlining (cs, node, new_edges);
+ res = update_indirect_edges_after_inlining (cs, node, ignore, new_edges);
for (e = node->callees; e; e = e->next_callee)
if (!e->inline_failed)
- res |= propagate_info_to_inlined_callees (cs, e->callee, new_edges);
+ res |= propagate_info_to_inlined_callees (cs, e->callee, ignore,
+ new_edges);
else
update_jump_functions_after_inlining (cs, e);
@@ -1637,13 +1640,16 @@ propagate_info_to_inlined_callees (struc
/* Update jump functions and call note functions on inlining the call site CS.
CS is expected to lead to a node already cloned by
cgraph_clone_inline_nodes. Newly discovered indirect edges will be added to
- *NEW_EDGES, unless NEW_EDGES is NULL. Return true iff a new edge(s) were +
- created. */
+ *NEW_EDGES except when NEW_EDGES is NULL or the edge leads to the node
+ IGNORE. Return true iff any new edges were added to the vector. */
bool
ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
+ bool new_recursive,
VEC (cgraph_edge_p, heap) **new_edges)
{
+ struct cgraph_node *ignore;
+
/* FIXME lto: We do not stream out indirect call information. */
if (flag_wpa)
return false;
@@ -1654,7 +1660,16 @@ ipa_propagate_indirect_call_infos (struc
return false;
gcc_assert (ipa_edge_args_vector);
- return propagate_info_to_inlined_callees (cs, cs->callee, new_edges);
+ if (new_recursive)
+ ignore = NULL;
+ else
+ {
+ ignore = cs->caller;
+ if (ignore->global.inlined_to)
+ ignore = ignore->global.inlined_to;
+ }
+
+ return propagate_info_to_inlined_callees (cs, cs->callee, ignore, new_edges);
}
/* Frees all dynamically allocated structures that the argument info points
Index: icln/gcc/ipa-prop.h
===================================================================
--- icln.orig/gcc/ipa-prop.h
+++ icln/gcc/ipa-prop.h
@@ -427,6 +427,7 @@ void ipa_analyze_node (struct cgraph_nod
/* Function formal parameters related computations. */
void ipa_initialize_node_params (struct cgraph_node *node);
bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs,
+ bool new_recursive,
VEC (cgraph_edge_p, heap) **new_edges);
/* Indirect edge and binfo processing. */
Index: icln/gcc/testsuite/g++.dg/torture/pr45572-1.C
===================================================================
--- /dev/null
+++ icln/gcc/testsuite/g++.dg/torture/pr45572-1.C
@@ -0,0 +1,63 @@
+// { dg-do compile }
+
+extern "C" {
+typedef long unsigned int size_t;
+typedef long int __ssize_t;
+typedef struct _IO_FILE FILE;
+typedef struct
+{
+} __mbstate_t;
+extern __inline __attribute__ ((__gnu_inline__)) int
+fgetc_unlocked (FILE *__fp)
+{
+}
+extern __inline __attribute__ ((__gnu_inline__)) int
+putc_unlocked (int __c, FILE *__stream)
+{
+}
+extern __inline __attribute__ ((__gnu_inline__)) __ssize_t
+getline (char **__lineptr, size_t *__n, FILE *__stream)
+{
+}
+extern __inline __attribute__ ((__gnu_inline__)) int
+ferror_unlocked (FILE *__stream) throw ()
+{
+}
+}
+typedef struct
+{} __mpf_struct;
+typedef __mpf_struct mpf_t[1];
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+extern "C" {
+ void __gmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+}
+class _knumber
+{
+ public:
+ enum NumType {SpecialType, IntegerType, FractionType, FloatType};
+ virtual NumType type(void) const = 0;
+ virtual _knumber * add(_knumber const & arg2) const = 0;
+ virtual operator long int(void) const = 0;
+};
+class _knumfloat : public _knumber
+{
+ _knumfloat(double num = 1.0)
+ ;
+ virtual NumType type(void) const ;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual operator long int (void) const;
+ mpf_t _mpf;
+};
+_knumber *_knumfloat::add(_knumber const & arg2) const
+{
+ if (arg2.type() == SpecialType)
+ return arg2.add(*this);
+{
+ _knumfloat tmp_num(arg2);
+ return tmp_num.add(*this);
+ }
+ _knumfloat * tmp_num = new _knumfloat();
+ __gmpf_add(tmp_num->_mpf, _mpf,
+ dynamic_cast<_knumfloat const &>(arg2)._mpf);
+}
Index: icln/gcc/testsuite/g++.dg/torture/pr45572-2.C
===================================================================
--- /dev/null
+++ icln/gcc/testsuite/g++.dg/torture/pr45572-2.C
@@ -0,0 +1,39 @@
+// { dg-do compile }
+
+typedef struct
+{} __mpf_struct;
+typedef __mpf_struct mpf_t[1];
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+extern "C" {
+ void __gmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+}
+class _knumber
+{
+ public:
+ enum NumType {SpecialType, IntegerType, FractionType, FloatType};
+ virtual NumType type(void) const = 0;
+ virtual _knumber * add(_knumber const & arg2) const = 0;
+ virtual operator long int(void) const = 0;
+};
+class _knumfloat : public _knumber
+{
+ _knumfloat(double num = 1.0)
+ ;
+ virtual NumType type(void) const ;
+ virtual _knumber * add(_knumber const & arg2) const;
+ virtual operator long int (void) const;
+ mpf_t _mpf;
+};
+_knumber *_knumfloat::add(_knumber const & arg2) const
+{
+ if (arg2.type() == SpecialType)
+ return arg2.add(*this);
+{
+ _knumfloat tmp_num(arg2);
+ return tmp_num.add(*this);
+ }
+ _knumfloat * tmp_num = new _knumfloat();
+ __gmpf_add(tmp_num->_mpf, _mpf,
+ dynamic_cast<_knumfloat const &>(arg2)._mpf);
+}
More information about the Gcc-patches
mailing list