aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-inline.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-inline.c')
-rw-r--r--gcc/tree-inline.c292
1 files changed, 110 insertions, 182 deletions
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 1dcb31c..5e50e80 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -152,30 +152,6 @@ insert_decl_map (copy_body_data *id, tree key, tree value)
id->decl_map->put (value, value);
}
-/* Insert a tree->tree mapping for ID. This is only used for
- variables. */
-
-static void
-insert_debug_decl_map (copy_body_data *id, tree key, tree value)
-{
- if (!gimple_in_ssa_p (id->src_cfun))
- return;
-
- if (!opt_for_fn (id->dst_fn, flag_var_tracking_assignments))
- return;
-
- if (!target_for_debug_bind (key))
- return;
-
- gcc_assert (TREE_CODE (key) == PARM_DECL);
- gcc_assert (VAR_P (value));
-
- if (!id->debug_map)
- id->debug_map = new hash_map<tree, tree>;
-
- id->debug_map->put (key, value);
-}
-
/* If nonzero, we're remapping the contents of inlined debug
statements. If negative, an error has occurred, such as a
reference to a variable that isn't available in the inlined
@@ -1140,7 +1116,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
*tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1));
TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
- TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+ copy_warning (*tp, old);
if (MR_DEPENDENCE_CLIQUE (old) != 0)
{
MR_DEPENDENCE_CLIQUE (*tp)
@@ -1399,7 +1375,7 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
*tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1));
TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old);
TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old);
- TREE_NO_WARNING (*tp) = TREE_NO_WARNING (old);
+ copy_warning (*tp, old);
if (MR_DEPENDENCE_CLIQUE (old) != 0)
{
MR_DEPENDENCE_CLIQUE (*tp)
@@ -1477,6 +1453,28 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
*walk_subtrees = 0;
}
+ else if (TREE_CODE (*tp) == OMP_CLAUSE
+ && (OMP_CLAUSE_CODE (*tp) == OMP_CLAUSE_AFFINITY
+ || OMP_CLAUSE_CODE (*tp) == OMP_CLAUSE_DEPEND))
+ {
+ tree t = OMP_CLAUSE_DECL (*tp);
+ if (t
+ && TREE_CODE (t) == TREE_LIST
+ && TREE_PURPOSE (t)
+ && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC)
+ {
+ *walk_subtrees = 0;
+ OMP_CLAUSE_DECL (*tp) = copy_node (t);
+ t = OMP_CLAUSE_DECL (*tp);
+ TREE_PURPOSE (t) = copy_node (TREE_PURPOSE (t));
+ for (int i = 0; i <= 4; i++)
+ walk_tree (&TREE_VEC_ELT (TREE_PURPOSE (t), i),
+ copy_tree_body_r, id, NULL);
+ if (TREE_VEC_ELT (TREE_PURPOSE (t), 5))
+ remap_block (&TREE_VEC_ELT (TREE_PURPOSE (t), 5), id);
+ walk_tree (&TREE_VALUE (t), copy_tree_body_r, id, NULL);
+ }
+ }
}
/* Keep iterating. */
@@ -1528,6 +1526,11 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
: !opt_for_fn (id->dst_fn, flag_var_tracking_assignments)))
return NULL;
+ if (!is_gimple_debug (stmt)
+ && id->param_body_adjs
+ && id->param_body_adjs->m_dead_stmts.contains (stmt))
+ return NULL;
+
/* Begin by recognizing trees that we'll completely rewrite for the
inlining context. Our output for these trees is completely
different from our input (e.g. RETURN_EXPR is deleted and morphs
@@ -1655,6 +1658,18 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
copy = gimple_build_omp_master (s1);
break;
+ case GIMPLE_OMP_MASKED:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_masked
+ (s1, gimple_omp_masked_clauses (stmt));
+ break;
+
+ case GIMPLE_OMP_SCOPE:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_scope
+ (s1, gimple_omp_scope_clauses (stmt));
+ break;
+
case GIMPLE_OMP_TASKGROUP:
s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
copy = gimple_build_omp_taskgroup
@@ -1792,10 +1807,15 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
if (gimple_debug_bind_p (stmt))
{
+ tree value;
+ if (id->param_body_adjs
+ && id->param_body_adjs->m_dead_stmts.contains (stmt))
+ value = NULL_TREE;
+ else
+ value = gimple_debug_bind_get_value (stmt);
gdebug *copy
= gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
- gimple_debug_bind_get_value (stmt),
- stmt);
+ value, stmt);
if (id->reset_location)
gimple_set_location (copy, input_location);
id->debug_stmts.safe_push (copy);
@@ -1924,7 +1944,7 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
if (id->param_body_adjs)
{
gimple_seq extra_stmts = NULL;
- id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts);
+ id->param_body_adjs->modify_gimple_stmt (&copy, &extra_stmts, stmt);
if (!gimple_seq_empty_p (extra_stmts))
{
memset (&wi, 0, sizeof (wi));
@@ -2093,27 +2113,29 @@ copy_bb (copy_body_data *id, basic_block bb,
tree p;
gcall *new_call;
vec<tree> argarray;
- size_t nargs = gimple_call_num_args (id->call_stmt);
- size_t n;
+ size_t nargs_caller = gimple_call_num_args (id->call_stmt);
+ size_t nargs = nargs_caller;
for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
nargs--;
/* Create the new array of arguments. */
- n = nargs + gimple_call_num_args (call_stmt);
+ size_t nargs_callee = gimple_call_num_args (call_stmt);
+ size_t n = nargs + nargs_callee;
argarray.create (n);
argarray.safe_grow_cleared (n, true);
/* Copy all the arguments before '...' */
- memcpy (argarray.address (),
- gimple_call_arg_ptr (call_stmt, 0),
- gimple_call_num_args (call_stmt) * sizeof (tree));
+ if (nargs_callee)
+ memcpy (argarray.address (),
+ gimple_call_arg_ptr (call_stmt, 0),
+ nargs_callee * sizeof (tree));
/* Append the arguments passed in '...' */
- memcpy (argarray.address () + gimple_call_num_args (call_stmt),
- gimple_call_arg_ptr (id->call_stmt, 0)
- + (gimple_call_num_args (id->call_stmt) - nargs),
- nargs * sizeof (tree));
+ if (nargs)
+ memcpy (argarray.address () + nargs_callee,
+ gimple_call_arg_ptr (id->call_stmt, 0)
+ + (nargs_caller - nargs), nargs * sizeof (tree));
new_call = gimple_build_call_vec (gimple_call_fn (call_stmt),
argarray);
@@ -2124,6 +2146,7 @@ copy_bb (copy_body_data *id, basic_block bb,
GF_CALL_VA_ARG_PACK. */
gimple_call_copy_flags (new_call, call_stmt);
gimple_call_set_va_arg_pack (new_call, false);
+ gimple_call_set_fntype (new_call, gimple_call_fntype (call_stmt));
/* location includes block. */
gimple_set_location (new_call, gimple_location (stmt));
gimple_call_set_lhs (new_call, gimple_call_lhs (call_stmt));
@@ -2674,7 +2697,9 @@ copy_phis_for_bb (basic_block bb, copy_body_data *id)
phi = si.phi ();
res = PHI_RESULT (phi);
new_res = res;
- if (!virtual_operand_p (res))
+ if (!virtual_operand_p (res)
+ && (!id->param_body_adjs
+ || !id->param_body_adjs->m_dead_stmts.contains (phi)))
{
walk_tree (&new_res, copy_tree_body_r, id, NULL);
if (EDGE_COUNT (new_bb->preds) == 0)
@@ -2855,7 +2880,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
gimple_set_location (stmt, UNKNOWN_LOCATION);
}
gsi_remove (&si, false);
- gsi_insert_before (&dsi, stmt, GSI_SAME_STMT);
+ gsi_insert_before (&dsi, stmt, GSI_NEW_STMT);
continue;
}
@@ -2881,7 +2906,7 @@ maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb)
new_stmt = as_a <gdebug *> (gimple_copy (stmt));
else
gcc_unreachable ();
- gsi_insert_before (&dsi, new_stmt, GSI_SAME_STMT);
+ gsi_insert_before (&dsi, new_stmt, GSI_NEW_STMT);
id->debug_stmts.safe_push (new_stmt);
gsi_prev (&ssi);
}
@@ -3190,7 +3215,8 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
else
gcc_unreachable ();
- if (TREE_CODE (t) == PARM_DECL && id->debug_map
+ if (TREE_CODE (t) == PARM_DECL
+ && id->debug_map
&& (n = id->debug_map->get (t)))
{
gcc_assert (VAR_P (*n));
@@ -3258,13 +3284,10 @@ copy_debug_stmt (gdebug *stmt, copy_body_data *id)
static void
copy_debug_stmts (copy_body_data *id)
{
- size_t i;
- gdebug *stmt;
-
if (!id->debug_stmts.exists ())
return;
- FOR_EACH_VEC_ELT (id->debug_stmts, i, stmt)
+ for (gdebug *stmt : id->debug_stmts)
copy_debug_stmt (stmt, id);
id->debug_stmts.release ();
@@ -3387,7 +3410,7 @@ insert_init_stmt (copy_body_data *id, basic_block bb, gimple *init_stmt)
&& gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS)
{
tree rhs = build1 (gimple_assign_rhs_code (init_stmt),
- gimple_expr_type (init_stmt),
+ TREE_TYPE (gimple_assign_lhs (init_stmt)),
gimple_assign_rhs1 (init_stmt));
rhs = force_gimple_operand_gsi (&si, rhs, true, NULL_TREE, false,
GSI_NEW_STMT);
@@ -3460,16 +3483,18 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
value. */
if (TREE_READONLY (p)
&& !TREE_ADDRESSABLE (p)
- && value && !TREE_SIDE_EFFECTS (value)
+ && value
+ && !TREE_SIDE_EFFECTS (value)
&& !def)
{
- /* We may produce non-gimple trees by adding NOPs or introduce
- invalid sharing when operand is not really constant.
- It is not big deal to prohibit constant propagation here as
- we will constant propagate in DOM1 pass anyway. */
- if (is_gimple_min_invariant (value)
- && useless_type_conversion_p (TREE_TYPE (p),
- TREE_TYPE (value))
+ /* We may produce non-gimple trees by adding NOPs or introduce invalid
+ sharing when the value is not constant or DECL. And we need to make
+ sure that it cannot be modified from another path in the callee. */
+ if ((is_gimple_min_invariant (value)
+ || (DECL_P (value) && TREE_READONLY (value))
+ || (auto_var_in_fn_p (value, id->dst_fn)
+ && !TREE_ADDRESSABLE (value)))
+ && useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value))
/* We have to be very careful about ADDR_EXPR. Make sure
the base variable isn't a local variable of the inlined
function, e.g., when doing recursive inlining, direct or
@@ -3478,7 +3503,9 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
&& ! self_inlining_addr_expr (value, fn))
{
insert_decl_map (id, p, value);
- insert_debug_decl_map (id, p, var);
+ if (!id->debug_map)
+ id->debug_map = new hash_map<tree, tree>;
+ id->debug_map->put (p, var);
return insert_init_debug_bind (id, bb, var, value, NULL);
}
}
@@ -3488,17 +3515,11 @@ setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn,
automatically replaced by the VAR_DECL. */
insert_decl_map (id, p, var);
- /* Even if P was TREE_READONLY, the new VAR should not be.
- In the original code, we would have constructed a
- temporary, and then the function body would have never
- changed the value of P. However, now, we will be
- constructing VAR directly. The constructor body may
- change its value multiple times as it is being
- constructed. Therefore, it must not be TREE_READONLY;
- the back-end assumes that TREE_READONLY variable is
- assigned to only once. */
- if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (p)))
- TREE_READONLY (var) = 0;
+ /* Even if P was TREE_READONLY, the new VAR should not be. In the original
+ code, we would have constructed a temporary, and then the function body
+ would have never changed the value of P. However, now, we will be
+ constructing VAR directly. Therefore, it must not be TREE_READONLY. */
+ TREE_READONLY (var) = 0;
tree rhs = value;
if (value
@@ -3772,7 +3793,7 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
/* Do not have the rest of GCC warn about this variable as it should
not be visible to the user. */
- TREE_NO_WARNING (var) = 1;
+ suppress_warning (var /* OPT_Wuninitialized? */);
declare_inline_vars (id->block, var);
@@ -4022,17 +4043,10 @@ inline_forbidden_p (tree fndecl)
wi.info = (void *) fndecl;
wi.pset = &visited_nodes;
- /* We cannot inline a function with a VLA typed argument or result since
- we have no implementation materializing a variable of such type in
- the caller. */
- if (COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (fndecl)))
- && !poly_int_tree_p (TYPE_SIZE (TREE_TYPE (TREE_TYPE (fndecl)))))
- {
- inline_forbidden_reason
- = G_("function %q+F can never be inlined because "
- "it has a VLA return argument");
- return true;
- }
+ /* We cannot inline a function with a variable-sized parameter because we
+ cannot materialize a temporary of such a type in the caller if need be.
+ Note that the return case is not symmetrical because we can guarantee
+ that a temporary is not needed by means of CALL_EXPR_RETURN_SLOT_OPT. */
for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
if (!poly_int_tree_p (DECL_SIZE (parm)))
{
@@ -4422,8 +4436,8 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
/* Do not special case builtins where we see the body.
This just confuse inliner. */
struct cgraph_node *node;
- if (!(node = cgraph_node::get (decl))
- || node->definition)
+ if ((node = cgraph_node::get (decl))
+ && node->definition)
;
/* For buitins that are likely expanded to nothing or
inlined do not account operand costs. */
@@ -4542,6 +4556,8 @@ estimate_num_insns (gimple *stmt, eni_weights *weights)
case GIMPLE_OMP_TASK:
case GIMPLE_OMP_CRITICAL:
case GIMPLE_OMP_MASTER:
+ case GIMPLE_OMP_MASKED:
+ case GIMPLE_OMP_SCOPE:
case GIMPLE_OMP_TASKGROUP:
case GIMPLE_OMP_ORDERED:
case GIMPLE_OMP_SCAN:
@@ -4740,7 +4756,6 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
use_operand_p use;
gimple *simtenter_stmt = NULL;
vec<tree> *simtvars_save;
- clone_info *info;
/* The gimplifier uses input_location in too many places, such as
internal_get_tmp_var (). */
@@ -5037,7 +5052,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
initialized. We do not want to issue a warning about that
uninitialized variable. */
if (DECL_P (modify_dest))
- TREE_NO_WARNING (modify_dest) = 1;
+ suppress_warning (modify_dest, OPT_Wuninitialized);
if (gimple_call_return_slot_opt_p (call_stmt))
{
@@ -5065,40 +5080,6 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
/* Add local vars in this inlined callee to caller. */
add_local_variables (id->src_cfun, cfun, id);
- info = clone_info::get (id->src_node);
- if (info && info->performed_splits)
- {
- clone_info *dst_info = clone_info::get_create (id->dst_node);
- /* Any calls from the inlined function will be turned into calls from the
- function we inline into. We must preserve notes about how to split
- parameters such calls should be redirected/updated. */
- unsigned len = vec_safe_length (info->performed_splits);
- for (unsigned i = 0; i < len; i++)
- {
- ipa_param_performed_split ps
- = (*info->performed_splits)[i];
- ps.dummy_decl = remap_decl (ps.dummy_decl, id);
- vec_safe_push (dst_info->performed_splits, ps);
- }
-
- if (flag_checking)
- {
- len = vec_safe_length (dst_info->performed_splits);
- for (unsigned i = 0; i < len; i++)
- {
- ipa_param_performed_split *ps1
- = &(*dst_info->performed_splits)[i];
- for (unsigned j = i + 1; j < len; j++)
- {
- ipa_param_performed_split *ps2
- = &(*dst_info->performed_splits)[j];
- gcc_assert (ps1->dummy_decl != ps2->dummy_decl
- || ps1->unit_offset != ps2->unit_offset);
- }
- }
- }
- }
-
if (dump_enabled_p ())
{
char buf[128];
@@ -5128,8 +5109,13 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
for (tree p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
if (!TREE_THIS_VOLATILE (p))
{
+ /* The value associated with P is a local temporary only if
+ there is no value associated with P in the debug map. */
tree *varp = id->decl_map->get (p);
- if (varp && VAR_P (*varp) && !is_gimple_reg (*varp))
+ if (varp
+ && VAR_P (*varp)
+ && !is_gimple_reg (*varp)
+ && !(id->debug_map && id->debug_map->get (p)))
{
tree clobber = build_clobber (TREE_TYPE (*varp));
gimple *clobber_stmt;
@@ -6117,23 +6103,10 @@ tree_versionable_function_p (tree fndecl)
static void
update_clone_info (copy_body_data * id)
{
- clone_info *dst_info = clone_info::get (id->dst_node);
- vec<ipa_param_performed_split, va_gc> *cur_performed_splits
- = dst_info ? dst_info->performed_splits : NULL;
- if (cur_performed_splits)
- {
- unsigned len = cur_performed_splits->length ();
- for (unsigned i = 0; i < len; i++)
- {
- ipa_param_performed_split *ps = &(*cur_performed_splits)[i];
- ps->dummy_decl = remap_decl (ps->dummy_decl, id);
- }
- }
-
- struct cgraph_node *node;
- if (!id->dst_node->clones)
+ struct cgraph_node *this_node = id->dst_node;
+ if (!this_node->clones)
return;
- for (node = id->dst_node->clones; node != id->dst_node;)
+ for (cgraph_node *node = this_node->clones; node != this_node;)
{
/* First update replace maps to match the new body. */
clone_info *info = clone_info::get (node);
@@ -6147,53 +6120,6 @@ update_clone_info (copy_body_data * id)
walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
}
}
- if (info && info->performed_splits)
- {
- unsigned len = vec_safe_length (info->performed_splits);
- for (unsigned i = 0; i < len; i++)
- {
- ipa_param_performed_split *ps
- = &(*info->performed_splits)[i];
- ps->dummy_decl = remap_decl (ps->dummy_decl, id);
- }
- }
- if (unsigned len = vec_safe_length (cur_performed_splits))
- {
- /* We do not want to add current performed splits when we are saving
- a copy of function body for later during inlining, that would just
- duplicate all entries. So let's have a look whether anything
- referring to the first dummy_decl is present. */
- if (!info)
- info = clone_info::get_create (node);
- unsigned dst_len = vec_safe_length (info->performed_splits);
- ipa_param_performed_split *first = &(*cur_performed_splits)[0];
- for (unsigned i = 0; i < dst_len; i++)
- if ((*info->performed_splits)[i].dummy_decl
- == first->dummy_decl)
- {
- len = 0;
- break;
- }
-
- for (unsigned i = 0; i < len; i++)
- vec_safe_push (info->performed_splits,
- (*cur_performed_splits)[i]);
- if (flag_checking)
- {
- for (unsigned i = 0; i < dst_len; i++)
- {
- ipa_param_performed_split *ps1
- = &(*info->performed_splits)[i];
- for (unsigned j = i + 1; j < dst_len; j++)
- {
- ipa_param_performed_split *ps2
- = &(*info->performed_splits)[j];
- gcc_assert (ps1->dummy_decl != ps2->dummy_decl
- || ps1->unit_offset != ps2->unit_offset);
- }
- }
- }
- }
if (node->clones)
node = node->clones;
@@ -6381,6 +6307,8 @@ tree_function_versioning (tree old_decl, tree new_decl,
tree resdecl_repl = copy_result_decl_to_var (DECL_RESULT (old_decl),
&id);
declare_inline_vars (NULL, resdecl_repl);
+ if (DECL_BY_REFERENCE (DECL_RESULT (old_decl)))
+ resdecl_repl = build_fold_addr_expr (resdecl_repl);
insert_decl_map (&id, DECL_RESULT (old_decl), resdecl_repl);
DECL_RESULT (new_decl)