7123347c8b
PR 93621 testcase makes redirect_call_stmt_to_callee wrongly assume that a call statement needs redirecting but then rightly fails an assert ensuring the call statement parameters have not already been adjusted because they were already created adjusted as part of thunk expansion. The test fails because the decl in the call call statement is different than the decl of the callee, because the latter was created in save_inline_function_body. This patch adds a way to link these two and detect the situation in redirect_call_stmt_to_callee. 2020-04-16 Martin Jambor <mjambor@suse.cz> PR ipa/93621 * ipa-inline.h (ipa_saved_clone_sources): Declare. * ipa-inline-transform.c (ipa_saved_clone_sources): New variable. (save_inline_function_body): Link the new body holder with the previous one. * cgraph.c: Include ipa-inline.h. (cgraph_edge::redirect_call_stmt_to_callee): Try to find the decl from the statement in ipa_saved_clone_sources. * cgraphunit.c: Include ipa-inline.h. (expand_all_functions): Free ipa_saved_clone_sources. testsuite/ * g++.dg/ipa/pr93621.C: New test.
135 lines
4.2 KiB
C++
135 lines
4.2 KiB
C++
/* Inlining decision heuristics.
|
|
Copyright (C) 2003-2020 Free Software Foundation, Inc.
|
|
Contributed by Jan Hubicka
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef GCC_IPA_INLINE_H
|
|
#define GCC_IPA_INLINE_H
|
|
|
|
/* Data we cache about callgraph edges during inlining to avoid expensive
|
|
re-computations during the greedy algorithm. */
|
|
class edge_growth_cache_entry
|
|
{
|
|
public:
|
|
sreal time, nonspec_time;
|
|
int size;
|
|
ipa_hints hints;
|
|
|
|
edge_growth_cache_entry()
|
|
: size (0), hints (0) {}
|
|
|
|
edge_growth_cache_entry(int64_t time, int64_t nonspec_time,
|
|
int size, ipa_hints hints)
|
|
: time (time), nonspec_time (nonspec_time), size (size),
|
|
hints (hints) {}
|
|
};
|
|
|
|
extern fast_call_summary<edge_growth_cache_entry *, va_heap> *edge_growth_cache;
|
|
|
|
/* In ipa-inline-analysis.c */
|
|
int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
|
|
int estimate_growth (struct cgraph_node *);
|
|
bool growth_positive_p (struct cgraph_node *, struct cgraph_edge *, int);
|
|
int do_estimate_edge_size (struct cgraph_edge *edge);
|
|
sreal do_estimate_edge_time (struct cgraph_edge *edge, sreal *nonspec_time = NULL);
|
|
ipa_hints do_estimate_edge_hints (struct cgraph_edge *edge);
|
|
void reset_node_cache (struct cgraph_node *node);
|
|
void initialize_growth_caches ();
|
|
void free_growth_caches (void);
|
|
|
|
/* In ipa-inline.c */
|
|
unsigned int early_inliner (function *fun);
|
|
bool inline_account_function_p (struct cgraph_node *node);
|
|
|
|
|
|
/* In ipa-inline-transform.c */
|
|
bool inline_call (struct cgraph_edge *, bool, vec<cgraph_edge *> *, int *, bool,
|
|
bool *callee_removed = NULL);
|
|
unsigned int inline_transform (struct cgraph_node *);
|
|
void clone_inlined_nodes (struct cgraph_edge *e, bool, bool, int *);
|
|
|
|
extern int ncalls_inlined;
|
|
extern int nfunctions_inlined;
|
|
extern function_summary <tree *> *ipa_saved_clone_sources;
|
|
|
|
/* Return estimated size of the inline sequence of EDGE. */
|
|
|
|
static inline int
|
|
estimate_edge_size (struct cgraph_edge *edge)
|
|
{
|
|
edge_growth_cache_entry *entry;
|
|
if (edge_growth_cache == NULL
|
|
|| (entry = edge_growth_cache->get (edge)) == NULL
|
|
|| entry->size == 0)
|
|
return do_estimate_edge_size (edge);
|
|
return entry->size - (entry->size > 0);
|
|
}
|
|
|
|
/* Return lower bound on estimated callee growth after inlining EDGE. */
|
|
|
|
static inline int
|
|
estimate_min_edge_growth (struct cgraph_edge *edge)
|
|
{
|
|
ipa_call_summary *s = ipa_call_summaries->get (edge);
|
|
struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
|
|
return (ipa_fn_summaries->get (callee)->min_size - s->call_stmt_size);
|
|
}
|
|
|
|
/* Return estimated callee growth after inlining EDGE. */
|
|
|
|
static inline int
|
|
estimate_edge_growth (struct cgraph_edge *edge)
|
|
{
|
|
ipa_call_summary *s = ipa_call_summaries->get (edge);
|
|
gcc_checking_assert (s->call_stmt_size || !edge->callee->analyzed);
|
|
return (estimate_edge_size (edge) - s->call_stmt_size);
|
|
}
|
|
|
|
/* Return estimated callee runtime increase after inlining
|
|
EDGE. */
|
|
|
|
static inline sreal
|
|
estimate_edge_time (struct cgraph_edge *edge, sreal *nonspec_time = NULL)
|
|
{
|
|
edge_growth_cache_entry *entry;
|
|
if (edge_growth_cache == NULL
|
|
|| (entry = edge_growth_cache->get (edge)) == NULL
|
|
|| entry->time == 0)
|
|
return do_estimate_edge_time (edge, nonspec_time);
|
|
if (nonspec_time)
|
|
*nonspec_time = edge_growth_cache->get (edge)->nonspec_time;
|
|
return entry->time;
|
|
}
|
|
|
|
|
|
/* Return estimated callee runtime increase after inlining
|
|
EDGE. */
|
|
|
|
static inline ipa_hints
|
|
estimate_edge_hints (struct cgraph_edge *edge)
|
|
{
|
|
edge_growth_cache_entry *entry;
|
|
if (edge_growth_cache == NULL
|
|
|| (entry = edge_growth_cache->get (edge)) == NULL
|
|
|| entry->hints == 0)
|
|
return do_estimate_edge_hints (edge);
|
|
return entry->hints - 1;
|
|
}
|
|
|
|
#endif /* GCC_IPA_INLINE_H */
|