Message ID | 20100922095156.GA3994@virgil.arch.suse.de |
---|---|
State | New |
Headers | show |
On Wed, Sep 22, 2010 at 11:51 AM, Martin Jambor <mjambor@suse.cz> wrote: > 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. That part sounds obvious, you might want to install it separately. > 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. Can you expand on the "weird consequences"? Could we instead disable indirect inlining during recursive inlining (and would that make the patch any prettier?). Thanks, Richard. > 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); > +} > >
> On Wed, Sep 22, 2010 at 11:51 AM, Martin Jambor <mjambor@suse.cz> wrote: > > 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. > > That part sounds obvious, you might want to install it separately. This is the case where we have previously virtual call but devirtualization finds call using object with external vtable (so function never seen previously becomes reachable). I don't like the approach of keeping calls indirect when they are really known to be direct. Even when it won't degrade inlining (since the function was unseen previously and thus has no body), still how much pain would be to update tables instead? > > > 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. > > Can you expand on the "weird consequences"? Could we instead > disable indirect inlining during recursive inlining (and would that > make the patch any prettier?). I saw here a testcase where virtual method was self recursive. Only after inlining the first call the self recursiveness become obvious, so I guess we should handle this. I looked into the PR briefly before and noticed it has an weird consequences, but didn't quite understood why? Honza > > Thanks, > Richard. > > > 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); > > +} > > > >
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); +}