aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-02-20 07:40:07 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2014-02-20 06:40:07 +0000
commitbd936951453c1105710649955568375e67c69d30 (patch)
treeaa5cb062d365b7b66d1c27c29cac928aaa4f40a4 /gcc
parent3c898e1acb4f9c8d43c84d2138fa298de0205c46 (diff)
downloadgcc-bd936951453c1105710649955568375e67c69d30.zip
gcc-bd936951453c1105710649955568375e67c69d30.tar.gz
gcc-bd936951453c1105710649955568375e67c69d30.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/ipa-inline-transform.c17
-rw-r--r--gcc/ipa-inline.c8
-rw-r--r--gcc/ipa-inline.h3
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr58555.C114
6 files changed, 150 insertions, 7 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a401d85..24d8e18 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index a24f68d..b2e0285 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -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);
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index d304133..f6f97f8 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -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);
}
diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
index 618189b..0a59608 100644
--- a/gcc/ipa-inline.h
+++ b/gcc/ipa-inline.h
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 46ef4dc..0b8de78 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/torture/pr58555.C b/gcc/testsuite/g++.dg/torture/pr58555.C
new file mode 100644
index 0000000..ac5009a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr58555.C
@@ -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); }