diff options
author | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2021-09-13 10:37:49 -0700 |
commit | e252b51ccde010cbd2a146485d8045103cd99533 (patch) | |
tree | e060f101cdc32bf5e520de8e5275db9d4236b74c /gcc/tree-inline.c | |
parent | f10c7c4596dda99d2ee872c995ae4aeda65adbdf (diff) | |
parent | 104c05c5284b7822d770ee51a7d91946c7e56d50 (diff) | |
download | gcc-e252b51ccde010cbd2a146485d8045103cd99533.zip gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.gz gcc-e252b51ccde010cbd2a146485d8045103cd99533.tar.bz2 |
Merge from trunk revision 104c05c5284b7822d770ee51a7d91946c7e56d50.
Diffstat (limited to 'gcc/tree-inline.c')
-rw-r--r-- | gcc/tree-inline.c | 292 |
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 (©, &extra_stmts); + id->param_body_adjs->modify_gimple_stmt (©, &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) |