re PR middle-end/58555 (Floating point exception in want_inline_self_recursive_call_p)
PR ipa/58555 * ipa-inline-transform.c (clone_inlined_nodes): Add freq_scale parameter specifying the scaling. (inline_call): Update. (want_inline_recursively): Guard division by zero. (recursive_inlining): Update. * ipa-inline.h (clone_inlined_nodes): Update. * testsuite/g++.dg/torture/pr58555.C: New testcase. From-SVN: r207934
This commit is contained in:
parent
3c898e1acb
commit
bd93695145
@ -1,3 +1,13 @@
|
||||
2014-02-20 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/58555
|
||||
* ipa-inline-transform.c (clone_inlined_nodes): Add freq_scale parameter
|
||||
specifying the scaling.
|
||||
(inline_call): Update.
|
||||
(want_inline_recursively): Guard division by zero.
|
||||
(recursive_inlining): Update.
|
||||
* ipa-inline.h (clone_inlined_nodes): Update.
|
||||
|
||||
2014-02-20 Ilya Tocar <ilya.tocar@intel.com>
|
||||
|
||||
PR target/60204
|
||||
|
@ -127,11 +127,15 @@ can_remove_node_now_p (struct cgraph_node *node, struct cgraph_edge *e)
|
||||
the edge and redirect it to the new clone.
|
||||
DUPLICATE is used for bookkeeping on whether we are actually creating new
|
||||
clones or re-using node originally representing out-of-line function call.
|
||||
*/
|
||||
By default the offline copy is removed, when it appears dead after inlining.
|
||||
UPDATE_ORIGINAL prevents this transformation.
|
||||
If OVERALL_SIZE is non-NULL, the size is updated to reflect the
|
||||
transformation.
|
||||
FREQ_SCALE specify the scaling of frequencies of call sites. */
|
||||
|
||||
void
|
||||
clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
|
||||
bool update_original, int *overall_size)
|
||||
bool update_original, int *overall_size, int freq_scale)
|
||||
{
|
||||
struct cgraph_node *inlining_into;
|
||||
struct cgraph_edge *next;
|
||||
@ -175,8 +179,11 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
|
||||
else
|
||||
{
|
||||
struct cgraph_node *n;
|
||||
|
||||
if (freq_scale == -1)
|
||||
freq_scale = e->frequency;
|
||||
n = cgraph_clone_node (e->callee, e->callee->decl,
|
||||
e->count, e->frequency, update_original,
|
||||
e->count, freq_scale, update_original,
|
||||
vNULL, true, inlining_into);
|
||||
cgraph_redirect_edge_callee (e, n);
|
||||
}
|
||||
@ -191,7 +198,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
|
||||
{
|
||||
next = e->next_callee;
|
||||
if (!e->inline_failed)
|
||||
clone_inlined_nodes (e, duplicate, update_original, overall_size);
|
||||
clone_inlined_nodes (e, duplicate, update_original, overall_size, freq_scale);
|
||||
if (e->speculative && !speculation_useful_p (e, true))
|
||||
{
|
||||
cgraph_resolve_speculation (e, NULL);
|
||||
@ -260,7 +267,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
|
||||
}
|
||||
}
|
||||
|
||||
clone_inlined_nodes (e, true, update_original, overall_size);
|
||||
clone_inlined_nodes (e, true, update_original, overall_size, e->frequency);
|
||||
|
||||
gcc_assert (curr->callee->global.inlined_to == to);
|
||||
|
||||
|
@ -708,6 +708,12 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
|
||||
if (outer_node->global.inlined_to)
|
||||
caller_freq = outer_node->callers->frequency;
|
||||
|
||||
if (!caller_freq)
|
||||
{
|
||||
reason = "function is inlined and unlikely";
|
||||
want_inline = false;
|
||||
}
|
||||
|
||||
if (!want_inline)
|
||||
;
|
||||
/* Inlining of self recursive function into copy of itself within other function
|
||||
@ -1385,7 +1391,7 @@ recursive_inlining (struct cgraph_edge *edge,
|
||||
false, vNULL, true, NULL);
|
||||
for (e = master_clone->callees; e; e = e->next_callee)
|
||||
if (!e->inline_failed)
|
||||
clone_inlined_nodes (e, true, false, NULL);
|
||||
clone_inlined_nodes (e, true, false, NULL, CGRAPH_FREQ_BASE);
|
||||
cgraph_redirect_edge_callee (curr, master_clone);
|
||||
reset_edge_growth_cache (curr);
|
||||
}
|
||||
|
@ -233,7 +233,8 @@ bool speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining);
|
||||
/* In ipa-inline-transform.c */
|
||||
bool inline_call (struct cgraph_edge *, bool, vec<cgraph_edge_p> *, int *, bool);
|
||||
unsigned int inline_transform (struct cgraph_node *);
|
||||
void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *);
|
||||
void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *,
|
||||
int freq_scale);
|
||||
|
||||
extern int ncalls_inlined;
|
||||
extern int nfunctions_inlined;
|
||||
|
@ -1,3 +1,8 @@
|
||||
2014-02-20 Jan Hubicka <hubicka@ucw.cz>
|
||||
|
||||
PR ipa/58555
|
||||
* testsuite/g++.dg/torture/pr58555.C: New testcase.
|
||||
|
||||
2014-02-20 Ilya Tocar <ilya.tocar@intel.com>
|
||||
|
||||
PR target/60204
|
||||
|
114
gcc/testsuite/g++.dg/torture/pr58555.C
Normal file
114
gcc/testsuite/g++.dg/torture/pr58555.C
Normal file
@ -0,0 +1,114 @@
|
||||
/* { dg-do compile } */
|
||||
template <typename _Tp> _Tp *__addressof(_Tp &) {}
|
||||
template <typename _Tp> class A {
|
||||
public:
|
||||
typedef _Tp *pointer;
|
||||
};
|
||||
template <typename _Tp> class M : public A<_Tp> {
|
||||
public:
|
||||
typedef M other;
|
||||
~M();
|
||||
};
|
||||
class B {
|
||||
public:
|
||||
B(int *);
|
||||
};
|
||||
class C {
|
||||
public:
|
||||
void GetNext();
|
||||
C *GetChildren();
|
||||
};
|
||||
template <typename _Tp> void _Destroy(_Tp *p1) { p1->~_Tp(); }
|
||||
struct D {
|
||||
template <typename _ForwardIterator>
|
||||
static void __destroy(_ForwardIterator p1, _ForwardIterator p2) {
|
||||
for (; p1 != p2; ++p1)
|
||||
_Destroy(__addressof(*p1));
|
||||
}
|
||||
};
|
||||
template <typename _ForwardIterator>
|
||||
void _Destroy(_ForwardIterator p1, _ForwardIterator p2) {
|
||||
D::__destroy(p1, p2);
|
||||
}
|
||||
template <typename _ForwardIterator, typename _Tp>
|
||||
void _Destroy(_ForwardIterator p1, _ForwardIterator p2, M<_Tp> &) {
|
||||
_Destroy(p1, p2);
|
||||
}
|
||||
template <typename _Alloc> struct F {
|
||||
typedef _Alloc _Tp_alloc_type;
|
||||
typedef typename _Tp_alloc_type::pointer pointer;
|
||||
struct N : _Tp_alloc_type {
|
||||
pointer _M_start;
|
||||
pointer _M_finish;
|
||||
};
|
||||
_Tp_alloc_type &_M_get_Tp_allocator();
|
||||
N _M_impl;
|
||||
};
|
||||
template <typename _Tp, typename _Alloc = M<_Tp> > class O : F<_Alloc> {
|
||||
using F<_Alloc>::_M_get_Tp_allocator;
|
||||
public:
|
||||
~O() {
|
||||
_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
|
||||
_M_get_Tp_allocator());
|
||||
}
|
||||
};
|
||||
template <class T> void checked_delete(T *p1) { delete p1; }
|
||||
template <class> class I;
|
||||
template <class T> struct J {
|
||||
typedef T *type;
|
||||
};
|
||||
class K;
|
||||
class L {
|
||||
public:
|
||||
virtual ~L();
|
||||
};
|
||||
class P : L {
|
||||
O<I<int> > databasesM;
|
||||
O<I<K> > usersM;
|
||||
public:
|
||||
I<int> addDatabase();
|
||||
};
|
||||
C a;
|
||||
C *b;
|
||||
int atomic_exchange_and_add();
|
||||
class G {
|
||||
public:
|
||||
virtual void dispose() = 0;
|
||||
void release() {
|
||||
if (atomic_exchange_and_add() == 1)
|
||||
dispose();
|
||||
}
|
||||
};
|
||||
class Q : G {
|
||||
P *px_;
|
||||
Q() {}
|
||||
void dispose() { checked_delete(px_); }
|
||||
};
|
||||
class H {
|
||||
G *pi_;
|
||||
public:
|
||||
H();
|
||||
H(P *);
|
||||
~H() {
|
||||
if (pi_)
|
||||
pi_->release();
|
||||
}
|
||||
};
|
||||
template <class T, class Y> void sp_pointer_construct(I<T> *, Y, H);
|
||||
template <class T> class I {
|
||||
public:
|
||||
typedef T element_type;
|
||||
template <class Y> I(Y *p1) { sp_pointer_construct(this, 0, 0); }
|
||||
typename J<T>::type operator->();
|
||||
H pn;
|
||||
};
|
||||
void getNodeContent(const B &) {
|
||||
for (C *n = a.GetChildren(); n; n->GetNext())
|
||||
;
|
||||
}
|
||||
void parseDatabase(I<P> p1) {
|
||||
I<int> c = p1->addDatabase();
|
||||
for (; b;)
|
||||
getNodeContent(0);
|
||||
}
|
||||
void addServer() { I<int>(new P); }
|
Loading…
Reference in New Issue
Block a user