New IPA-SRA
2019-09-20 Martin Jambor <mjambor@suse.cz> * coretypes.h (cgraph_edge): Declare. * ipa-param-manipulation.c: Rewrite. * ipa-param-manipulation.h: Likewise. * Makefile.in (GTFILES): Added ipa-param-manipulation.h and ipa-sra.c. (OBJS): Added ipa-sra.o. * cgraph.h (ipa_replace_map): Removed fields old_tree, replace_p and ref_p, added fields param_adjustments and performed_splits. (struct cgraph_clone_info): Remove ags_to_skip and combined_args_to_skip, new field param_adjustments. (cgraph_node::create_clone): Changed parameters to use ipa_param_adjustments. (cgraph_node::create_virtual_clone): Likewise. (cgraph_node::create_virtual_clone_with_body): Likewise. (tree_function_versioning): Likewise. (cgraph_build_function_type_skip_args): Removed. * cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Convert to using ipa_param_adjustments. (clone_of_p): Likewise. * cgraphclones.c (cgraph_build_function_type_skip_args): Removed. (build_function_decl_skip_args): Likewise. (duplicate_thunk_for_node): Adjust parameters using ipa_param_body_adjustments, copy param_adjustments instead of args_to_skip. (cgraph_node::create_clone): Convert to using ipa_param_adjustments. (cgraph_node::create_virtual_clone): Likewise. (cgraph_node::create_version_clone_with_body): Likewise. (cgraph_materialize_clone): Likewise. (symbol_table::materialize_all_clones): Likewise. * ipa-fnsummary.c (ipa_fn_summary_t::duplicate): Simplify ipa_replace_map check. * ipa-cp.c (get_replacement_map): Do not initialize removed fields. (initialize_node_lattices): Make aware that some parameters might have already been removed. (want_remove_some_param_p): New function. (create_specialized_node): Convert to using ipa_param_adjustments and deal with possibly pre-existing adjustments. * lto-cgraph.c (output_cgraph_opt_summary_p): Likewise. (output_node_opt_summary): Do not stream removed fields. Stream parameter adjustments instead of argumetns to skip. (input_node_opt_summary): Likewise. (input_node_opt_summary): Likewise. * lto-section-in.c (lto_section_name): Added ipa-sra section. * lto-streamer.h (lto_section_type): Likewise. * tree-inline.h (copy_body_data): New fields killed_new_ssa_names and param_body_adjs. (copy_decl_to_var): Declare. * tree-inline.c (update_clone_info): Do not remap old_tree. (remap_gimple_stmt): Use ipa_param_body_adjustments to modify gimple statements, walk all extra generated statements and remap their operands. (redirect_all_calls): Add killed SSA names to a hash set. (remap_ssa_name): Do not remap killed SSA names. (copy_arguments_for_versioning): Renames to copy_arguments_nochange, half of functionality moved to ipa_param_body_adjustments. (copy_decl_to_var): Make exported. (copy_body): Destroy killed_new_ssa_names hash set. (expand_call_inline): Remap performed splits. (update_clone_info): Likewise. (tree_function_versioning): Simplify tree_map processing. Updated to accept ipa_param_adjustments and use ipa_param_body_adjustments. * omp-simd-clone.c (simd_clone_vector_of_formal_parm_types): Adjust for the new interface. (simd_clone_clauses_extract): Likewise, make args an auto_vec. (simd_clone_compute_base_data_type): Likewise. (simd_clone_init_simd_arrays): Adjust for the new interface. (simd_clone_adjust_argument_types): Likewise. (struct modify_stmt_info): Likewise. (ipa_simd_modify_stmt_ops): Likewise. (ipa_simd_modify_function_body): Likewise. (simd_clone_adjust): Likewise. * tree-sra.c: Removed IPA-SRA. Include tree-sra.h. (type_internals_preclude_sra_p): Make public. * tree-sra.h: New file. * ipa-inline-transform.c (save_inline_function_body): Update to refelct new tree_function_versioning signature. * ipa-prop.c (adjust_agg_replacement_values): Use a helper from ipa_param_adjustments to get current parameter indices. (ipcp_modif_dom_walker::before_dom_children): Likewise. (ipcp_update_bits): Likewise. (ipcp_update_vr): Likewise. * ipa-split.c (split_function): Convert to using ipa_param_adjustments. * ipa-sra.c: New file. * multiple_target.c (create_target_clone): Update to reflet new type of create_version_clone_with_body. * trans-mem.c (ipa_tm_create_version): Update to reflect new type of tree_function_versioning. (modify_function): Update to reflect new type of tree_function_versioning. * params.def (PARAM_IPA_SRA_MAX_REPLACEMENTS): New. * passes.def: Remove old IPA-SRA and add new one. * tree-pass.h (make_pass_early_ipa_sra): Remove declaration. (make_pass_ipa_sra): Declare. * dbgcnt.def: Remove eipa_sra. Added ipa_sra_params and ipa_sra_retvalues. * doc/invoke.texi (ipa-sra-max-replacements): New. testsuite/ * g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan. * gcc.dg/ipa/ipa-sra-1.c: Likewise. * gcc.dg/ipa/ipa-sra-10.c: Likewise. * gcc.dg/ipa/ipa-sra-11.c: Likewise. * gcc.dg/ipa/ipa-sra-3.c: Likewise. * gcc.dg/ipa/ipa-sra-4.c: Likewise. * gcc.dg/ipa/ipa-sra-5.c: Likewise. * gcc.dg/ipa/ipacost-2.c: Disable ipa-sra. * gcc.dg/ipa/ipcp-agg-9.c: Likewise. * gcc.dg/ipa/pr78121.c: Adjust scan pattern. * gcc.dg/ipa/vrp1.c: Likewise. * gcc.dg/ipa/vrp2.c: Likewise. * gcc.dg/ipa/vrp3.c: Likewise. * gcc.dg/ipa/vrp7.c: Likewise. * gcc.dg/ipa/vrp8.c: Likewise. * gcc.dg/noreorder.c: use noipa attribute instead of noinline. * gcc.dg/ipa/20040703-wpa.c: New test. * gcc.dg/ipa/ipa-sra-12.c: New test. * gcc.dg/ipa/ipa-sra-13.c: Likewise. * gcc.dg/ipa/ipa-sra-14.c: Likewise. * gcc.dg/ipa/ipa-sra-15.c: Likewise. * gcc.dg/ipa/ipa-sra-16.c: Likewise. * gcc.dg/ipa/ipa-sra-17.c: Likewise. * gcc.dg/ipa/ipa-sra-18.c: Likewise. * gcc.dg/ipa/ipa-sra-19.c: Likewise. * gcc.dg/ipa/ipa-sra-20.c: Likewise. * gcc.dg/ipa/ipa-sra-21.c: Likewise. * gcc.dg/ipa/ipa-sra-22.c: Likewise. * gcc.dg/sso/ipa-sra-1.c: Likewise. * g++.dg/ipa/ipa-sra-2.C: Likewise. * g++.dg/ipa/ipa-sra-3.C: Likewise. * gcc.dg/tree-ssa/ipa-cp-1.c: Make return value used. * g++.dg/ipa/devirt-19.C: Add missing return, add -fipa-cp-clone option. * g++.dg/lto/devirt-19_0.C: Add -fipa-cp-clone option. * gcc.dg/ipa/ipa-sra-2.c: Removed. * gcc.dg/ipa/ipa-sra-6.c: Likewise. From-SVN: r275982
This commit is contained in:
parent
6889a3acfe
commit
ff6686d2e5
@ -1,3 +1,101 @@
|
||||
2019-09-20 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* coretypes.h (cgraph_edge): Declare.
|
||||
* ipa-param-manipulation.c: Rewrite.
|
||||
* ipa-param-manipulation.h: Likewise.
|
||||
* Makefile.in (GTFILES): Added ipa-param-manipulation.h and ipa-sra.c.
|
||||
(OBJS): Added ipa-sra.o.
|
||||
* cgraph.h (ipa_replace_map): Removed fields old_tree, replace_p
|
||||
and ref_p, added fields param_adjustments and performed_splits.
|
||||
(struct cgraph_clone_info): Remove ags_to_skip and
|
||||
combined_args_to_skip, new field param_adjustments.
|
||||
(cgraph_node::create_clone): Changed parameters to use
|
||||
ipa_param_adjustments.
|
||||
(cgraph_node::create_virtual_clone): Likewise.
|
||||
(cgraph_node::create_virtual_clone_with_body): Likewise.
|
||||
(tree_function_versioning): Likewise.
|
||||
(cgraph_build_function_type_skip_args): Removed.
|
||||
* cgraph.c (cgraph_edge::redirect_call_stmt_to_callee): Convert to
|
||||
using ipa_param_adjustments.
|
||||
(clone_of_p): Likewise.
|
||||
* cgraphclones.c (cgraph_build_function_type_skip_args): Removed.
|
||||
(build_function_decl_skip_args): Likewise.
|
||||
(duplicate_thunk_for_node): Adjust parameters using
|
||||
ipa_param_body_adjustments, copy param_adjustments instead of
|
||||
args_to_skip.
|
||||
(cgraph_node::create_clone): Convert to using ipa_param_adjustments.
|
||||
(cgraph_node::create_virtual_clone): Likewise.
|
||||
(cgraph_node::create_version_clone_with_body): Likewise.
|
||||
(cgraph_materialize_clone): Likewise.
|
||||
(symbol_table::materialize_all_clones): Likewise.
|
||||
* ipa-fnsummary.c (ipa_fn_summary_t::duplicate): Simplify
|
||||
ipa_replace_map check.
|
||||
* ipa-cp.c (get_replacement_map): Do not initialize removed fields.
|
||||
(initialize_node_lattices): Make aware that some parameters might have
|
||||
already been removed.
|
||||
(want_remove_some_param_p): New function.
|
||||
(create_specialized_node): Convert to using ipa_param_adjustments and
|
||||
deal with possibly pre-existing adjustments.
|
||||
* lto-cgraph.c (output_cgraph_opt_summary_p): Likewise.
|
||||
(output_node_opt_summary): Do not stream removed fields. Stream
|
||||
parameter adjustments instead of argumetns to skip.
|
||||
(input_node_opt_summary): Likewise.
|
||||
(input_node_opt_summary): Likewise.
|
||||
* lto-section-in.c (lto_section_name): Added ipa-sra section.
|
||||
* lto-streamer.h (lto_section_type): Likewise.
|
||||
* tree-inline.h (copy_body_data): New fields killed_new_ssa_names and
|
||||
param_body_adjs.
|
||||
(copy_decl_to_var): Declare.
|
||||
* tree-inline.c (update_clone_info): Do not remap old_tree.
|
||||
(remap_gimple_stmt): Use ipa_param_body_adjustments to modify gimple
|
||||
statements, walk all extra generated statements and remap their
|
||||
operands.
|
||||
(redirect_all_calls): Add killed SSA names to a hash set.
|
||||
(remap_ssa_name): Do not remap killed SSA names.
|
||||
(copy_arguments_for_versioning): Renames to copy_arguments_nochange,
|
||||
half of functionality moved to ipa_param_body_adjustments.
|
||||
(copy_decl_to_var): Make exported.
|
||||
(copy_body): Destroy killed_new_ssa_names hash set.
|
||||
(expand_call_inline): Remap performed splits.
|
||||
(update_clone_info): Likewise.
|
||||
(tree_function_versioning): Simplify tree_map processing. Updated to
|
||||
accept ipa_param_adjustments and use ipa_param_body_adjustments.
|
||||
* omp-simd-clone.c (simd_clone_vector_of_formal_parm_types): Adjust
|
||||
for the new interface.
|
||||
(simd_clone_clauses_extract): Likewise, make args an auto_vec.
|
||||
(simd_clone_compute_base_data_type): Likewise.
|
||||
(simd_clone_init_simd_arrays): Adjust for the new interface.
|
||||
(simd_clone_adjust_argument_types): Likewise.
|
||||
(struct modify_stmt_info): Likewise.
|
||||
(ipa_simd_modify_stmt_ops): Likewise.
|
||||
(ipa_simd_modify_function_body): Likewise.
|
||||
(simd_clone_adjust): Likewise.
|
||||
* tree-sra.c: Removed IPA-SRA. Include tree-sra.h.
|
||||
(type_internals_preclude_sra_p): Make public.
|
||||
* tree-sra.h: New file.
|
||||
* ipa-inline-transform.c (save_inline_function_body): Update to
|
||||
refelct new tree_function_versioning signature.
|
||||
* ipa-prop.c (adjust_agg_replacement_values): Use a helper from
|
||||
ipa_param_adjustments to get current parameter indices.
|
||||
(ipcp_modif_dom_walker::before_dom_children): Likewise.
|
||||
(ipcp_update_bits): Likewise.
|
||||
(ipcp_update_vr): Likewise.
|
||||
* ipa-split.c (split_function): Convert to using ipa_param_adjustments.
|
||||
* ipa-sra.c: New file.
|
||||
* multiple_target.c (create_target_clone): Update to reflet new type
|
||||
of create_version_clone_with_body.
|
||||
* trans-mem.c (ipa_tm_create_version): Update to reflect new type of
|
||||
tree_function_versioning.
|
||||
(modify_function): Update to reflect new type of
|
||||
tree_function_versioning.
|
||||
* params.def (PARAM_IPA_SRA_MAX_REPLACEMENTS): New.
|
||||
* passes.def: Remove old IPA-SRA and add new one.
|
||||
* tree-pass.h (make_pass_early_ipa_sra): Remove declaration.
|
||||
(make_pass_ipa_sra): Declare.
|
||||
* dbgcnt.def: Remove eipa_sra. Added ipa_sra_params and
|
||||
ipa_sra_retvalues.
|
||||
* doc/invoke.texi (ipa-sra-max-replacements): New.
|
||||
|
||||
2019-09-19 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91631
|
||||
|
@ -1368,6 +1368,7 @@ OBJS = \
|
||||
init-regs.o \
|
||||
internal-fn.o \
|
||||
ipa-cp.o \
|
||||
ipa-sra.o \
|
||||
ipa-devirt.o \
|
||||
ipa-fnsummary.o \
|
||||
ipa-polymorphic-call.o \
|
||||
@ -2527,7 +2528,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
||||
$(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \
|
||||
$(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \
|
||||
$(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \
|
||||
$(srcdir)/dbxout.c \
|
||||
$(srcdir)/ipa-param-manipulation.h $(srcdir)/ipa-sra.c $(srcdir)/dbxout.c \
|
||||
$(srcdir)/signop.h \
|
||||
$(srcdir)/dwarf2out.h \
|
||||
$(srcdir)/dwarf2asm.c \
|
||||
|
127
gcc/cgraph.c
127
gcc/cgraph.c
@ -1342,7 +1342,7 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
|
||||
if (flag_checking && decl)
|
||||
{
|
||||
cgraph_node *node = cgraph_node::get (decl);
|
||||
gcc_assert (!node || !node->clone.combined_args_to_skip);
|
||||
gcc_assert (!node || !node->clone.param_adjustments);
|
||||
}
|
||||
|
||||
if (symtab->dump_file)
|
||||
@ -1350,25 +1350,36 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
|
||||
fprintf (symtab->dump_file, "updating call of %s -> %s: ",
|
||||
e->caller->dump_name (), e->callee->dump_name ());
|
||||
print_gimple_stmt (symtab->dump_file, e->call_stmt, 0, dump_flags);
|
||||
if (e->callee->clone.combined_args_to_skip)
|
||||
if (e->callee->clone.param_adjustments)
|
||||
e->callee->clone.param_adjustments->dump (symtab->dump_file);
|
||||
unsigned performed_len
|
||||
= vec_safe_length (e->caller->clone.performed_splits);
|
||||
if (performed_len > 0)
|
||||
fprintf (symtab->dump_file, "Performed splits records:\n");
|
||||
for (unsigned i = 0; i < performed_len; i++)
|
||||
{
|
||||
fprintf (symtab->dump_file, " combined args to skip: ");
|
||||
dump_bitmap (symtab->dump_file,
|
||||
e->callee->clone.combined_args_to_skip);
|
||||
ipa_param_performed_split *sm
|
||||
= &(*e->caller->clone.performed_splits)[i];
|
||||
print_node_brief (symtab->dump_file, " dummy_decl: ", sm->dummy_decl,
|
||||
TDF_UID);
|
||||
fprintf (symtab->dump_file, ", unit_offset: %u\n", sm->unit_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (e->callee->clone.combined_args_to_skip)
|
||||
if (ipa_param_adjustments *padjs = e->callee->clone.param_adjustments)
|
||||
{
|
||||
int lp_nr;
|
||||
/* We need to defer cleaning EH info on the new statement to
|
||||
fixup-cfg. We may not have dominator information at this point
|
||||
and thus would end up with unreachable blocks and have no way
|
||||
to communicate that we need to run CFG cleanup then. */
|
||||
int lp_nr = lookup_stmt_eh_lp (e->call_stmt);
|
||||
if (lp_nr != 0)
|
||||
remove_stmt_from_eh_lp (e->call_stmt);
|
||||
|
||||
new_stmt = e->call_stmt;
|
||||
if (e->callee->clone.combined_args_to_skip)
|
||||
new_stmt
|
||||
= gimple_call_copy_skip_args (new_stmt,
|
||||
e->callee->clone.combined_args_to_skip);
|
||||
tree old_fntype = gimple_call_fntype (e->call_stmt);
|
||||
gimple_call_set_fndecl (new_stmt, e->callee->decl);
|
||||
new_stmt = padjs->modify_call (e->call_stmt,
|
||||
e->caller->clone.performed_splits,
|
||||
e->callee->decl, false);
|
||||
cgraph_node *origin = e->callee;
|
||||
while (origin->clone_of)
|
||||
origin = origin->clone_of;
|
||||
@ -1379,92 +1390,12 @@ cgraph_edge::redirect_call_stmt_to_callee (void)
|
||||
gimple_call_set_fntype (new_stmt, TREE_TYPE (e->callee->decl));
|
||||
else
|
||||
{
|
||||
bitmap skip = e->callee->clone.combined_args_to_skip;
|
||||
tree t = cgraph_build_function_type_skip_args (old_fntype, skip,
|
||||
false);
|
||||
gimple_call_set_fntype (new_stmt, t);
|
||||
tree new_fntype = padjs->build_new_function_type (old_fntype, true);
|
||||
gimple_call_set_fntype (new_stmt, new_fntype);
|
||||
}
|
||||
|
||||
if (gimple_vdef (new_stmt)
|
||||
&& TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME)
|
||||
SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
|
||||
|
||||
gsi = gsi_for_stmt (e->call_stmt);
|
||||
|
||||
/* For optimized away parameters, add on the caller side
|
||||
before the call
|
||||
DEBUG D#X => parm_Y(D)
|
||||
stmts and associate D#X with parm in decl_debug_args_lookup
|
||||
vector to say for debug info that if parameter parm had been passed,
|
||||
it would have value parm_Y(D). */
|
||||
if (e->callee->clone.combined_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
|
||||
{
|
||||
vec<tree, va_gc> **debug_args
|
||||
= decl_debug_args_lookup (e->callee->decl);
|
||||
tree old_decl = gimple_call_fndecl (e->call_stmt);
|
||||
if (debug_args && old_decl)
|
||||
{
|
||||
tree parm;
|
||||
unsigned i = 0, num;
|
||||
unsigned len = vec_safe_length (*debug_args);
|
||||
unsigned nargs = gimple_call_num_args (e->call_stmt);
|
||||
for (parm = DECL_ARGUMENTS (old_decl), num = 0;
|
||||
parm && num < nargs;
|
||||
parm = DECL_CHAIN (parm), num++)
|
||||
if (bitmap_bit_p (e->callee->clone.combined_args_to_skip, num)
|
||||
&& is_gimple_reg (parm))
|
||||
{
|
||||
unsigned last = i;
|
||||
|
||||
while (i < len && (**debug_args)[i] != DECL_ORIGIN (parm))
|
||||
i += 2;
|
||||
if (i >= len)
|
||||
{
|
||||
i = 0;
|
||||
while (i < last
|
||||
&& (**debug_args)[i] != DECL_ORIGIN (parm))
|
||||
i += 2;
|
||||
if (i >= last)
|
||||
continue;
|
||||
}
|
||||
tree ddecl = (**debug_args)[i + 1];
|
||||
tree arg = gimple_call_arg (e->call_stmt, num);
|
||||
if (!useless_type_conversion_p (TREE_TYPE (ddecl),
|
||||
TREE_TYPE (arg)))
|
||||
{
|
||||
tree rhs1;
|
||||
if (!fold_convertible_p (TREE_TYPE (ddecl), arg))
|
||||
continue;
|
||||
if (TREE_CODE (arg) == SSA_NAME
|
||||
&& gimple_assign_cast_p (SSA_NAME_DEF_STMT (arg))
|
||||
&& (rhs1
|
||||
= gimple_assign_rhs1 (SSA_NAME_DEF_STMT (arg)))
|
||||
&& useless_type_conversion_p (TREE_TYPE (ddecl),
|
||||
TREE_TYPE (rhs1)))
|
||||
arg = rhs1;
|
||||
else
|
||||
arg = fold_convert (TREE_TYPE (ddecl), arg);
|
||||
}
|
||||
|
||||
gimple *def_temp
|
||||
= gimple_build_debug_bind (ddecl, unshare_expr (arg),
|
||||
e->call_stmt);
|
||||
gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gsi_replace (&gsi, new_stmt, false);
|
||||
/* We need to defer cleaning EH info on the new statement to
|
||||
fixup-cfg. We may not have dominator information at this point
|
||||
and thus would end up with unreachable blocks and have no way
|
||||
to communicate that we need to run CFG cleanup then. */
|
||||
lp_nr = lookup_stmt_eh_lp (e->call_stmt);
|
||||
if (lp_nr != 0)
|
||||
{
|
||||
remove_stmt_from_eh_lp (e->call_stmt);
|
||||
add_stmt_to_eh_lp (new_stmt, lp_nr);
|
||||
}
|
||||
add_stmt_to_eh_lp (new_stmt, lp_nr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3014,8 +2945,8 @@ clone_of_p (cgraph_node *node, cgraph_node *node2)
|
||||
return true;
|
||||
node = node->callees->callee->ultimate_alias_target ();
|
||||
|
||||
if (!node2->clone.args_to_skip
|
||||
|| !bitmap_bit_p (node2->clone.args_to_skip, 0))
|
||||
if (!node2->clone.param_adjustments
|
||||
|| node2->clone.param_adjustments->first_param_intact_p ())
|
||||
return false;
|
||||
if (node2->former_clone_of == node->decl)
|
||||
return true;
|
||||
|
45
gcc/cgraph.h
45
gcc/cgraph.h
@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "profile-count.h"
|
||||
#include "ipa-ref.h"
|
||||
#include "plugin-api.h"
|
||||
#include "ipa-param-manipulation.h"
|
||||
|
||||
extern void debuginfo_early_init (void);
|
||||
extern void debuginfo_init (void);
|
||||
@ -740,23 +741,31 @@ struct GTY(()) cgraph_global_info {
|
||||
will be replaced by another tree while versioning. */
|
||||
struct GTY(()) ipa_replace_map
|
||||
{
|
||||
/* The tree that will be replaced. */
|
||||
tree old_tree;
|
||||
/* The new (replacing) tree. */
|
||||
tree new_tree;
|
||||
/* Parameter number to replace, when old_tree is NULL. */
|
||||
int parm_num;
|
||||
/* True when a substitution should be done, false otherwise. */
|
||||
bool replace_p;
|
||||
/* True when we replace a reference to old_tree. */
|
||||
bool ref_p;
|
||||
};
|
||||
|
||||
struct GTY(()) cgraph_clone_info
|
||||
{
|
||||
/* Constants discovered by IPA-CP, i.e. which parameter should be replaced
|
||||
with what. */
|
||||
vec<ipa_replace_map *, va_gc> *tree_map;
|
||||
bitmap args_to_skip;
|
||||
bitmap combined_args_to_skip;
|
||||
/* Parameter modification that IPA-SRA decided to perform. */
|
||||
ipa_param_adjustments *param_adjustments;
|
||||
/* Lists of dummy-decl and offset pairs representing split formal parameters
|
||||
in the caller. Offsets of all new replacements are enumerated, those
|
||||
coming from the same original parameter have the same dummy decl stored
|
||||
along with them.
|
||||
|
||||
Dummy decls sit in call statement arguments followed by new parameter
|
||||
decls (or their SSA names) in between (caller) clone materialization and
|
||||
call redirection. Redirection then recognizes the dummy variable and
|
||||
together with the stored offsets can reconstruct what exactly the new
|
||||
parameter decls represent and can leave in place only those that the
|
||||
callee expects. */
|
||||
vec<ipa_param_performed_split, va_gc> *performed_splits;
|
||||
};
|
||||
|
||||
enum cgraph_simd_clone_arg_type
|
||||
@ -976,15 +985,16 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
|
||||
vec<cgraph_edge *> redirect_callers,
|
||||
bool call_duplication_hook,
|
||||
cgraph_node *new_inlined_to,
|
||||
bitmap args_to_skip, const char *suffix = NULL);
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
const char *suffix = NULL);
|
||||
|
||||
/* Create callgraph node clone with new declaration. The actual body will be
|
||||
copied later at compilation stage. The name of the new clone will be
|
||||
constructed from the name of the original node, SUFFIX and NUM_SUFFIX. */
|
||||
cgraph_node *create_virtual_clone (vec<cgraph_edge *> redirect_callers,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map,
|
||||
bitmap args_to_skip, const char * suffix,
|
||||
unsigned num_suffix);
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
const char * suffix, unsigned num_suffix);
|
||||
|
||||
/* cgraph node being removed from symbol table; see if its entry can be
|
||||
replaced by other inline clone. */
|
||||
@ -1033,9 +1043,10 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
|
||||
Return the new version's cgraph node. */
|
||||
cgraph_node *create_version_clone_with_body
|
||||
(vec<cgraph_edge *> redirect_callers,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map, bitmap args_to_skip,
|
||||
bool skip_return, bitmap bbs_to_copy, basic_block new_entry_block,
|
||||
const char *clone_name, tree target_attributes = NULL_TREE);
|
||||
vec<ipa_replace_map *, va_gc> *tree_map,
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
bitmap bbs_to_copy, basic_block new_entry_block, const char *clone_name,
|
||||
tree target_attributes = NULL_TREE);
|
||||
|
||||
/* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
|
||||
corresponding to cgraph_node. */
|
||||
@ -2459,14 +2470,12 @@ tree clone_function_name (tree decl, const char *suffix,
|
||||
tree clone_function_name (tree decl, const char *suffix);
|
||||
|
||||
void tree_function_versioning (tree, tree, vec<ipa_replace_map *, va_gc> *,
|
||||
bool, bitmap, bool, bitmap, basic_block);
|
||||
ipa_param_adjustments *,
|
||||
bool, bitmap, basic_block);
|
||||
|
||||
void dump_callgraph_transformation (const cgraph_node *original,
|
||||
const cgraph_node *clone,
|
||||
const char *suffix);
|
||||
tree cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
|
||||
bool skip_return);
|
||||
|
||||
/* In cgraphbuild.c */
|
||||
int compute_call_stmt_bb_frequency (tree, basic_block bb);
|
||||
void record_references_in_initializer (tree, bool);
|
||||
|
@ -142,96 +142,6 @@ cgraph_edge::clone (cgraph_node *n, gcall *call_stmt, unsigned stmt_uid,
|
||||
return new_edge;
|
||||
}
|
||||
|
||||
/* Build variant of function type ORIG_TYPE skipping ARGS_TO_SKIP and the
|
||||
return value if SKIP_RETURN is true. */
|
||||
|
||||
tree
|
||||
cgraph_build_function_type_skip_args (tree orig_type, bitmap args_to_skip,
|
||||
bool skip_return)
|
||||
{
|
||||
tree new_type = NULL;
|
||||
tree args, new_args = NULL;
|
||||
tree new_reversed;
|
||||
int i = 0;
|
||||
|
||||
for (args = TYPE_ARG_TYPES (orig_type); args && args != void_list_node;
|
||||
args = TREE_CHAIN (args), i++)
|
||||
if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
|
||||
new_args = tree_cons (NULL_TREE, TREE_VALUE (args), new_args);
|
||||
|
||||
new_reversed = nreverse (new_args);
|
||||
if (args)
|
||||
{
|
||||
if (new_reversed)
|
||||
TREE_CHAIN (new_args) = void_list_node;
|
||||
else
|
||||
new_reversed = void_list_node;
|
||||
}
|
||||
|
||||
/* Use copy_node to preserve as much as possible from original type
|
||||
(debug info, attribute lists etc.)
|
||||
Exception is METHOD_TYPEs must have THIS argument.
|
||||
When we are asked to remove it, we need to build new FUNCTION_TYPE
|
||||
instead. */
|
||||
if (TREE_CODE (orig_type) != METHOD_TYPE
|
||||
|| !args_to_skip
|
||||
|| !bitmap_bit_p (args_to_skip, 0))
|
||||
{
|
||||
new_type = build_distinct_type_copy (orig_type);
|
||||
TYPE_ARG_TYPES (new_type) = new_reversed;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_type
|
||||
= build_distinct_type_copy (build_function_type (TREE_TYPE (orig_type),
|
||||
new_reversed));
|
||||
TYPE_CONTEXT (new_type) = TYPE_CONTEXT (orig_type);
|
||||
}
|
||||
|
||||
if (skip_return)
|
||||
TREE_TYPE (new_type) = void_type_node;
|
||||
|
||||
return new_type;
|
||||
}
|
||||
|
||||
/* Build variant of function decl ORIG_DECL skipping ARGS_TO_SKIP and the
|
||||
return value if SKIP_RETURN is true.
|
||||
|
||||
Arguments from DECL_ARGUMENTS list can't be removed now, since they are
|
||||
linked by TREE_CHAIN directly. The caller is responsible for eliminating
|
||||
them when they are being duplicated (i.e. copy_arguments_for_versioning). */
|
||||
|
||||
static tree
|
||||
build_function_decl_skip_args (tree orig_decl, bitmap args_to_skip,
|
||||
bool skip_return)
|
||||
{
|
||||
tree new_decl = copy_node (orig_decl);
|
||||
tree new_type;
|
||||
|
||||
new_type = TREE_TYPE (orig_decl);
|
||||
if (prototype_p (new_type)
|
||||
|| (skip_return && !VOID_TYPE_P (TREE_TYPE (new_type))))
|
||||
new_type
|
||||
= cgraph_build_function_type_skip_args (new_type, args_to_skip,
|
||||
skip_return);
|
||||
TREE_TYPE (new_decl) = new_type;
|
||||
|
||||
/* For declarations setting DECL_VINDEX (i.e. methods)
|
||||
we expect first argument to be THIS pointer. */
|
||||
if (args_to_skip && bitmap_bit_p (args_to_skip, 0))
|
||||
DECL_VINDEX (new_decl) = NULL_TREE;
|
||||
|
||||
/* When signature changes, we need to clear builtin info. */
|
||||
if (fndecl_built_in_p (new_decl)
|
||||
&& args_to_skip
|
||||
&& !bitmap_empty_p (args_to_skip))
|
||||
set_decl_built_in_function (new_decl, NOT_BUILT_IN, 0);
|
||||
/* The FE might have information and assumptions about the other
|
||||
arguments. */
|
||||
DECL_LANG_SPECIFIC (new_decl) = NULL;
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
/* Set flags of NEW_NODE and its decl. NEW_NODE is a newly created private
|
||||
clone or its thunk. */
|
||||
|
||||
@ -281,35 +191,21 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
|
||||
return cs->caller;
|
||||
|
||||
tree new_decl;
|
||||
if (!node->clone.args_to_skip)
|
||||
new_decl = copy_node (thunk->decl);
|
||||
else
|
||||
if (node->clone.param_adjustments)
|
||||
{
|
||||
/* We do not need to duplicate this_adjusting thunks if we have removed
|
||||
this. */
|
||||
if (thunk->thunk.this_adjusting
|
||||
&& bitmap_bit_p (node->clone.args_to_skip, 0))
|
||||
&& !node->clone.param_adjustments->first_param_intact_p ())
|
||||
return node;
|
||||
|
||||
new_decl = build_function_decl_skip_args (thunk->decl,
|
||||
node->clone.args_to_skip,
|
||||
false);
|
||||
new_decl = copy_node (thunk->decl);
|
||||
ipa_param_body_adjustments body_adj (node->clone.param_adjustments,
|
||||
new_decl);
|
||||
body_adj.modify_formal_parameters ();
|
||||
}
|
||||
|
||||
tree *link = &DECL_ARGUMENTS (new_decl);
|
||||
int i = 0;
|
||||
for (tree pd = DECL_ARGUMENTS (thunk->decl); pd; pd = DECL_CHAIN (pd), i++)
|
||||
{
|
||||
if (!node->clone.args_to_skip
|
||||
|| !bitmap_bit_p (node->clone.args_to_skip, i))
|
||||
{
|
||||
tree nd = copy_node (pd);
|
||||
DECL_CONTEXT (nd) = new_decl;
|
||||
*link = nd;
|
||||
link = &DECL_CHAIN (nd);
|
||||
}
|
||||
}
|
||||
*link = NULL_TREE;
|
||||
else
|
||||
new_decl = copy_node (thunk->decl);
|
||||
|
||||
gcc_checking_assert (!DECL_STRUCT_FUNCTION (new_decl));
|
||||
gcc_checking_assert (!DECL_INITIAL (new_decl));
|
||||
@ -331,8 +227,7 @@ duplicate_thunk_for_node (cgraph_node *thunk, cgraph_node *node)
|
||||
new_thunk->thunk = thunk->thunk;
|
||||
new_thunk->unique_name = in_lto_p;
|
||||
new_thunk->former_clone_of = thunk->decl;
|
||||
new_thunk->clone.args_to_skip = node->clone.args_to_skip;
|
||||
new_thunk->clone.combined_args_to_skip = node->clone.combined_args_to_skip;
|
||||
new_thunk->clone.param_adjustments = node->clone.param_adjustments;
|
||||
|
||||
cgraph_edge *e = new_thunk->create_edge (node, NULL, new_thunk->count);
|
||||
symtab->call_edge_duplication_hooks (thunk->callees, e);
|
||||
@ -415,7 +310,11 @@ dump_callgraph_transformation (const cgraph_node *original,
|
||||
If the new node is being inlined into another one, NEW_INLINED_TO should be
|
||||
the outline function the new one is (even indirectly) inlined to. All hooks
|
||||
will see this in node's global.inlined_to, when invoked. Can be NULL if the
|
||||
node is not inlined. */
|
||||
node is not inlined.
|
||||
|
||||
If PARAM_ADJUSTMENTS is non-NULL, the parameter manipulation information
|
||||
will be overwritten by the new structure. Otherwise the new node will
|
||||
share parameter manipulation information with the original node. */
|
||||
|
||||
cgraph_node *
|
||||
cgraph_node::create_clone (tree new_decl, profile_count prof_count,
|
||||
@ -423,7 +322,8 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count,
|
||||
vec<cgraph_edge *> redirect_callers,
|
||||
bool call_duplication_hook,
|
||||
cgraph_node *new_inlined_to,
|
||||
bitmap args_to_skip, const char *suffix)
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
const char *suffix)
|
||||
{
|
||||
cgraph_node *new_node = symtab->create_empty ();
|
||||
cgraph_edge *e;
|
||||
@ -467,19 +367,13 @@ cgraph_node::create_clone (tree new_decl, profile_count prof_count,
|
||||
new_node->merged_comdat = merged_comdat;
|
||||
new_node->thunk = thunk;
|
||||
|
||||
new_node->clone.tree_map = NULL;
|
||||
new_node->clone.args_to_skip = args_to_skip;
|
||||
new_node->split_part = split_part;
|
||||
if (!args_to_skip)
|
||||
new_node->clone.combined_args_to_skip = clone.combined_args_to_skip;
|
||||
else if (clone.combined_args_to_skip)
|
||||
{
|
||||
new_node->clone.combined_args_to_skip = BITMAP_GGC_ALLOC ();
|
||||
bitmap_ior (new_node->clone.combined_args_to_skip,
|
||||
clone.combined_args_to_skip, args_to_skip);
|
||||
}
|
||||
if (param_adjustments)
|
||||
new_node->clone.param_adjustments = param_adjustments;
|
||||
else
|
||||
new_node->clone.combined_args_to_skip = args_to_skip;
|
||||
new_node->clone.param_adjustments = clone.param_adjustments;
|
||||
new_node->clone.tree_map = NULL;
|
||||
new_node->clone.performed_splits = vec_safe_copy (clone.performed_splits);
|
||||
new_node->split_part = split_part;
|
||||
|
||||
FOR_EACH_VEC_ELT (redirect_callers, i, e)
|
||||
{
|
||||
@ -621,8 +515,8 @@ clone_function_name (tree decl, const char *suffix)
|
||||
cgraph_node *
|
||||
cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map,
|
||||
bitmap args_to_skip, const char * suffix,
|
||||
unsigned num_suffix)
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
const char * suffix, unsigned num_suffix)
|
||||
{
|
||||
tree old_decl = decl;
|
||||
cgraph_node *new_node = NULL;
|
||||
@ -632,13 +526,16 @@ cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
|
||||
char *name;
|
||||
|
||||
gcc_checking_assert (local.versionable);
|
||||
gcc_assert (local.can_change_signature || !args_to_skip);
|
||||
/* TODO: It would be nice if we could recognize that param_adjustments do not
|
||||
actually perform any changes, but at the moment let's require it simply
|
||||
does not exist. */
|
||||
gcc_assert (local.can_change_signature || !param_adjustments);
|
||||
|
||||
/* Make a new FUNCTION_DECL tree node */
|
||||
if (!args_to_skip)
|
||||
if (!param_adjustments)
|
||||
new_decl = copy_node (old_decl);
|
||||
else
|
||||
new_decl = build_function_decl_skip_args (old_decl, args_to_skip, false);
|
||||
new_decl = param_adjustments->adjust_decl (old_decl);
|
||||
|
||||
/* These pointers represent function body and will be populated only when clone
|
||||
is materialized. */
|
||||
@ -662,7 +559,8 @@ cgraph_node::create_virtual_clone (vec<cgraph_edge *> redirect_callers,
|
||||
SET_DECL_RTL (new_decl, NULL);
|
||||
|
||||
new_node = create_clone (new_decl, count, false,
|
||||
redirect_callers, false, NULL, args_to_skip, suffix);
|
||||
redirect_callers, false, NULL, param_adjustments,
|
||||
suffix);
|
||||
|
||||
/* Update the properties.
|
||||
Make clone visible only within this translation unit. Make sure
|
||||
@ -1021,9 +919,10 @@ cgraph_node::create_version_clone (tree new_decl,
|
||||
cgraph_node *
|
||||
cgraph_node::create_version_clone_with_body
|
||||
(vec<cgraph_edge *> redirect_callers,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map, bitmap args_to_skip,
|
||||
bool skip_return, bitmap bbs_to_copy, basic_block new_entry_block,
|
||||
const char *suffix, tree target_attributes)
|
||||
vec<ipa_replace_map *, va_gc> *tree_map,
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
bitmap bbs_to_copy, basic_block new_entry_block, const char *suffix,
|
||||
tree target_attributes)
|
||||
{
|
||||
tree old_decl = decl;
|
||||
cgraph_node *new_version_node = NULL;
|
||||
@ -1032,14 +931,16 @@ cgraph_node::create_version_clone_with_body
|
||||
if (!tree_versionable_function_p (old_decl))
|
||||
return NULL;
|
||||
|
||||
gcc_assert (local.can_change_signature || !args_to_skip);
|
||||
/* TODO: Restore an assert that we do not change signature if
|
||||
local.can_change_signature is false. We cannot just check that
|
||||
param_adjustments is NULL because unfortunately ipa-split removes return
|
||||
values from such functions. */
|
||||
|
||||
/* Make a new FUNCTION_DECL tree node for the new version. */
|
||||
if (!args_to_skip && !skip_return)
|
||||
new_decl = copy_node (old_decl);
|
||||
if (param_adjustments)
|
||||
new_decl = param_adjustments->adjust_decl (old_decl);
|
||||
else
|
||||
new_decl
|
||||
= build_function_decl_skip_args (old_decl, args_to_skip, skip_return);
|
||||
new_decl = copy_node (old_decl);
|
||||
|
||||
/* Generate a new name for the new version. */
|
||||
DECL_NAME (new_decl) = clone_function_name_numbered (old_decl, suffix);
|
||||
@ -1076,8 +977,8 @@ cgraph_node::create_version_clone_with_body
|
||||
new_version_node->ipa_transforms_to_apply
|
||||
= ipa_transforms_to_apply.copy ();
|
||||
/* Copy the OLD_VERSION_NODE function tree to the new version. */
|
||||
tree_function_versioning (old_decl, new_decl, tree_map, false, args_to_skip,
|
||||
skip_return, bbs_to_copy, new_entry_block);
|
||||
tree_function_versioning (old_decl, new_decl, tree_map, param_adjustments,
|
||||
false, bbs_to_copy, new_entry_block);
|
||||
|
||||
/* Update the new version's properties.
|
||||
Make The new version visible only within this translation unit. Make sure
|
||||
@ -1117,9 +1018,8 @@ cgraph_materialize_clone (cgraph_node *node)
|
||||
node->former_clone_of = node->clone_of->former_clone_of;
|
||||
/* Copy the OLD_VERSION_NODE function tree to the new version. */
|
||||
tree_function_versioning (node->clone_of->decl, node->decl,
|
||||
node->clone.tree_map, true,
|
||||
node->clone.args_to_skip, false,
|
||||
NULL, NULL);
|
||||
node->clone.tree_map, node->clone.param_adjustments,
|
||||
true, NULL, NULL);
|
||||
if (symtab->dump_file)
|
||||
{
|
||||
dump_function_to_file (node->clone_of->decl, symtab->dump_file,
|
||||
@ -1194,28 +1094,15 @@ symbol_table::materialize_all_clones (void)
|
||||
{
|
||||
ipa_replace_map *replace_info;
|
||||
replace_info = (*node->clone.tree_map)[i];
|
||||
print_generic_expr (symtab->dump_file,
|
||||
replace_info->old_tree);
|
||||
fprintf (symtab->dump_file, " -> ");
|
||||
fprintf (symtab->dump_file, "%i -> ",
|
||||
(*node->clone.tree_map)[i]->parm_num);
|
||||
print_generic_expr (symtab->dump_file,
|
||||
replace_info->new_tree);
|
||||
fprintf (symtab->dump_file, "%s%s;",
|
||||
replace_info->replace_p ? "(replace)":"",
|
||||
replace_info->ref_p ? "(ref)":"");
|
||||
}
|
||||
fprintf (symtab->dump_file, "\n");
|
||||
}
|
||||
if (node->clone.args_to_skip)
|
||||
{
|
||||
fprintf (symtab->dump_file, " args_to_skip: ");
|
||||
dump_bitmap (symtab->dump_file,
|
||||
node->clone.args_to_skip);
|
||||
}
|
||||
if (node->clone.args_to_skip)
|
||||
{
|
||||
fprintf (symtab->dump_file, " combined_args_to_skip:");
|
||||
dump_bitmap (symtab->dump_file, node->clone.combined_args_to_skip);
|
||||
}
|
||||
if (node->clone.param_adjustments)
|
||||
node->clone.param_adjustments->dump (symtab->dump_file);
|
||||
}
|
||||
cgraph_materialize_clone (node);
|
||||
stabilized = false;
|
||||
|
@ -141,6 +141,7 @@ struct gomp_teams;
|
||||
struct symtab_node;
|
||||
struct cgraph_node;
|
||||
struct varpool_node;
|
||||
struct cgraph_edge;
|
||||
|
||||
union section;
|
||||
typedef union section section;
|
||||
|
@ -156,7 +156,6 @@ DEBUG_COUNTER (df_byte_scan)
|
||||
DEBUG_COUNTER (dse)
|
||||
DEBUG_COUNTER (dse1)
|
||||
DEBUG_COUNTER (dse2)
|
||||
DEBUG_COUNTER (eipa_sra)
|
||||
DEBUG_COUNTER (gcse2_delete)
|
||||
DEBUG_COUNTER (global_alloc_at_func)
|
||||
DEBUG_COUNTER (global_alloc_at_reg)
|
||||
@ -168,6 +167,8 @@ DEBUG_COUNTER (if_after_combine)
|
||||
DEBUG_COUNTER (if_after_reload)
|
||||
DEBUG_COUNTER (if_conversion)
|
||||
DEBUG_COUNTER (if_conversion_tree)
|
||||
DEBUG_COUNTER (ipa_sra_params)
|
||||
DEBUG_COUNTER (ipa_sra_retvalues)
|
||||
DEBUG_COUNTER (ira_move)
|
||||
DEBUG_COUNTER (local_alloc_for_sched)
|
||||
DEBUG_COUNTER (merged_ipa_icf)
|
||||
|
@ -11870,6 +11870,11 @@ parameters only when their cumulative size is less or equal to
|
||||
@option{ipa-sra-ptr-growth-factor} times the size of the original
|
||||
pointer parameter.
|
||||
|
||||
@item ipa-sra-max-replacements
|
||||
Maximum pieces of an aggregate that IPA-SRA tracks. As a
|
||||
consequence, it is also the maximum number of replacements of a formal
|
||||
parameter.
|
||||
|
||||
@item sra-max-scalarization-size-Ospeed
|
||||
@itemx sra-max-scalarization-size-Osize
|
||||
The two Scalar Reduction of Aggregates passes (SRA and IPA-SRA) aim to
|
||||
|
180
gcc/ipa-cp.c
180
gcc/ipa-cp.c
@ -1184,7 +1184,10 @@ initialize_node_lattices (struct cgraph_node *node)
|
||||
int i;
|
||||
|
||||
gcc_checking_assert (node->has_gimple_body_p ());
|
||||
if (node->local.local)
|
||||
|
||||
if (!ipa_get_param_count (info))
|
||||
disable = true;
|
||||
else if (node->local.local)
|
||||
{
|
||||
int caller_count = 0;
|
||||
node->call_for_symbol_thunks_and_aliases (count_callers, &caller_count,
|
||||
@ -1206,32 +1209,72 @@ initialize_node_lattices (struct cgraph_node *node)
|
||||
disable = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < ipa_get_param_count (info); i++)
|
||||
if (dump_file && (dump_flags & TDF_DETAILS)
|
||||
&& !node->alias && !node->thunk.thunk_p)
|
||||
{
|
||||
class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
|
||||
plats->m_value_range.init ();
|
||||
fprintf (dump_file, "Initializing lattices of %s\n",
|
||||
node->dump_name ());
|
||||
if (disable || variable)
|
||||
fprintf (dump_file, " Marking all lattices as %s\n",
|
||||
disable ? "BOTTOM" : "VARIABLE");
|
||||
}
|
||||
|
||||
if (disable || variable)
|
||||
auto_vec<bool, 16> surviving_params;
|
||||
bool pre_modified = false;
|
||||
if (!disable && node->clone.param_adjustments)
|
||||
{
|
||||
for (i = 0; i < ipa_get_param_count (info); i++)
|
||||
{
|
||||
class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
|
||||
if (disable)
|
||||
{
|
||||
plats->itself.set_to_bottom ();
|
||||
plats->ctxlat.set_to_bottom ();
|
||||
set_agg_lats_to_bottom (plats);
|
||||
plats->bits_lattice.set_to_bottom ();
|
||||
plats->m_value_range.set_to_bottom ();
|
||||
}
|
||||
else
|
||||
set_all_contains_variable (plats);
|
||||
}
|
||||
/* At the moment all IPA optimizations should use the number of
|
||||
parameters of the prevailing decl as the m_always_copy_start.
|
||||
Handling any other value would complicate the code below, so for the
|
||||
time bing let's only assert it is so. */
|
||||
gcc_assert ((node->clone.param_adjustments->m_always_copy_start
|
||||
== ipa_get_param_count (info))
|
||||
|| node->clone.param_adjustments->m_always_copy_start < 0);
|
||||
|
||||
pre_modified = true;
|
||||
node->clone.param_adjustments->get_surviving_params (&surviving_params);
|
||||
|
||||
if (dump_file && (dump_flags & TDF_DETAILS)
|
||||
&& !node->alias && !node->thunk.thunk_p)
|
||||
fprintf (dump_file, "Marking all lattices of %s as %s\n",
|
||||
node->dump_name (), disable ? "BOTTOM" : "VARIABLE");
|
||||
{
|
||||
bool first = true;
|
||||
for (int j = 0; j < ipa_get_param_count (info); j++)
|
||||
{
|
||||
if (j < (int) surviving_params.length ()
|
||||
&& surviving_params[j])
|
||||
continue;
|
||||
if (first)
|
||||
{
|
||||
fprintf (dump_file,
|
||||
" The following parameters are dead on arrival:");
|
||||
first = false;
|
||||
}
|
||||
fprintf (dump_file, " %u", j);
|
||||
}
|
||||
if (!first)
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ipa_get_param_count (info); i++)
|
||||
{
|
||||
ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i);
|
||||
if (disable
|
||||
|| (pre_modified && (surviving_params.length () <= (unsigned) i
|
||||
|| !surviving_params[i])))
|
||||
{
|
||||
plats->itself.set_to_bottom ();
|
||||
plats->ctxlat.set_to_bottom ();
|
||||
set_agg_lats_to_bottom (plats);
|
||||
plats->bits_lattice.set_to_bottom ();
|
||||
plats->m_value_range.set_to_bottom ();
|
||||
}
|
||||
else
|
||||
{
|
||||
plats->m_value_range.init ();
|
||||
if (variable)
|
||||
set_all_contains_variable (plats);
|
||||
}
|
||||
}
|
||||
|
||||
for (ie = node->indirect_calls; ie; ie = ie->next_callee)
|
||||
@ -3654,12 +3697,8 @@ get_replacement_map (class ipa_node_params *info, tree value, int parm_num)
|
||||
print_generic_expr (dump_file, value);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
replace_map->old_tree = NULL;
|
||||
replace_map->parm_num = parm_num;
|
||||
replace_map->new_tree = value;
|
||||
replace_map->replace_p = true;
|
||||
replace_map->ref_p = false;
|
||||
|
||||
return replace_map;
|
||||
}
|
||||
|
||||
@ -3797,6 +3836,35 @@ update_specialized_profile (struct cgraph_node *new_node,
|
||||
dump_profile_updates (orig_node, new_node);
|
||||
}
|
||||
|
||||
/* Return true if we would like to remove a parameter from NODE when cloning it
|
||||
with KNOWN_CSTS scalar constants. */
|
||||
|
||||
static bool
|
||||
want_remove_some_param_p (cgraph_node *node, vec<tree> known_csts)
|
||||
{
|
||||
auto_vec<bool, 16> surviving;
|
||||
bool filled_vec = false;
|
||||
ipa_node_params *info = IPA_NODE_REF (node);
|
||||
int i, count = ipa_get_param_count (info);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (!known_csts[i] && ipa_is_param_used (info, i))
|
||||
continue;
|
||||
|
||||
if (!filled_vec)
|
||||
{
|
||||
if (!node->clone.param_adjustments)
|
||||
return true;
|
||||
node->clone.param_adjustments->get_surviving_params (&surviving);
|
||||
filled_vec = true;
|
||||
}
|
||||
if (surviving.length() < (unsigned) i && surviving[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Create a specialized version of NODE with known constants in KNOWN_CSTS,
|
||||
known contexts in KNOWN_CONTEXTS and known aggregate values in AGGVALS and
|
||||
redirect all edges in CALLERS to it. */
|
||||
@ -3810,31 +3878,65 @@ create_specialized_node (struct cgraph_node *node,
|
||||
{
|
||||
class ipa_node_params *new_info, *info = IPA_NODE_REF (node);
|
||||
vec<ipa_replace_map *, va_gc> *replace_trees = NULL;
|
||||
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
|
||||
struct ipa_agg_replacement_value *av;
|
||||
struct cgraph_node *new_node;
|
||||
int i, count = ipa_get_param_count (info);
|
||||
bitmap args_to_skip;
|
||||
|
||||
ipa_param_adjustments *old_adjustments = node->clone.param_adjustments;
|
||||
ipa_param_adjustments *new_adjustments;
|
||||
gcc_assert (!info->ipcp_orig_node);
|
||||
gcc_assert (node->local.can_change_signature
|
||||
|| !old_adjustments);
|
||||
|
||||
if (node->local.can_change_signature)
|
||||
if (old_adjustments)
|
||||
{
|
||||
args_to_skip = BITMAP_GGC_ALLOC ();
|
||||
for (i = 0; i < count; i++)
|
||||
/* At the moment all IPA optimizations should use the number of
|
||||
parameters of the prevailing decl as the m_always_copy_start.
|
||||
Handling any other value would complicate the code below, so for the
|
||||
time bing let's only assert it is so. */
|
||||
gcc_assert (old_adjustments->m_always_copy_start == count
|
||||
|| old_adjustments->m_always_copy_start < 0);
|
||||
int old_adj_count = vec_safe_length (old_adjustments->m_adj_params);
|
||||
for (i = 0; i < old_adj_count; i++)
|
||||
{
|
||||
tree t = known_csts[i];
|
||||
ipa_adjusted_param *old_adj = &(*old_adjustments->m_adj_params)[i];
|
||||
if (!node->local.can_change_signature
|
||||
|| old_adj->op != IPA_PARAM_OP_COPY
|
||||
|| (!known_csts[old_adj->base_index]
|
||||
&& ipa_is_param_used (info, old_adj->base_index)))
|
||||
{
|
||||
ipa_adjusted_param new_adj = *old_adj;
|
||||
|
||||
if (t || !ipa_is_param_used (info, i))
|
||||
bitmap_set_bit (args_to_skip, i);
|
||||
new_adj.prev_clone_adjustment = true;
|
||||
new_adj.prev_clone_index = i;
|
||||
vec_safe_push (new_params, new_adj);
|
||||
}
|
||||
}
|
||||
bool skip_return = old_adjustments->m_skip_return;
|
||||
new_adjustments = (new (ggc_alloc <ipa_param_adjustments> ())
|
||||
ipa_param_adjustments (new_params, count,
|
||||
skip_return));
|
||||
}
|
||||
else if (node->local.can_change_signature
|
||||
&& want_remove_some_param_p (node, known_csts))
|
||||
{
|
||||
ipa_adjusted_param adj;
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
adj.op = IPA_PARAM_OP_COPY;
|
||||
for (i = 0; i < count; i++)
|
||||
if (!known_csts[i] && ipa_is_param_used (info, i))
|
||||
{
|
||||
adj.base_index = i;
|
||||
adj.prev_clone_index = i;
|
||||
vec_safe_push (new_params, adj);
|
||||
}
|
||||
new_adjustments = (new (ggc_alloc <ipa_param_adjustments> ())
|
||||
ipa_param_adjustments (new_params, count, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
args_to_skip = NULL;
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
fprintf (dump_file, " cannot change function signature\n");
|
||||
}
|
||||
new_adjustments = NULL;
|
||||
|
||||
replace_trees = vec_safe_copy (node->clone.tree_map);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
tree t = known_csts[i];
|
||||
@ -3863,7 +3965,7 @@ create_specialized_node (struct cgraph_node *node,
|
||||
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (
|
||||
node->decl)));
|
||||
new_node = node->create_virtual_clone (callers, replace_trees,
|
||||
args_to_skip, "constprop",
|
||||
new_adjustments, "constprop",
|
||||
suffix_counter);
|
||||
suffix_counter++;
|
||||
|
||||
|
@ -616,9 +616,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
|
||||
|
||||
for (j = 0; vec_safe_iterate (dst->clone.tree_map, j, &r); j++)
|
||||
{
|
||||
if (((!r->old_tree && r->parm_num == i)
|
||||
|| (r->old_tree && r->old_tree == ipa_get_param (parms_info, i)))
|
||||
&& r->replace_p && !r->ref_p)
|
||||
if (r->parm_num == i)
|
||||
{
|
||||
known_vals[i] = r->new_tree;
|
||||
break;
|
||||
|
@ -617,8 +617,7 @@ save_inline_function_body (struct cgraph_node *node)
|
||||
|
||||
/* Copy the OLD_VERSION_NODE function tree to the new version. */
|
||||
tree_function_versioning (node->decl, first_clone->decl,
|
||||
NULL, true, NULL, false,
|
||||
NULL, NULL);
|
||||
NULL, NULL, true, NULL, NULL);
|
||||
|
||||
/* The function will be short lived and removed after we inline all the clones,
|
||||
but make it internal so we won't confuse ourself. */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,101 +16,416 @@ 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/>. */
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
This file defines classes and other data structures that are used to manipulate
|
||||
the prototype of a function, especially to create, remove or split its formal
|
||||
parameters, but also to remove its return value, and also its call statements
|
||||
correspondingly.
|
||||
|
||||
The most basic one is a vector of structures ipa_adjusted_param. It is simply
|
||||
a description how the new parameters should look like after the transformation
|
||||
in what way they relate to the previous ones (if in any). Such relation to an
|
||||
old parameter can be an outright copy or an IPA-SRA replacement. If an old
|
||||
parameter is not listed or otherwise mentioned, it is removed as unused or at
|
||||
least unnecessary. Note that this most basic structure does not work for
|
||||
modifying calls of functions with variable number of arguments.
|
||||
|
||||
Class ipa_param_adjustments is only a little more than a thin encapsulation of
|
||||
a vector of ipa_param_adjustments. Along with this vector it contains an index
|
||||
of the first potential vararg argument and a boolean flag whether the return
|
||||
value should be removed or not. Moreover, the class contains method
|
||||
modify_call which can transform a call statement so that it correctly calls a
|
||||
modified function. These two data structures were designed to have a small
|
||||
memory footprint because they are allocated for each clone of a call graph node
|
||||
that has its prototype changed and live until the end of IPA clone
|
||||
materialization and call redirection phase.
|
||||
|
||||
On the other hand, class ipa_param_body_adjustments can afford to allocate more
|
||||
data because its life span is much smaller, it is allocated and destroyed in
|
||||
the course of materialization of each single clone that needs it or only when a
|
||||
particular pass needs to change a function it is operating on. This class has
|
||||
various methods required to change function declaration and the body of the
|
||||
function according to instructions given either by class ipa_param_adjustments
|
||||
or only a vector of ipa_adjusted_params.
|
||||
|
||||
When these classes are used in the context of call graph clone materialization
|
||||
and subsequent call statement redirection - which is the point at which we
|
||||
modify arguments in call statements - they need to cooperate with each other in
|
||||
order to handle what we refer to as transitive (IPA-SRA) splits. These are
|
||||
situations when a formal parameter of one function is split into several
|
||||
smaller ones and some of them are then passed on in a call to another function
|
||||
because the formal parameter of this callee has also been split.
|
||||
|
||||
Consider a simple example:
|
||||
|
||||
struct S {int a, b, c;};
|
||||
struct Z {int x; S s;};
|
||||
|
||||
foo (S s)
|
||||
{
|
||||
use (s.b);
|
||||
}
|
||||
|
||||
bar (Z z)
|
||||
{
|
||||
use (z.s.a);
|
||||
foo (z.s);
|
||||
}
|
||||
|
||||
baz ()
|
||||
{
|
||||
bar (*global);
|
||||
}
|
||||
|
||||
Both bar and foo would have their parameter split. Foo would receive one
|
||||
replacement representing s.b. Function bar would see its parameter split into
|
||||
one replacement representing z.s.a and another representing z.s.b which would
|
||||
be passed on to foo. It would be a so called transitive split IPA-SRA
|
||||
replacement, one which is passed in a call as an actual argument to another
|
||||
IPA-SRA replacement in another function.
|
||||
|
||||
Note that the call chain the example can be arbitrarily long and recursive and
|
||||
that any function in it can be cloned by another IPA pass and any number of
|
||||
adjacent functions in the call chain can be inlined into each other. Call
|
||||
redirection takes place only after bodies of the function have been modified by
|
||||
all of the above.
|
||||
|
||||
Call redirection has to be able to find the right decl or SSA_NAME that
|
||||
corresponds to the transitive split in the caller. The SSA names are assigned
|
||||
right after clone materialization/ modification and cannot be "added"
|
||||
afterwards. Moreover, if the caller has been inlined the SSA_NAMEs in question
|
||||
no longer belong to PARM_DECLs but to VAR_DECLs, indistinguishable from any
|
||||
others.
|
||||
|
||||
Therefore, when clone materialization finds a call statement which it knows is
|
||||
a part of a transitive split, it will modify it into:
|
||||
|
||||
foo (DUMMY_Z_VAR.s, repl_for_a, repl_for_b, <rest of original arguments>);
|
||||
|
||||
It will also store {DUMMY_S_VAR, 32} and {DUMMY_S_VAR, 64} representing offsets
|
||||
of z.s.a and z.s.b (assuming a 32-bit int) into foo's cgraph node
|
||||
clone->performed_splits vector (which is storing structures of type
|
||||
ipa_param_performed_split also defined in this header file).
|
||||
|
||||
Call redirection will identify that expression DUMMY_Z_VAR.s is based on a
|
||||
variable stored in performed_splits vector and learn that the following
|
||||
arguments, already in SSA form, represent offsets 32 and 64 in a split original
|
||||
parameter. It subtracts offset of DUMMY_Z_VAR.s from 32 and 64 and arrives at
|
||||
offsets 0 and 32 within callee's original parameter. At this point it also
|
||||
knows from the call graph that only the bit with offset 32 is needed and so
|
||||
changes the call statement into final:
|
||||
|
||||
bar (repl_for_b, <rest of original arguments>); */
|
||||
|
||||
#ifndef IPA_PARAM_MANIPULATION_H
|
||||
#define IPA_PARAM_MANIPULATION_H
|
||||
|
||||
/* Operation to be performed for the parameter in ipa_parm_adjustment
|
||||
below. */
|
||||
enum ipa_parm_op {
|
||||
IPA_PARM_OP_NONE,
|
||||
|
||||
/* This describes a brand new parameter.
|
||||
|
||||
The field `type' should be set to the new type, `arg_prefix'
|
||||
should be set to the string prefix for the new DECL_NAME, and
|
||||
`new_decl' will ultimately hold the newly created argument. */
|
||||
IPA_PARM_OP_NEW,
|
||||
|
||||
/* This new parameter is an unmodified parameter at index base_index. */
|
||||
IPA_PARM_OP_COPY,
|
||||
|
||||
/* This adjustment describes a parameter that is about to be removed
|
||||
completely. Most users will probably need to book keep those so that they
|
||||
don't leave behinfd any non default def ssa names belonging to them. */
|
||||
IPA_PARM_OP_REMOVE
|
||||
/* Indices into ipa_param_prefixes to identify a human-readable prefix for newly
|
||||
synthesized parameters. Keep in sync with the array. */
|
||||
enum ipa_param_name_prefix_indices
|
||||
{
|
||||
IPA_PARAM_PREFIX_SYNTH,
|
||||
IPA_PARAM_PREFIX_ISRA,
|
||||
IPA_PARAM_PREFIX_SIMD,
|
||||
IPA_PARAM_PREFIX_MASK,
|
||||
IPA_PARAM_PREFIX_COUNT
|
||||
};
|
||||
|
||||
/* Structure to describe transformations of formal parameters and actual
|
||||
arguments. Each instance describes one new parameter and they are meant to
|
||||
be stored in a vector. Additionally, most users will probably want to store
|
||||
adjustments about parameters that are being removed altogether so that SSA
|
||||
names belonging to them can be replaced by SSA names of an artificial
|
||||
variable. */
|
||||
struct ipa_parm_adjustment
|
||||
{
|
||||
/* The original PARM_DECL itself, helpful for processing of the body of the
|
||||
function itself. Intended for traversing function bodies.
|
||||
ipa_modify_formal_parameters, ipa_modify_call_arguments and
|
||||
ipa_combine_adjustments ignore this and use base_index.
|
||||
ipa_modify_formal_parameters actually sets this. */
|
||||
tree base;
|
||||
/* We do not support manipulating functions with more than
|
||||
1<<IPA_PARAM_MAX_INDEX_BITS parameters. */
|
||||
#define IPA_PARAM_MAX_INDEX_BITS 16
|
||||
|
||||
/* Type of the new parameter. However, if by_ref is true, the real type will
|
||||
be a pointer to this type. */
|
||||
/* Operation to be performed for the parameter in ipa_parm_adjustment
|
||||
below. */
|
||||
|
||||
enum ipa_parm_op
|
||||
{
|
||||
/* Do not use or you will trigger an assert. */
|
||||
IPA_PARAM_OP_UNDEFINED,
|
||||
|
||||
/* This new parameter is an unmodified parameter at index base_index. */
|
||||
IPA_PARAM_OP_COPY,
|
||||
|
||||
/* This describes a brand new parameter. If it somehow relates to any
|
||||
original parameters, the user needs to manage the transition itself. */
|
||||
IPA_PARAM_OP_NEW,
|
||||
|
||||
/* Split parameter as indicated by fields base_index, offset and type. */
|
||||
IPA_PARAM_OP_SPLIT
|
||||
};
|
||||
|
||||
/* Structure that describes one parameter of a function after transformation.
|
||||
Omitted parameters will be removed. */
|
||||
|
||||
struct GTY(()) ipa_adjusted_param
|
||||
{
|
||||
/* Type of the new parameter. Required for all operations except
|
||||
IPA_PARM_OP_COPY when the original type will be preserved. */
|
||||
tree type;
|
||||
|
||||
/* Alias refrerence type to be used in MEM_REFs when adjusting caller
|
||||
arguments. */
|
||||
/* Alias reference type to be used in MEM_REFs when adjusting caller
|
||||
arguments. Required for IPA_PARM_OP_SPLIT operation. */
|
||||
tree alias_ptr_type;
|
||||
|
||||
/* The new declaration when creating/replacing a parameter. Created
|
||||
by ipa_modify_formal_parameters, useful for functions modifying
|
||||
the body accordingly. For brand new arguments, this is the newly
|
||||
created argument. */
|
||||
tree new_decl;
|
||||
|
||||
/* New declaration of a substitute variable that we may use to replace all
|
||||
non-default-def ssa names when a parm decl is going away. */
|
||||
tree new_ssa_base;
|
||||
|
||||
/* This holds the prefix to be used for the new DECL_NAME. */
|
||||
const char *arg_prefix;
|
||||
|
||||
/* Offset into the original parameter (for the cases when the new parameter
|
||||
is a component of an original one). */
|
||||
poly_int64_pod offset;
|
||||
is a component of an original one). Required for IPA_PARM_OP_SPLIT
|
||||
operation. */
|
||||
unsigned unit_offset;
|
||||
|
||||
/* Zero based index of the original parameter this one is based on. */
|
||||
int base_index;
|
||||
/* Zero based index of the original parameter this one is based on. Required
|
||||
for IPA_PARAM_OP_COPY and IPA_PARAM_OP_SPLIT, users of IPA_PARAM_OP_NEW
|
||||
only need to specify it if they use replacement lookup provided by
|
||||
ipa_param_body_adjustments. */
|
||||
unsigned base_index : IPA_PARAM_MAX_INDEX_BITS;
|
||||
|
||||
/* Whether this parameter is a new parameter, a copy of an old one,
|
||||
or one about to be removed. */
|
||||
enum ipa_parm_op op;
|
||||
/* Zero based index of the parameter this one is based on in the previous
|
||||
clone. If there is no previous clone, it must be equal to base_index. */
|
||||
unsigned prev_clone_index : IPA_PARAM_MAX_INDEX_BITS;
|
||||
|
||||
/* Specify the operation, if any, to be performed on the parameter. */
|
||||
enum ipa_parm_op op : 2;
|
||||
|
||||
/* If set, this structure describes a parameter copied over from a previous
|
||||
IPA clone, any transformations are thus not to be re-done. */
|
||||
unsigned prev_clone_adjustment : 1;
|
||||
|
||||
/* Index into ipa_param_prefixes specifying a prefix to be used with
|
||||
DECL_NAMEs of newly synthesized parameters. */
|
||||
unsigned param_prefix_index : 2;
|
||||
|
||||
/* Storage order of the original parameter (for the cases when the new
|
||||
parameter is a component of an original one). */
|
||||
unsigned reverse : 1;
|
||||
|
||||
/* The parameter is to be passed by reference. */
|
||||
unsigned by_ref : 1;
|
||||
/* A bit free for the user. */
|
||||
unsigned user_flag : 1;
|
||||
};
|
||||
|
||||
typedef vec<ipa_parm_adjustment> ipa_parm_adjustment_vec;
|
||||
void ipa_dump_adjusted_parameters (FILE *f,
|
||||
vec<ipa_adjusted_param, va_gc> *adj_params);
|
||||
|
||||
vec<tree> ipa_get_vector_of_formal_parms (tree fndecl);
|
||||
vec<tree> ipa_get_vector_of_formal_parm_types (tree fntype);
|
||||
void ipa_modify_formal_parameters (tree fndecl, ipa_parm_adjustment_vec);
|
||||
void ipa_modify_call_arguments (struct cgraph_edge *, gcall *,
|
||||
ipa_parm_adjustment_vec);
|
||||
ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec,
|
||||
ipa_parm_adjustment_vec);
|
||||
void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree);
|
||||
/* Structure to remember the split performed on a node so that edge redirection
|
||||
(i.e. splitting arguments of call statements) know how split formal
|
||||
parameters of the caller are represented. */
|
||||
|
||||
bool ipa_modify_expr (tree *, bool, ipa_parm_adjustment_vec);
|
||||
ipa_parm_adjustment *ipa_get_adjustment_candidate (tree **, bool *,
|
||||
ipa_parm_adjustment_vec,
|
||||
bool);
|
||||
struct GTY(()) ipa_param_performed_split
|
||||
{
|
||||
/* The dummy VAR_DECL that was created instead of the split parameter that
|
||||
sits in the call in the meantime between clone materialization and call
|
||||
redirection. All entries in a vector of performed splits that correspond
|
||||
to the same dumy decl must be grouped together. */
|
||||
tree dummy_decl;
|
||||
/* Offset into the original parameter. */
|
||||
unsigned unit_offset;
|
||||
};
|
||||
|
||||
/* Class used to record planned modifications to parameters of a function and
|
||||
also to perform necessary modifications at the caller side at the gimple
|
||||
level. Used to describe all cgraph node clones that have their parameters
|
||||
changed, therefore the class should only have a small memory footprint. */
|
||||
|
||||
class GTY(()) ipa_param_adjustments
|
||||
{
|
||||
public:
|
||||
/* Constructor from NEW_PARAMS showing how new parameters should look like
|
||||
plus copying any pre-existing actual arguments starting from argument
|
||||
with index ALWAYS_COPY_START (if non-negative, negative means do not copy
|
||||
anything beyond what is described in NEW_PARAMS), and SKIP_RETURN, which
|
||||
indicates that the function should return void after transformation. */
|
||||
|
||||
ipa_param_adjustments (vec<ipa_adjusted_param, va_gc> *new_params,
|
||||
int always_copy_start, bool skip_return)
|
||||
: m_adj_params (new_params), m_always_copy_start (always_copy_start),
|
||||
m_skip_return (skip_return)
|
||||
{}
|
||||
|
||||
/* Modify a call statement arguments (and possibly remove the return value)
|
||||
as described in the data fields of this class. */
|
||||
gcall *modify_call (gcall *stmt,
|
||||
vec<ipa_param_performed_split, va_gc> *performed_splits,
|
||||
tree callee_decl, bool update_references);
|
||||
/* Return if the first parameter is left intact. */
|
||||
bool first_param_intact_p ();
|
||||
/* Build a function type corresponding to the modified call. */
|
||||
tree build_new_function_type (tree old_type, bool type_is_original_p);
|
||||
/* Build a declaration corresponding to the target of the modified call. */
|
||||
tree adjust_decl (tree orig_decl);
|
||||
/* Fill a vector marking which parameters are intact by the described
|
||||
modifications. */
|
||||
void get_surviving_params (vec<bool> *surviving_params);
|
||||
/* Fill a vector with new indices of surviving original parameters. */
|
||||
void get_updated_indices (vec<int> *new_indices);
|
||||
|
||||
void dump (FILE *f);
|
||||
void debug ();
|
||||
|
||||
/* How the known part of arguments should look like. */
|
||||
vec<ipa_adjusted_param, va_gc> *m_adj_params;
|
||||
|
||||
/* If non-negative, copy any arguments starting at this offset without any
|
||||
modifications so that functions with variable number of arguments can be
|
||||
modified. This number should be equal to the number of original forma
|
||||
parameters. */
|
||||
int m_always_copy_start;
|
||||
/* If true, make the function not return any value. */
|
||||
bool m_skip_return;
|
||||
|
||||
private:
|
||||
ipa_param_adjustments () {}
|
||||
|
||||
void init (vec<tree> *cur_params);
|
||||
int get_max_base_index ();
|
||||
bool method2func_p (tree orig_type);
|
||||
};
|
||||
|
||||
/* Structure used to map expressions accessing split or replaced parameters to
|
||||
new PARM_DECLs. */
|
||||
|
||||
struct ipa_param_body_replacement
|
||||
{
|
||||
/* The old decl of the original parameter. */
|
||||
tree base;
|
||||
/* The new decl it should be replaced with. */
|
||||
tree repl;
|
||||
/* When modifying clones during IPA clone materialization, this is a dummy
|
||||
decl used to mark calls in which we need to apply transitive splitting,
|
||||
these dummy delcls are inserted as arguments to such calls and then
|
||||
followed by all the replacements with offset info stored in
|
||||
ipa_param_performed_split.
|
||||
|
||||
Users of ipa_param_body_adjustments that modify standalone functions
|
||||
outside of IPA clone materialization can use this field for their internal
|
||||
purposes. */
|
||||
tree dummy;
|
||||
/* The offset within BASE that REPL represents. */
|
||||
unsigned unit_offset;
|
||||
};
|
||||
|
||||
struct ipa_replace_map;
|
||||
|
||||
/* Class used when actually performing adjustments to formal parameters of a
|
||||
function to map accesses that need to be replaced to replacements. The
|
||||
class attempts to work in two very different sets of circumstances: as a
|
||||
part of tree-inine.c's tree_function_versioning machinery to clone functions
|
||||
(when M_ID is not NULL) and in s standalone fashion, modifying an existing
|
||||
function in place (when M_ID is NULL). While a lot of stuff handled in a
|
||||
unified way in both modes, there are many aspects of the processs that
|
||||
requires distinct paths. */
|
||||
|
||||
class ipa_param_body_adjustments
|
||||
{
|
||||
public:
|
||||
/* Constructor to use from within tree-inline. */
|
||||
ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
|
||||
tree fndecl, tree old_fndecl,
|
||||
struct copy_body_data *id, tree *vars,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map);
|
||||
/* Constructor to use for modifying a function outside of tree-inline from an
|
||||
instance of ipa_param_adjustments. */
|
||||
ipa_param_body_adjustments (ipa_param_adjustments *adjustments,
|
||||
tree fndecl);
|
||||
/* Constructor to use for modifying a function outside of tree-inline from a
|
||||
simple vector of desired parameter modification. */
|
||||
ipa_param_body_adjustments (vec<ipa_adjusted_param, va_gc> *adj_params,
|
||||
tree fndecl);
|
||||
|
||||
/* The do-it-all function for modifying a function outside of
|
||||
tree-inline. */
|
||||
bool perform_cfun_body_modifications ();
|
||||
|
||||
/* Change the PARM_DECLs. */
|
||||
void modify_formal_parameters ();
|
||||
/* Register a replacement decl for the transformation done in APM. */
|
||||
void register_replacement (ipa_adjusted_param *apm, tree replacement,
|
||||
tree dummy = NULL_TREE);
|
||||
/* Lookup a replacement for a given offset within a given parameter. */
|
||||
tree lookup_replacement (tree base, unsigned unit_offset);
|
||||
/* Lookup a replacement for an expression, if there is one. */
|
||||
ipa_param_body_replacement *get_expr_replacement (tree expr,
|
||||
bool ignore_default_def);
|
||||
/* Lookup the new base for surviving names previously belonging to a
|
||||
parameter. */
|
||||
tree get_replacement_ssa_base (tree old_decl);
|
||||
/* Modify a statement. */
|
||||
bool modify_gimple_stmt (gimple **stmt, gimple_seq *extra_stmts);
|
||||
/* Return the new chain of parameters. */
|
||||
tree get_new_param_chain ();
|
||||
|
||||
/* Pointers to data structures defining how the function should be
|
||||
modified. */
|
||||
vec<ipa_adjusted_param, va_gc> *m_adj_params;
|
||||
ipa_param_adjustments *m_adjustments;
|
||||
|
||||
/* Vector of old parameter declarations that must have their debug bind
|
||||
statements re-mapped and debug decls created. */
|
||||
|
||||
auto_vec<tree, 16> m_reset_debug_decls;
|
||||
|
||||
/* Set to true if there are any IPA_PARAM_OP_SPLIT adjustments among stored
|
||||
adjustments. */
|
||||
bool m_split_modifications_p;
|
||||
private:
|
||||
void common_initialization (tree old_fndecl, tree *vars,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map);
|
||||
unsigned get_base_index (ipa_adjusted_param *apm);
|
||||
ipa_param_body_replacement *lookup_replacement_1 (tree base,
|
||||
unsigned unit_offset);
|
||||
tree replace_removed_params_ssa_names (tree old_name, gimple *stmt);
|
||||
bool modify_expression (tree *expr_p, bool convert);
|
||||
bool modify_assignment (gimple *stmt, gimple_seq *extra_stmts);
|
||||
bool modify_call_stmt (gcall **stmt_p);
|
||||
bool modify_cfun_body ();
|
||||
void reset_debug_stmts ();
|
||||
|
||||
/* Declaration of the function that is being transformed. */
|
||||
|
||||
tree m_fndecl;
|
||||
|
||||
/* If non-NULL, the tree-inline master data structure guiding materialization
|
||||
of the current clone. */
|
||||
struct copy_body_data *m_id;
|
||||
|
||||
/* Vector of old parameter declarations (before changing them). */
|
||||
|
||||
auto_vec<tree, 16> m_oparms;
|
||||
|
||||
/* Vector of parameter declarations the function will have after
|
||||
transformation. */
|
||||
|
||||
auto_vec<tree, 16> m_new_decls;
|
||||
|
||||
/* If the function type has non-NULL TYPE_ARG_TYPES, this is the vector of
|
||||
these types after transformation, otherwise an empty one. */
|
||||
|
||||
auto_vec<tree, 16> m_new_types;
|
||||
|
||||
/* Vector of structures telling how to replace old parameters in in the
|
||||
function body. TODO: Even though there usually be only few, but should we
|
||||
use a hash? */
|
||||
|
||||
auto_vec<ipa_param_body_replacement, 16> m_replacements;
|
||||
|
||||
/* Vector for remapping SSA_BASES from old parameter declarations that are
|
||||
being removed as a part of the transformation. Before a new VAR_DECL is
|
||||
created, it holds the old PARM_DECL, once the variable is built it is
|
||||
stored here. */
|
||||
|
||||
auto_vec<tree> m_removed_decls;
|
||||
|
||||
/* Hash to quickly lookup the item in m_removed_decls given the old decl. */
|
||||
|
||||
hash_map<tree, unsigned> m_removed_map;
|
||||
|
||||
/* True iff the transformed function is a class method that is about to loose
|
||||
its this pointer and must be converted to a normal function. */
|
||||
|
||||
bool m_method2func;
|
||||
};
|
||||
|
||||
void push_function_arg_decls (vec<tree> *args, tree fndecl);
|
||||
void push_function_arg_types (vec<tree> *types, tree fntype);
|
||||
|
||||
#endif /* IPA_PARAM_MANIPULATION_H */
|
||||
|
103
gcc/ipa-prop.c
103
gcc/ipa-prop.c
@ -4851,31 +4851,24 @@ adjust_agg_replacement_values (struct cgraph_node *node,
|
||||
struct ipa_agg_replacement_value *aggval)
|
||||
{
|
||||
struct ipa_agg_replacement_value *v;
|
||||
int i, c = 0, d = 0, *adj;
|
||||
|
||||
if (!node->clone.combined_args_to_skip)
|
||||
if (!node->clone.param_adjustments)
|
||||
return;
|
||||
|
||||
auto_vec<int, 16> new_indices;
|
||||
node->clone.param_adjustments->get_updated_indices (&new_indices);
|
||||
for (v = aggval; v; v = v->next)
|
||||
{
|
||||
gcc_assert (v->index >= 0);
|
||||
if (c < v->index)
|
||||
c = v->index;
|
||||
gcc_checking_assert (v->index >= 0);
|
||||
|
||||
if ((unsigned) v->index < new_indices.length ())
|
||||
v->index = new_indices[v->index];
|
||||
else
|
||||
/* This can happen if we know about a constant passed by reference by
|
||||
an argument which is never actually used for anything, let alone
|
||||
loading that constant. */
|
||||
v->index = -1;
|
||||
}
|
||||
c++;
|
||||
|
||||
adj = XALLOCAVEC (int, c);
|
||||
for (i = 0; i < c; i++)
|
||||
if (bitmap_bit_p (node->clone.combined_args_to_skip, i))
|
||||
{
|
||||
adj[i] = -1;
|
||||
d++;
|
||||
}
|
||||
else
|
||||
adj[i] = i - d;
|
||||
|
||||
for (v = aggval; v; v = v->next)
|
||||
v->index = adj[v->index];
|
||||
}
|
||||
|
||||
/* Dominator walker driving the ipcp modification phase. */
|
||||
@ -5001,24 +4994,41 @@ ipcp_modif_dom_walker::before_dom_children (basic_block bb)
|
||||
static void
|
||||
ipcp_update_bits (struct cgraph_node *node)
|
||||
{
|
||||
tree parm = DECL_ARGUMENTS (node->decl);
|
||||
tree next_parm = parm;
|
||||
ipcp_transformation *ts = ipcp_get_transformation_summary (node);
|
||||
|
||||
if (!ts || vec_safe_length (ts->bits) == 0)
|
||||
return;
|
||||
|
||||
vec<ipa_bits *, va_gc> &bits = *ts->bits;
|
||||
unsigned count = bits.length ();
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < count; ++i, parm = next_parm)
|
||||
auto_vec<int, 16> new_indices;
|
||||
bool need_remapping = false;
|
||||
if (node->clone.param_adjustments)
|
||||
{
|
||||
if (node->clone.combined_args_to_skip
|
||||
&& bitmap_bit_p (node->clone.combined_args_to_skip, i))
|
||||
continue;
|
||||
node->clone.param_adjustments->get_updated_indices (&new_indices);
|
||||
need_remapping = true;
|
||||
}
|
||||
auto_vec <tree, 16> parm_decls;
|
||||
push_function_arg_decls (&parm_decls, node->decl);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
tree parm;
|
||||
if (need_remapping)
|
||||
{
|
||||
if (i >= new_indices.length ())
|
||||
continue;
|
||||
int idx = new_indices[i];
|
||||
if (idx < 0)
|
||||
continue;
|
||||
parm = parm_decls[idx];
|
||||
}
|
||||
else
|
||||
parm = parm_decls[i];
|
||||
gcc_checking_assert (parm);
|
||||
next_parm = DECL_CHAIN (parm);
|
||||
|
||||
|
||||
if (!bits[i]
|
||||
|| !(INTEGRAL_TYPE_P (TREE_TYPE (parm))
|
||||
@ -5093,22 +5103,42 @@ ipcp_update_bits (struct cgraph_node *node)
|
||||
static void
|
||||
ipcp_update_vr (struct cgraph_node *node)
|
||||
{
|
||||
tree fndecl = node->decl;
|
||||
tree parm = DECL_ARGUMENTS (fndecl);
|
||||
tree next_parm = parm;
|
||||
ipcp_transformation *ts = ipcp_get_transformation_summary (node);
|
||||
if (!ts || vec_safe_length (ts->m_vr) == 0)
|
||||
return;
|
||||
const vec<ipa_vr, va_gc> &vr = *ts->m_vr;
|
||||
unsigned count = vr.length ();
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < count; ++i, parm = next_parm)
|
||||
auto_vec<int, 16> new_indices;
|
||||
bool need_remapping = false;
|
||||
if (node->clone.param_adjustments)
|
||||
{
|
||||
if (node->clone.combined_args_to_skip
|
||||
&& bitmap_bit_p (node->clone.combined_args_to_skip, i))
|
||||
continue;
|
||||
node->clone.param_adjustments->get_updated_indices (&new_indices);
|
||||
need_remapping = true;
|
||||
}
|
||||
auto_vec <tree, 16> parm_decls;
|
||||
push_function_arg_decls (&parm_decls, node->decl);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
{
|
||||
tree parm;
|
||||
int remapped_idx;
|
||||
if (need_remapping)
|
||||
{
|
||||
if (i >= new_indices.length ())
|
||||
continue;
|
||||
remapped_idx = new_indices[i];
|
||||
if (remapped_idx < 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
remapped_idx = i;
|
||||
|
||||
parm = parm_decls[remapped_idx];
|
||||
|
||||
gcc_checking_assert (parm);
|
||||
next_parm = DECL_CHAIN (parm);
|
||||
tree ddef = ssa_default_def (DECL_STRUCT_FUNCTION (node->decl), parm);
|
||||
|
||||
if (!ddef || !is_gimple_reg (parm))
|
||||
@ -5123,7 +5153,8 @@ ipcp_update_vr (struct cgraph_node *node)
|
||||
{
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, "Setting value range of param %u ", i);
|
||||
fprintf (dump_file, "Setting value range of param %u "
|
||||
"(now %i) ", i, remapped_idx);
|
||||
fprintf (dump_file, "%s[",
|
||||
(vr[i].type == VR_ANTI_RANGE) ? "~" : "");
|
||||
print_decs (vr[i].min, dump_file);
|
||||
|
@ -1326,13 +1326,38 @@ split_function (basic_block return_bb, class split_point *split_point,
|
||||
}
|
||||
}
|
||||
|
||||
ipa_param_adjustments *adjustments;
|
||||
bool skip_return = (!split_part_return_p
|
||||
|| !split_point->split_part_set_retval);
|
||||
/* TODO: Perhaps get rid of args_to_skip entirely, after we make sure the
|
||||
debug info generation and discrepancy avoiding works well too. */
|
||||
if ((args_to_skip && !bitmap_empty_p (args_to_skip))
|
||||
|| skip_return)
|
||||
{
|
||||
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
|
||||
unsigned j;
|
||||
for (parm = DECL_ARGUMENTS (current_function_decl), j = 0;
|
||||
parm; parm = DECL_CHAIN (parm), j++)
|
||||
if (!args_to_skip || !bitmap_bit_p (args_to_skip, j))
|
||||
{
|
||||
ipa_adjusted_param adj;
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
adj.op = IPA_PARAM_OP_COPY;
|
||||
adj.base_index = j;
|
||||
adj.prev_clone_index = j;
|
||||
vec_safe_push (new_params, adj);
|
||||
}
|
||||
adjustments = new ipa_param_adjustments (new_params, j, skip_return);
|
||||
}
|
||||
else
|
||||
adjustments = NULL;
|
||||
|
||||
/* Now create the actual clone. */
|
||||
cgraph_edge::rebuild_edges ();
|
||||
node = cur_node->create_version_clone_with_body
|
||||
(vNULL, NULL, args_to_skip,
|
||||
!split_part_return_p || !split_point->split_part_set_retval,
|
||||
(vNULL, NULL, adjustments,
|
||||
split_point->split_bbs, split_point->entry_bb, "part");
|
||||
|
||||
delete adjustments;
|
||||
node->split_part = true;
|
||||
|
||||
if (cur_node->same_comdat_group)
|
||||
@ -1469,6 +1494,7 @@ split_function (basic_block return_bb, class split_point *split_point,
|
||||
= gimple_build_debug_bind (ddecl, unshare_expr (arg), call);
|
||||
gsi_insert_after (&gsi, def_temp, GSI_NEW_STMT);
|
||||
}
|
||||
BITMAP_FREE (args_to_skip);
|
||||
}
|
||||
|
||||
/* We avoid address being taken on any variable used by split part,
|
||||
|
4049
gcc/ipa-sra.c
Normal file
4049
gcc/ipa-sra.c
Normal file
File diff suppressed because it is too large
Load Diff
121
gcc/lto-cgraph.c
121
gcc/lto-cgraph.c
@ -1804,8 +1804,7 @@ output_cgraph_opt_summary_p (struct cgraph_node *node)
|
||||
{
|
||||
return ((node->clone_of || node->former_clone_of)
|
||||
&& (node->clone.tree_map
|
||||
|| node->clone.args_to_skip
|
||||
|| node->clone.combined_args_to_skip));
|
||||
|| node->clone.param_adjustments));
|
||||
}
|
||||
|
||||
/* Output optimization summary for EDGE to OB. */
|
||||
@ -1822,42 +1821,53 @@ output_node_opt_summary (struct output_block *ob,
|
||||
struct cgraph_node *node,
|
||||
lto_symtab_encoder_t encoder)
|
||||
{
|
||||
unsigned int index;
|
||||
bitmap_iterator bi;
|
||||
struct ipa_replace_map *map;
|
||||
struct bitpack_d bp;
|
||||
int i;
|
||||
struct cgraph_edge *e;
|
||||
|
||||
if (node->clone.args_to_skip)
|
||||
/* TODO: Should this code be moved to ipa-param-manipulation? */
|
||||
struct bitpack_d bp;
|
||||
bp = bitpack_create (ob->main_stream);
|
||||
bp_pack_value (&bp, (node->clone.param_adjustments != NULL), 1);
|
||||
streamer_write_bitpack (&bp);
|
||||
if (ipa_param_adjustments *adjustments = node->clone.param_adjustments)
|
||||
{
|
||||
streamer_write_uhwi (ob, bitmap_count_bits (node->clone.args_to_skip));
|
||||
EXECUTE_IF_SET_IN_BITMAP (node->clone.args_to_skip, 0, index, bi)
|
||||
streamer_write_uhwi (ob, index);
|
||||
streamer_write_uhwi (ob, vec_safe_length (adjustments->m_adj_params));
|
||||
ipa_adjusted_param *adj;
|
||||
FOR_EACH_VEC_SAFE_ELT (adjustments->m_adj_params, i, adj)
|
||||
{
|
||||
bp = bitpack_create (ob->main_stream);
|
||||
bp_pack_value (&bp, adj->base_index, IPA_PARAM_MAX_INDEX_BITS);
|
||||
bp_pack_value (&bp, adj->prev_clone_index, IPA_PARAM_MAX_INDEX_BITS);
|
||||
bp_pack_value (&bp, adj->op, 2);
|
||||
bp_pack_value (&bp, adj->param_prefix_index, 2);
|
||||
bp_pack_value (&bp, adj->prev_clone_adjustment, 1);
|
||||
bp_pack_value (&bp, adj->reverse, 1);
|
||||
bp_pack_value (&bp, adj->user_flag, 1);
|
||||
streamer_write_bitpack (&bp);
|
||||
if (adj->op == IPA_PARAM_OP_SPLIT
|
||||
|| adj->op == IPA_PARAM_OP_NEW)
|
||||
{
|
||||
stream_write_tree (ob, adj->type, true);
|
||||
if (adj->op == IPA_PARAM_OP_SPLIT)
|
||||
{
|
||||
stream_write_tree (ob, adj->alias_ptr_type, true);
|
||||
streamer_write_uhwi (ob, adj->unit_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
streamer_write_hwi (ob, adjustments->m_always_copy_start);
|
||||
bp = bitpack_create (ob->main_stream);
|
||||
bp_pack_value (&bp, node->clone.param_adjustments->m_skip_return, 1);
|
||||
streamer_write_bitpack (&bp);
|
||||
}
|
||||
else
|
||||
streamer_write_uhwi (ob, 0);
|
||||
if (node->clone.combined_args_to_skip)
|
||||
{
|
||||
streamer_write_uhwi (ob, bitmap_count_bits (node->clone.combined_args_to_skip));
|
||||
EXECUTE_IF_SET_IN_BITMAP (node->clone.combined_args_to_skip, 0, index, bi)
|
||||
streamer_write_uhwi (ob, index);
|
||||
}
|
||||
else
|
||||
streamer_write_uhwi (ob, 0);
|
||||
|
||||
streamer_write_uhwi (ob, vec_safe_length (node->clone.tree_map));
|
||||
FOR_EACH_VEC_SAFE_ELT (node->clone.tree_map, i, map)
|
||||
{
|
||||
/* At the moment we assume all old trees to be PARM_DECLs, because we have no
|
||||
mechanism to store function local declarations into summaries. */
|
||||
gcc_assert (!map->old_tree);
|
||||
streamer_write_uhwi (ob, map->parm_num);
|
||||
gcc_assert (EXPR_LOCATION (map->new_tree) == UNKNOWN_LOCATION);
|
||||
stream_write_tree (ob, map->new_tree, true);
|
||||
bp = bitpack_create (ob->main_stream);
|
||||
bp_pack_value (&bp, map->replace_p, 1);
|
||||
bp_pack_value (&bp, map->ref_p, 1);
|
||||
streamer_write_bitpack (&bp);
|
||||
}
|
||||
|
||||
if (lto_symtab_encoder_in_partition_p (encoder, node))
|
||||
@ -1922,26 +1932,49 @@ input_node_opt_summary (struct cgraph_node *node,
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
int bit;
|
||||
struct bitpack_d bp;
|
||||
struct cgraph_edge *e;
|
||||
|
||||
count = streamer_read_uhwi (ib_main);
|
||||
if (count)
|
||||
node->clone.args_to_skip = BITMAP_GGC_ALLOC ();
|
||||
for (i = 0; i < count; i++)
|
||||
/* TODO: Should this code be moved to ipa-param-manipulation? */
|
||||
struct bitpack_d bp;
|
||||
bp = streamer_read_bitpack (ib_main);
|
||||
bool have_adjustments = bp_unpack_value (&bp, 1);
|
||||
if (have_adjustments)
|
||||
{
|
||||
bit = streamer_read_uhwi (ib_main);
|
||||
bitmap_set_bit (node->clone.args_to_skip, bit);
|
||||
}
|
||||
count = streamer_read_uhwi (ib_main);
|
||||
if (count)
|
||||
node->clone.combined_args_to_skip = BITMAP_GGC_ALLOC ();
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
bit = streamer_read_uhwi (ib_main);
|
||||
bitmap_set_bit (node->clone.combined_args_to_skip, bit);
|
||||
count = streamer_read_uhwi (ib_main);
|
||||
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
ipa_adjusted_param adj;
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
bp = streamer_read_bitpack (ib_main);
|
||||
adj.base_index = bp_unpack_value (&bp, IPA_PARAM_MAX_INDEX_BITS);
|
||||
adj.prev_clone_index
|
||||
= bp_unpack_value (&bp, IPA_PARAM_MAX_INDEX_BITS);
|
||||
adj.op = (enum ipa_parm_op) bp_unpack_value (&bp, 2);
|
||||
adj.param_prefix_index = bp_unpack_value (&bp, 2);
|
||||
adj.prev_clone_adjustment = bp_unpack_value (&bp, 1);
|
||||
adj.reverse = bp_unpack_value (&bp, 1);
|
||||
adj.user_flag = bp_unpack_value (&bp, 1);
|
||||
if (adj.op == IPA_PARAM_OP_SPLIT
|
||||
|| adj.op == IPA_PARAM_OP_NEW)
|
||||
{
|
||||
adj.type = stream_read_tree (ib_main, data_in);
|
||||
if (adj.op == IPA_PARAM_OP_SPLIT)
|
||||
{
|
||||
adj.alias_ptr_type = stream_read_tree (ib_main, data_in);
|
||||
adj.unit_offset = streamer_read_uhwi (ib_main);
|
||||
}
|
||||
}
|
||||
vec_safe_push (new_params, adj);
|
||||
}
|
||||
int always_copy_start = streamer_read_hwi (ib_main);
|
||||
bp = streamer_read_bitpack (ib_main);
|
||||
bool skip_return = bp_unpack_value (&bp, 1);
|
||||
node->clone.param_adjustments
|
||||
= (new (ggc_alloc <ipa_param_adjustments> ())
|
||||
ipa_param_adjustments (new_params, always_copy_start, skip_return));
|
||||
}
|
||||
|
||||
count = streamer_read_uhwi (ib_main);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
@ -1949,11 +1982,7 @@ input_node_opt_summary (struct cgraph_node *node,
|
||||
|
||||
vec_safe_push (node->clone.tree_map, map);
|
||||
map->parm_num = streamer_read_uhwi (ib_main);
|
||||
map->old_tree = NULL;
|
||||
map->new_tree = stream_read_tree (ib_main, data_in);
|
||||
bp = streamer_read_bitpack (ib_main);
|
||||
map->replace_p = bp_unpack_value (&bp, 1);
|
||||
map->ref_p = bp_unpack_value (&bp, 1);
|
||||
}
|
||||
for (e = node->callees; e; e = e->next_callee)
|
||||
input_edge_opt_summary (e, ib_main);
|
||||
|
@ -53,7 +53,8 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] =
|
||||
"offload_table",
|
||||
"mode_table",
|
||||
"hsa",
|
||||
"lto"
|
||||
"lto",
|
||||
"ipa-sra"
|
||||
};
|
||||
|
||||
/* Hooks so that the ipa passes can call into the lto front end to get
|
||||
|
@ -235,6 +235,7 @@ enum lto_section_type
|
||||
LTO_section_mode_table,
|
||||
LTO_section_ipa_hsa,
|
||||
LTO_section_lto,
|
||||
LTO_section_ipa_sra,
|
||||
LTO_N_SECTION_TYPES /* Must be last. */
|
||||
};
|
||||
|
||||
|
@ -311,9 +311,8 @@ create_target_clone (cgraph_node *node, bool definition, char *name,
|
||||
if (definition)
|
||||
{
|
||||
new_node = node->create_version_clone_with_body (vNULL, NULL,
|
||||
NULL, false,
|
||||
NULL, NULL,
|
||||
name, attributes);
|
||||
NULL, NULL,
|
||||
NULL, name, attributes);
|
||||
if (new_node == NULL)
|
||||
return NULL;
|
||||
new_node->force_output = true;
|
||||
|
@ -86,21 +86,23 @@ simd_clone_struct_copy (struct cgraph_simd_clone *to,
|
||||
* sizeof (struct cgraph_simd_clone_arg))));
|
||||
}
|
||||
|
||||
/* Return vector of parameter types of function FNDECL. This uses
|
||||
TYPE_ARG_TYPES if available, otherwise falls back to types of
|
||||
/* Fill an empty vector ARGS with parameter types of function FNDECL. This
|
||||
uses TYPE_ARG_TYPES if available, otherwise falls back to types of
|
||||
DECL_ARGUMENTS types. */
|
||||
|
||||
static vec<tree>
|
||||
simd_clone_vector_of_formal_parm_types (tree fndecl)
|
||||
static void
|
||||
simd_clone_vector_of_formal_parm_types (vec<tree> *args, tree fndecl)
|
||||
{
|
||||
if (TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
|
||||
return ipa_get_vector_of_formal_parm_types (TREE_TYPE (fndecl));
|
||||
vec<tree> args = ipa_get_vector_of_formal_parms (fndecl);
|
||||
{
|
||||
push_function_arg_types (args, TREE_TYPE (fndecl));
|
||||
return;
|
||||
}
|
||||
push_function_arg_decls (args, fndecl);
|
||||
unsigned int i;
|
||||
tree arg;
|
||||
FOR_EACH_VEC_ELT (args, i, arg)
|
||||
args[i] = TREE_TYPE (args[i]);
|
||||
return args;
|
||||
FOR_EACH_VEC_ELT (*args, i, arg)
|
||||
(*args)[i] = TREE_TYPE ((*args)[i]);
|
||||
}
|
||||
|
||||
/* Given a simd function in NODE, extract the simd specific
|
||||
@ -113,7 +115,8 @@ static struct cgraph_simd_clone *
|
||||
simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
|
||||
bool *inbranch_specified)
|
||||
{
|
||||
vec<tree> args = simd_clone_vector_of_formal_parm_types (node->decl);
|
||||
auto_vec<tree> args;
|
||||
simd_clone_vector_of_formal_parm_types (&args, node->decl);
|
||||
tree t;
|
||||
int n;
|
||||
*inbranch_specified = false;
|
||||
@ -192,14 +195,12 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
|
||||
{
|
||||
warning_at (OMP_CLAUSE_LOCATION (t), 0,
|
||||
"ignoring large linear step");
|
||||
args.release ();
|
||||
return NULL;
|
||||
}
|
||||
else if (integer_zerop (step))
|
||||
{
|
||||
warning_at (OMP_CLAUSE_LOCATION (t), 0,
|
||||
"ignoring zero linear step");
|
||||
args.release ();
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
@ -263,7 +264,6 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
|
||||
warning_at (DECL_SOURCE_LOCATION (node->decl), 0,
|
||||
"ignoring %<#pragma omp declare simd%> on function "
|
||||
"with %<_Atomic%> qualified return type");
|
||||
args.release ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -278,7 +278,6 @@ simd_clone_clauses_extract (struct cgraph_node *node, tree clauses,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
args.release ();
|
||||
return clone_info;
|
||||
}
|
||||
|
||||
@ -303,14 +302,14 @@ simd_clone_compute_base_data_type (struct cgraph_node *node,
|
||||
such parameter. */
|
||||
else
|
||||
{
|
||||
vec<tree> map = simd_clone_vector_of_formal_parm_types (fndecl);
|
||||
auto_vec<tree> map;
|
||||
simd_clone_vector_of_formal_parm_types (&map, fndecl);
|
||||
for (unsigned int i = 0; i < clone_info->nargs; ++i)
|
||||
if (clone_info->args[i].arg_type == SIMD_CLONE_ARG_TYPE_VECTOR)
|
||||
{
|
||||
type = map[i];
|
||||
break;
|
||||
}
|
||||
map.release ();
|
||||
}
|
||||
|
||||
/* c) If the characteristic data type determined by a) or b) above
|
||||
@ -441,7 +440,7 @@ simd_clone_create (struct cgraph_node *old_node)
|
||||
return NULL;
|
||||
old_node->get_body ();
|
||||
new_node = old_node->create_version_clone_with_body (vNULL, NULL, NULL,
|
||||
false, NULL, NULL,
|
||||
NULL, NULL,
|
||||
"simdclone");
|
||||
}
|
||||
else
|
||||
@ -561,31 +560,33 @@ create_tmp_simd_array (const char *prefix, tree type, int simdlen)
|
||||
|
||||
NODE is the function whose arguments are to be adjusted.
|
||||
|
||||
Returns an adjustment vector that will be filled describing how the
|
||||
argument types will be adjusted. */
|
||||
If NODE does not represent function definition, returns NULL. Otherwise
|
||||
returns an adjustment class that will be filled describing how the argument
|
||||
declarations will be remapped. New arguments which are not to be remapped
|
||||
are marked with USER_FLAG. */
|
||||
|
||||
static ipa_parm_adjustment_vec
|
||||
static ipa_param_body_adjustments *
|
||||
simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
{
|
||||
vec<tree> args;
|
||||
ipa_parm_adjustment_vec adjustments;
|
||||
auto_vec<tree> args;
|
||||
|
||||
if (node->definition)
|
||||
args = ipa_get_vector_of_formal_parms (node->decl);
|
||||
push_function_arg_decls (&args, node->decl);
|
||||
else
|
||||
args = simd_clone_vector_of_formal_parm_types (node->decl);
|
||||
adjustments.create (args.length ());
|
||||
unsigned i, j, veclen;
|
||||
struct ipa_parm_adjustment adj;
|
||||
simd_clone_vector_of_formal_parm_types (&args, node->decl);
|
||||
struct cgraph_simd_clone *sc = node->simdclone;
|
||||
vec<ipa_adjusted_param, va_gc> *new_params = NULL;
|
||||
vec_safe_reserve (new_params, sc->nargs);
|
||||
unsigned i, j, veclen;
|
||||
|
||||
for (i = 0; i < sc->nargs; ++i)
|
||||
{
|
||||
ipa_adjusted_param adj;
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
tree parm = args[i];
|
||||
tree parm_type = node->definition ? TREE_TYPE (parm) : parm;
|
||||
adj.base_index = i;
|
||||
adj.base = parm;
|
||||
adj.prev_clone_index = i;
|
||||
|
||||
sc->args[i].orig_arg = node->definition ? parm : NULL_TREE;
|
||||
sc->args[i].orig_type = parm_type;
|
||||
@ -594,7 +595,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
{
|
||||
default:
|
||||
/* No adjustment necessary for scalar arguments. */
|
||||
adj.op = IPA_PARM_OP_COPY;
|
||||
adj.op = IPA_PARAM_OP_COPY;
|
||||
break;
|
||||
case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_CONSTANT_STEP:
|
||||
case SIMD_CLONE_ARG_TYPE_LINEAR_UVAL_VARIABLE_STEP:
|
||||
@ -603,7 +604,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
= create_tmp_simd_array (IDENTIFIER_POINTER (DECL_NAME (parm)),
|
||||
TREE_TYPE (parm_type),
|
||||
sc->simdlen);
|
||||
adj.op = IPA_PARM_OP_COPY;
|
||||
adj.op = IPA_PARAM_OP_COPY;
|
||||
break;
|
||||
case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_CONSTANT_STEP:
|
||||
case SIMD_CLONE_ARG_TYPE_LINEAR_VAL_VARIABLE_STEP:
|
||||
@ -615,7 +616,8 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
veclen /= GET_MODE_BITSIZE (SCALAR_TYPE_MODE (parm_type));
|
||||
if (veclen > sc->simdlen)
|
||||
veclen = sc->simdlen;
|
||||
adj.arg_prefix = "simd";
|
||||
adj.op = IPA_PARAM_OP_NEW;
|
||||
adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
|
||||
if (POINTER_TYPE_P (parm_type))
|
||||
adj.type = build_vector_type (pointer_sized_int_node, veclen);
|
||||
else
|
||||
@ -623,13 +625,15 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
sc->args[i].vector_type = adj.type;
|
||||
for (j = veclen; j < sc->simdlen; j += veclen)
|
||||
{
|
||||
adjustments.safe_push (adj);
|
||||
vec_safe_push (new_params, adj);
|
||||
if (j == veclen)
|
||||
{
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
adj.op = IPA_PARM_OP_NEW;
|
||||
adj.arg_prefix = "simd";
|
||||
adj.op = IPA_PARAM_OP_NEW;
|
||||
adj.user_flag = 1;
|
||||
adj.param_prefix_index = IPA_PARAM_PREFIX_SIMD;
|
||||
adj.base_index = i;
|
||||
adj.prev_clone_index = i;
|
||||
adj.type = sc->args[i].vector_type;
|
||||
}
|
||||
}
|
||||
@ -640,18 +644,20 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
? IDENTIFIER_POINTER (DECL_NAME (parm))
|
||||
: NULL, parm_type, sc->simdlen);
|
||||
}
|
||||
adjustments.safe_push (adj);
|
||||
vec_safe_push (new_params, adj);
|
||||
}
|
||||
|
||||
if (sc->inbranch)
|
||||
{
|
||||
tree base_type = simd_clone_compute_base_data_type (sc->origin, sc);
|
||||
|
||||
ipa_adjusted_param adj;
|
||||
memset (&adj, 0, sizeof (adj));
|
||||
adj.op = IPA_PARM_OP_NEW;
|
||||
adj.arg_prefix = "mask";
|
||||
adj.op = IPA_PARAM_OP_NEW;
|
||||
adj.user_flag = 1;
|
||||
adj.param_prefix_index = IPA_PARAM_PREFIX_MASK;
|
||||
|
||||
adj.base_index = i;
|
||||
adj.prev_clone_index = i;
|
||||
if (INTEGRAL_TYPE_P (base_type) || POINTER_TYPE_P (base_type))
|
||||
veclen = sc->vecsize_int;
|
||||
else
|
||||
@ -666,10 +672,10 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
adj.type = build_vector_type (pointer_sized_int_node, veclen);
|
||||
else
|
||||
adj.type = build_vector_type (base_type, veclen);
|
||||
adjustments.safe_push (adj);
|
||||
vec_safe_push (new_params, adj);
|
||||
|
||||
for (j = veclen; j < sc->simdlen; j += veclen)
|
||||
adjustments.safe_push (adj);
|
||||
vec_safe_push (new_params, adj);
|
||||
|
||||
/* We have previously allocated one extra entry for the mask. Use
|
||||
it and fill it. */
|
||||
@ -694,7 +700,13 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
}
|
||||
|
||||
if (node->definition)
|
||||
ipa_modify_formal_parameters (node->decl, adjustments);
|
||||
{
|
||||
ipa_param_body_adjustments *adjustments
|
||||
= new ipa_param_body_adjustments (new_params, node->decl);
|
||||
|
||||
adjustments->modify_formal_parameters ();
|
||||
return adjustments;
|
||||
}
|
||||
else
|
||||
{
|
||||
tree new_arg_types = NULL_TREE, new_reversed;
|
||||
@ -703,12 +715,12 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
last_parm_void = true;
|
||||
|
||||
gcc_assert (TYPE_ARG_TYPES (TREE_TYPE (node->decl)));
|
||||
j = adjustments.length ();
|
||||
j = vec_safe_length (new_params);
|
||||
for (i = 0; i < j; i++)
|
||||
{
|
||||
struct ipa_parm_adjustment *adj = &adjustments[i];
|
||||
struct ipa_adjusted_param *adj = &(*new_params)[i];
|
||||
tree ptype;
|
||||
if (adj->op == IPA_PARM_OP_COPY)
|
||||
if (adj->op == IPA_PARAM_OP_COPY)
|
||||
ptype = args[adj->base_index];
|
||||
else
|
||||
ptype = adj->type;
|
||||
@ -723,10 +735,8 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
new_reversed = void_list_node;
|
||||
}
|
||||
TYPE_ARG_TYPES (TREE_TYPE (node->decl)) = new_reversed;
|
||||
adjustments.release ();
|
||||
return NULL;
|
||||
}
|
||||
args.release ();
|
||||
return adjustments;
|
||||
}
|
||||
|
||||
/* Initialize and copy the function arguments in NODE to their
|
||||
@ -735,7 +745,7 @@ simd_clone_adjust_argument_types (struct cgraph_node *node)
|
||||
|
||||
static gimple_seq
|
||||
simd_clone_init_simd_arrays (struct cgraph_node *node,
|
||||
ipa_parm_adjustment_vec adjustments)
|
||||
ipa_param_body_adjustments *adjustments)
|
||||
{
|
||||
gimple_seq seq = NULL;
|
||||
unsigned i = 0, j = 0, k;
|
||||
@ -744,7 +754,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node,
|
||||
arg;
|
||||
arg = DECL_CHAIN (arg), i++, j++)
|
||||
{
|
||||
if (adjustments[j].op == IPA_PARM_OP_COPY
|
||||
if ((*adjustments->m_adj_params)[j].op == IPA_PARAM_OP_COPY
|
||||
|| POINTER_TYPE_P (TREE_TYPE (arg)))
|
||||
continue;
|
||||
|
||||
@ -809,7 +819,7 @@ simd_clone_init_simd_arrays (struct cgraph_node *node,
|
||||
/* Callback info for ipa_simd_modify_stmt_ops below. */
|
||||
|
||||
struct modify_stmt_info {
|
||||
ipa_parm_adjustment_vec adjustments;
|
||||
ipa_param_body_adjustments *adjustments;
|
||||
gimple *stmt;
|
||||
/* True if the parent statement was modified by
|
||||
ipa_simd_modify_stmt_ops. */
|
||||
@ -829,15 +839,26 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
|
||||
tree *orig_tp = tp;
|
||||
if (TREE_CODE (*tp) == ADDR_EXPR)
|
||||
tp = &TREE_OPERAND (*tp, 0);
|
||||
struct ipa_parm_adjustment *cand = NULL;
|
||||
|
||||
if (TREE_CODE (*tp) == BIT_FIELD_REF
|
||||
|| TREE_CODE (*tp) == IMAGPART_EXPR
|
||||
|| TREE_CODE (*tp) == REALPART_EXPR)
|
||||
tp = &TREE_OPERAND (*tp, 0);
|
||||
|
||||
tree repl = NULL_TREE;
|
||||
ipa_param_body_replacement *pbr = NULL;
|
||||
|
||||
if (TREE_CODE (*tp) == PARM_DECL)
|
||||
cand = ipa_get_adjustment_candidate (&tp, NULL, info->adjustments, true);
|
||||
{
|
||||
pbr = info->adjustments->get_expr_replacement (*tp, true);
|
||||
if (pbr)
|
||||
repl = pbr->repl;
|
||||
}
|
||||
else if (TYPE_P (*tp))
|
||||
*walk_subtrees = 0;
|
||||
|
||||
tree repl = NULL_TREE;
|
||||
if (cand)
|
||||
repl = unshare_expr (cand->new_decl);
|
||||
if (repl)
|
||||
repl = unshare_expr (repl);
|
||||
else
|
||||
{
|
||||
if (tp != orig_tp)
|
||||
@ -861,13 +882,13 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
|
||||
if (tp != orig_tp)
|
||||
{
|
||||
if (gimple_code (info->stmt) == GIMPLE_PHI
|
||||
&& cand
|
||||
&& pbr
|
||||
&& TREE_CODE (*orig_tp) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL
|
||||
&& cand->alias_ptr_type)
|
||||
&& pbr->dummy)
|
||||
{
|
||||
gcc_assert (TREE_CODE (cand->alias_ptr_type) == SSA_NAME);
|
||||
*orig_tp = cand->alias_ptr_type;
|
||||
gcc_assert (TREE_CODE (pbr->dummy) == SSA_NAME);
|
||||
*orig_tp = pbr->dummy;
|
||||
info->modified = true;
|
||||
return NULL_TREE;
|
||||
}
|
||||
@ -893,10 +914,13 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
|
||||
{
|
||||
gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
|
||||
/* Cache SSA_NAME for next time. */
|
||||
if (cand
|
||||
if (pbr
|
||||
&& TREE_CODE (*orig_tp) == ADDR_EXPR
|
||||
&& TREE_CODE (TREE_OPERAND (*orig_tp, 0)) == PARM_DECL)
|
||||
cand->alias_ptr_type = repl;
|
||||
{
|
||||
gcc_assert (!pbr->dummy);
|
||||
pbr->dummy = repl;
|
||||
}
|
||||
}
|
||||
else
|
||||
gsi = gsi_for_stmt (info->stmt);
|
||||
@ -926,70 +950,56 @@ ipa_simd_modify_stmt_ops (tree *tp, int *walk_subtrees, void *data)
|
||||
|
||||
static void
|
||||
ipa_simd_modify_function_body (struct cgraph_node *node,
|
||||
ipa_parm_adjustment_vec adjustments,
|
||||
ipa_param_body_adjustments *adjustments,
|
||||
tree retval_array, tree iter)
|
||||
{
|
||||
basic_block bb;
|
||||
unsigned int i, j, l;
|
||||
unsigned int i, j;
|
||||
|
||||
/* Re-use the adjustments array, but this time use it to replace
|
||||
every function argument use to an offset into the corresponding
|
||||
simd_array. */
|
||||
|
||||
/* Register replacements for every function argument use to an offset into
|
||||
the corresponding simd_array. */
|
||||
for (i = 0, j = 0; i < node->simdclone->nargs; ++i, ++j)
|
||||
{
|
||||
if (!node->simdclone->args[i].vector_arg)
|
||||
if (!node->simdclone->args[i].vector_arg
|
||||
|| (*adjustments->m_adj_params)[j].user_flag)
|
||||
continue;
|
||||
|
||||
tree basetype = TREE_TYPE (node->simdclone->args[i].orig_arg);
|
||||
tree vectype = TREE_TYPE (node->simdclone->args[i].vector_arg);
|
||||
adjustments[j].new_decl
|
||||
= build4 (ARRAY_REF,
|
||||
basetype,
|
||||
node->simdclone->args[i].simd_array,
|
||||
iter,
|
||||
NULL_TREE, NULL_TREE);
|
||||
if (adjustments[j].op == IPA_PARM_OP_NONE
|
||||
&& simd_clone_subparts (vectype) < node->simdclone->simdlen)
|
||||
tree r = build4 (ARRAY_REF, basetype, node->simdclone->args[i].simd_array,
|
||||
iter, NULL_TREE, NULL_TREE);
|
||||
adjustments->register_replacement (&(*adjustments->m_adj_params)[j], r);
|
||||
|
||||
if (simd_clone_subparts (vectype) < node->simdclone->simdlen)
|
||||
j += node->simdclone->simdlen / simd_clone_subparts (vectype) - 1;
|
||||
}
|
||||
|
||||
l = adjustments.length ();
|
||||
tree name;
|
||||
|
||||
FOR_EACH_SSA_NAME (i, name, cfun)
|
||||
{
|
||||
tree base_var;
|
||||
if (SSA_NAME_VAR (name)
|
||||
&& TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL)
|
||||
&& TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL
|
||||
&& (base_var
|
||||
= adjustments->get_replacement_ssa_base (SSA_NAME_VAR (name))))
|
||||
{
|
||||
for (j = 0; j < l; j++)
|
||||
if (SSA_NAME_VAR (name) == adjustments[j].base
|
||||
&& adjustments[j].new_decl)
|
||||
{
|
||||
tree base_var;
|
||||
if (adjustments[j].new_ssa_base == NULL_TREE)
|
||||
{
|
||||
base_var
|
||||
= copy_var_decl (adjustments[j].base,
|
||||
DECL_NAME (adjustments[j].base),
|
||||
TREE_TYPE (adjustments[j].base));
|
||||
adjustments[j].new_ssa_base = base_var;
|
||||
}
|
||||
else
|
||||
base_var = adjustments[j].new_ssa_base;
|
||||
if (SSA_NAME_IS_DEFAULT_DEF (name))
|
||||
{
|
||||
bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
gimple_stmt_iterator gsi = gsi_after_labels (bb);
|
||||
tree new_decl = unshare_expr (adjustments[j].new_decl);
|
||||
set_ssa_default_def (cfun, adjustments[j].base, NULL_TREE);
|
||||
SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
|
||||
SSA_NAME_IS_DEFAULT_DEF (name) = 0;
|
||||
gimple *stmt = gimple_build_assign (name, new_decl);
|
||||
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
|
||||
}
|
||||
else
|
||||
SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
|
||||
}
|
||||
if (SSA_NAME_IS_DEFAULT_DEF (name))
|
||||
{
|
||||
tree old_decl = SSA_NAME_VAR (name);
|
||||
bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
gimple_stmt_iterator gsi = gsi_after_labels (bb);
|
||||
tree repl = adjustments->lookup_replacement (old_decl, 0);
|
||||
gcc_checking_assert (repl);
|
||||
repl = unshare_expr (repl);
|
||||
set_ssa_default_def (cfun, old_decl, NULL_TREE);
|
||||
SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
|
||||
SSA_NAME_IS_DEFAULT_DEF (name) = 0;
|
||||
gimple *stmt = gimple_build_assign (name, repl);
|
||||
gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
|
||||
}
|
||||
else
|
||||
SET_SSA_NAME_VAR_OR_IDENTIFIER (name, base_var);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1162,8 +1172,9 @@ simd_clone_adjust (struct cgraph_node *node)
|
||||
targetm.simd_clone.adjust (node);
|
||||
|
||||
tree retval = simd_clone_adjust_return_type (node);
|
||||
ipa_parm_adjustment_vec adjustments
|
||||
ipa_param_body_adjustments *adjustments
|
||||
= simd_clone_adjust_argument_types (node);
|
||||
gcc_assert (adjustments);
|
||||
|
||||
push_gimplify_context ();
|
||||
|
||||
@ -1175,7 +1186,7 @@ simd_clone_adjust (struct cgraph_node *node)
|
||||
tree iter1 = make_ssa_name (iter);
|
||||
tree iter2 = NULL_TREE;
|
||||
ipa_simd_modify_function_body (node, adjustments, retval, iter1);
|
||||
adjustments.release ();
|
||||
delete adjustments;
|
||||
|
||||
/* Initialize the iteration variable. */
|
||||
basic_block entry_bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
|
@ -1062,6 +1062,13 @@ DEFPARAM (PARAM_IPA_SRA_PTR_GROWTH_FACTOR,
|
||||
"that ipa-sra replaces a pointer to an aggregate with.",
|
||||
2, 0, 0)
|
||||
|
||||
DEFPARAM (PARAM_IPA_SRA_MAX_REPLACEMENTS,
|
||||
"ipa-sra-max-replacements",
|
||||
"Maximum pieces that IPA-SRA tracks per formal parameter, as "
|
||||
"a consequence, also the maximum number of replacements of a formal "
|
||||
"parameter.",
|
||||
8, 0, 16)
|
||||
|
||||
DEFPARAM (PARAM_TM_MAX_AGGREGATE_SIZE,
|
||||
"tm-max-aggregate-size",
|
||||
"Size in bytes after which thread-local aggregates should be "
|
||||
|
@ -89,7 +89,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
NEXT_PASS (pass_dse);
|
||||
NEXT_PASS (pass_cd_dce);
|
||||
NEXT_PASS (pass_phiopt, true /* early_p */);
|
||||
NEXT_PASS (pass_early_ipa_sra);
|
||||
NEXT_PASS (pass_tail_recursion);
|
||||
NEXT_PASS (pass_convert_switch);
|
||||
NEXT_PASS (pass_cleanup_eh);
|
||||
@ -148,6 +147,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
NEXT_PASS (pass_ipa_icf);
|
||||
NEXT_PASS (pass_ipa_devirt);
|
||||
NEXT_PASS (pass_ipa_cp);
|
||||
NEXT_PASS (pass_ipa_sra);
|
||||
NEXT_PASS (pass_ipa_cdtor_merge);
|
||||
NEXT_PASS (pass_ipa_hsa);
|
||||
NEXT_PASS (pass_ipa_fn_summary);
|
||||
|
@ -1,3 +1,43 @@
|
||||
2019-09-20 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* g++.dg/ipa/pr81248.C: Adjust dg-options and dump-scan.
|
||||
* gcc.dg/ipa/ipa-sra-1.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-10.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-11.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-3.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-4.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-5.c: Likewise.
|
||||
* gcc.dg/ipa/ipacost-2.c: Disable ipa-sra.
|
||||
* gcc.dg/ipa/ipcp-agg-9.c: Likewise.
|
||||
* gcc.dg/ipa/pr78121.c: Adjust scan pattern.
|
||||
* gcc.dg/ipa/vrp1.c: Likewise.
|
||||
* gcc.dg/ipa/vrp2.c: Likewise.
|
||||
* gcc.dg/ipa/vrp3.c: Likewise.
|
||||
* gcc.dg/ipa/vrp7.c: Likewise.
|
||||
* gcc.dg/ipa/vrp8.c: Likewise.
|
||||
* gcc.dg/noreorder.c: use noipa attribute instead of noinline.
|
||||
* gcc.dg/ipa/20040703-wpa.c: New test.
|
||||
* gcc.dg/ipa/ipa-sra-12.c: New test.
|
||||
* gcc.dg/ipa/ipa-sra-13.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-14.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-15.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-16.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-17.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-18.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-19.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-20.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-21.c: Likewise.
|
||||
* gcc.dg/ipa/ipa-sra-22.c: Likewise.
|
||||
* gcc.dg/sso/ipa-sra-1.c: Likewise.
|
||||
* g++.dg/ipa/ipa-sra-2.C: Likewise.
|
||||
* g++.dg/ipa/ipa-sra-3.C: Likewise.
|
||||
* gcc.dg/tree-ssa/ipa-cp-1.c: Make return value used.
|
||||
* g++.dg/ipa/devirt-19.C: Add missing return, add -fipa-cp-clone
|
||||
option.
|
||||
* g++.dg/lto/devirt-19_0.C: Add -fipa-cp-clone option.
|
||||
* gcc.dg/ipa/ipa-sra-2.c: Removed.
|
||||
* gcc.dg/ipa/ipa-sra-6.c: Likewise.
|
||||
|
||||
2019-09-19 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91631
|
||||
|
@ -2,7 +2,7 @@
|
||||
Previously we were failing by considering CLOBBER statement to be
|
||||
a type change. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-ipa-cp" } */
|
||||
/* { dg-options "-O2 -fdump-ipa-cp -fipa-cp-clone" } */
|
||||
/* { dg-additional-options "-Wno-return-type" } */
|
||||
|
||||
struct A {
|
||||
@ -23,9 +23,12 @@ public:
|
||||
|
||||
C<int, int> b;
|
||||
template <typename T, typename M> const M &C<T, M>::m_fn2(const T &) {
|
||||
|
||||
A a = _map.m_fn2();
|
||||
a == _map.m_fn1();
|
||||
m_fn1();
|
||||
static M m;
|
||||
return m;
|
||||
}
|
||||
|
||||
void fn1() { b.m_fn2(0); }
|
||||
|
46
gcc/testsuite/g++.dg/ipa/ipa-sra-1.C
Normal file
46
gcc/testsuite/g++.dg/ipa/ipa-sra-1.C
Normal file
@ -0,0 +1,46 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra" } */
|
||||
|
||||
void fn1(int *, int *, double *, int *, double *);
|
||||
int a, c, d, e, f, g, k;
|
||||
double *b;
|
||||
double h, i;
|
||||
void fn2(int *p1, int *p2, double *p3) {
|
||||
int l = 0, j, q, r;
|
||||
double m, n, o, p, s, t, u;
|
||||
--p3;
|
||||
for (; a;) {
|
||||
if (c) {
|
||||
++*p2;
|
||||
goto L170;
|
||||
}
|
||||
m = n = b[c];
|
||||
p = t = m;
|
||||
for (; j; ++j) {
|
||||
u = 1.;
|
||||
if (k) {
|
||||
s = o;
|
||||
u = -1.;
|
||||
}
|
||||
}
|
||||
i = u * p;
|
||||
L60:
|
||||
p3[1] = s;
|
||||
for (; d;)
|
||||
goto L60;
|
||||
fn1(&f, &g, &h, &l, &p3[1]);
|
||||
o = p3[1];
|
||||
L100:
|
||||
o *= i;
|
||||
if (e)
|
||||
goto L100;
|
||||
L170:;
|
||||
}
|
||||
if (*p1)
|
||||
for (;;) {
|
||||
if (r)
|
||||
q = *p2;
|
||||
d = q - j;
|
||||
r = j;
|
||||
}
|
||||
}
|
19
gcc/testsuite/g++.dg/ipa/ipa-sra-2.C
Normal file
19
gcc/testsuite/g++.dg/ipa/ipa-sra-2.C
Normal file
@ -0,0 +1,19 @@
|
||||
/* { dg-do compile { target c++11 } } */
|
||||
/* { dg-options "-O2 -fipa-sra" } */
|
||||
|
||||
class a {
|
||||
void b();
|
||||
char16_t c;
|
||||
char16_t d;
|
||||
};
|
||||
void e(a);
|
||||
void g();
|
||||
void a::b() {
|
||||
char16_t f = d;
|
||||
e(*this);
|
||||
for (;;) {
|
||||
g();
|
||||
if (f)
|
||||
break;
|
||||
}
|
||||
}
|
9
gcc/testsuite/g++.dg/ipa/ipa-sra-3.C
Normal file
9
gcc/testsuite/g++.dg/ipa/ipa-sra-3.C
Normal file
@ -0,0 +1,9 @@
|
||||
/* { dg-options "-O2 -fipa-sra -fno-inline -fno-ipa-cp" } */
|
||||
|
||||
|
||||
char *a() __attribute__((__malloc__));
|
||||
static char *b() {
|
||||
char *c = a();
|
||||
return c;
|
||||
}
|
||||
int d() { b(); return 4; }
|
@ -1,5 +1,5 @@
|
||||
// { dg-do compile { target c++17 } }
|
||||
// { dg-options "-O2 -fdump-tree-eipa_sra" }
|
||||
// { dg-options "-O2 -fdump-ipa-sra" }
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
@ -37,4 +37,4 @@ int main() {
|
||||
f(n2);
|
||||
}
|
||||
|
||||
// { dg-final { scan-tree-dump-times "Adjusting call" 2 "eipa_sra" } }
|
||||
// { dg-final { scan-ipa-dump "Will split parameter 0" "sra" } }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-lto-do link } */
|
||||
/* { dg-lto-options { "-O2 -fdump-ipa-cp -Wno-return-type -flto -r -nostdlib" } } */
|
||||
/* { dg-lto-options { "-O2 -fdump-ipa-cp -fipa-cp-clone -Wno-return-type -flto -r -nostdlib" } } */
|
||||
/* { dg-extra-ld-options "-flinker-output=nolto-rel -flto=auto" } */
|
||||
#include "../ipa/devirt-19.C"
|
||||
/* { dg-final { scan-wpa-ipa-dump-times "Discovered a virtual call to a known target" 1 "cp" } } */
|
||||
|
151
gcc/testsuite/gcc.dg/ipa/20040703-wpa.c
Normal file
151
gcc/testsuite/gcc.dg/ipa/20040703-wpa.c
Normal file
@ -0,0 +1,151 @@
|
||||
/* With -fwhole-program this is an excelent testcase for inlining IPA-SRAed
|
||||
functions into each other. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -w -fno-ipa-cp -fwhole-program" } */
|
||||
/* { dg-require-effective-target int32plus } */
|
||||
|
||||
#define PART_PRECISION (sizeof (cpp_num_part) * 8)
|
||||
|
||||
typedef unsigned int cpp_num_part;
|
||||
typedef struct cpp_num cpp_num;
|
||||
struct cpp_num
|
||||
{
|
||||
cpp_num_part high;
|
||||
cpp_num_part low;
|
||||
int unsignedp; /* True if value should be treated as unsigned. */
|
||||
int overflow; /* True if the most recent calculation overflowed. */
|
||||
};
|
||||
|
||||
static int
|
||||
num_positive (cpp_num num, unsigned int precision)
|
||||
{
|
||||
if (precision > PART_PRECISION)
|
||||
{
|
||||
precision -= PART_PRECISION;
|
||||
return (num.high & (cpp_num_part) 1 << (precision - 1)) == 0;
|
||||
}
|
||||
|
||||
return (num.low & (cpp_num_part) 1 << (precision - 1)) == 0;
|
||||
}
|
||||
|
||||
static cpp_num
|
||||
num_trim (cpp_num num, unsigned int precision)
|
||||
{
|
||||
if (precision > PART_PRECISION)
|
||||
{
|
||||
precision -= PART_PRECISION;
|
||||
if (precision < PART_PRECISION)
|
||||
num.high &= ((cpp_num_part) 1 << precision) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (precision < PART_PRECISION)
|
||||
num.low &= ((cpp_num_part) 1 << precision) - 1;
|
||||
num.high = 0;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Shift NUM, of width PRECISION, right by N bits. */
|
||||
static cpp_num
|
||||
num_rshift (cpp_num num, unsigned int precision, unsigned int n)
|
||||
{
|
||||
cpp_num_part sign_mask;
|
||||
int x = num_positive (num, precision);
|
||||
|
||||
if (num.unsignedp || x)
|
||||
sign_mask = 0;
|
||||
else
|
||||
sign_mask = ~(cpp_num_part) 0;
|
||||
|
||||
if (n >= precision)
|
||||
num.high = num.low = sign_mask;
|
||||
else
|
||||
{
|
||||
/* Sign-extend. */
|
||||
if (precision < PART_PRECISION)
|
||||
num.high = sign_mask, num.low |= sign_mask << precision;
|
||||
else if (precision < 2 * PART_PRECISION)
|
||||
num.high |= sign_mask << (precision - PART_PRECISION);
|
||||
|
||||
if (n >= PART_PRECISION)
|
||||
{
|
||||
n -= PART_PRECISION;
|
||||
num.low = num.high;
|
||||
num.high = sign_mask;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
num.low = (num.low >> n) | (num.high << (PART_PRECISION - n));
|
||||
num.high = (num.high >> n) | (sign_mask << (PART_PRECISION - n));
|
||||
}
|
||||
}
|
||||
|
||||
num = num_trim (num, precision);
|
||||
num.overflow = 0;
|
||||
return num;
|
||||
}
|
||||
#define num_zerop(num) ((num.low | num.high) == 0)
|
||||
#define num_eq(num1, num2) (num1.low == num2.low && num1.high == num2.high)
|
||||
|
||||
cpp_num
|
||||
num_lshift (cpp_num num, unsigned int precision, unsigned int n)
|
||||
{
|
||||
if (n >= precision)
|
||||
{
|
||||
num.overflow = !num.unsignedp && !num_zerop (num);
|
||||
num.high = num.low = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpp_num orig;
|
||||
unsigned int m = n;
|
||||
|
||||
orig = num;
|
||||
if (m >= PART_PRECISION)
|
||||
{
|
||||
m -= PART_PRECISION;
|
||||
num.high = num.low;
|
||||
num.low = 0;
|
||||
}
|
||||
if (m)
|
||||
{
|
||||
num.high = (num.high << m) | (num.low >> (PART_PRECISION - m));
|
||||
num.low <<= m;
|
||||
}
|
||||
num = num_trim (num, precision);
|
||||
|
||||
if (num.unsignedp)
|
||||
num.overflow = 0;
|
||||
else
|
||||
{
|
||||
cpp_num maybe_orig = num_rshift (num, precision, n);
|
||||
num.overflow = !num_eq (orig, maybe_orig);
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
unsigned int precision = 64;
|
||||
unsigned int n = 16;
|
||||
|
||||
cpp_num num = { 0, 3, 0, 0 };
|
||||
|
||||
int main()
|
||||
{
|
||||
cpp_num res = num_lshift (num, 64, n);
|
||||
|
||||
if (res.low != 0x30000)
|
||||
abort ();
|
||||
|
||||
if (res.high != 0)
|
||||
abort ();
|
||||
|
||||
if (res.overflow != 0)
|
||||
abort ();
|
||||
|
||||
exit (0);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra-details" } */
|
||||
|
||||
struct bovid
|
||||
{
|
||||
@ -36,4 +36,4 @@ main (int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "About to replace expr" 2 "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump "Will split parameter" "sra" } } */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-options "-O2 -fno-ipa-cp -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
extern void consume (int);
|
||||
extern int glob, glob1, glob2;
|
||||
@ -31,4 +31,4 @@ bar (int a)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "replacing an SSA name of a removed param" 4 "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump "Will remove parameter 0" "sra" } } */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra-details" } */
|
||||
|
||||
struct bovid
|
||||
{
|
||||
@ -36,4 +36,4 @@ main (int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-not "About to replace expr" "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-not "Will split parameter" "sra" } } */
|
||||
|
50
gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c
Normal file
50
gcc/testsuite/gcc.dg/ipa/ipa-sra-12.c
Normal file
@ -0,0 +1,50 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
/* Check of a simple and transitive structure split. */
|
||||
|
||||
struct S
|
||||
{
|
||||
float red;
|
||||
void *blue;
|
||||
int green;
|
||||
};
|
||||
|
||||
|
||||
void __attribute__((noipa))
|
||||
check (float r, int g, int g2)
|
||||
{
|
||||
if (r < 7.39 || r > 7.41
|
||||
|| g != 6 || g2 != 6)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
foo (struct S s)
|
||||
{
|
||||
check (s.red, s.green, s.green);
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
bar (struct S s)
|
||||
{
|
||||
foo (s);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct S s;
|
||||
|
||||
s.red = 7.4;
|
||||
s.green = 6;
|
||||
s.blue = &s;
|
||||
|
||||
bar (s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */
|
49
gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c
Normal file
49
gcc/testsuite/gcc.dg/ipa/ipa-sra-13.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
/* Check of a by-reference structure split. */
|
||||
|
||||
struct S
|
||||
{
|
||||
float red;
|
||||
void *blue;
|
||||
int green;
|
||||
};
|
||||
|
||||
void __attribute__((noipa))
|
||||
check (float r, int g, int g2)
|
||||
{
|
||||
if (r < 7.39 || r > 7.41
|
||||
|| g != 6 || g2 != 6)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
foo (struct S *s)
|
||||
{
|
||||
check (s->red, s->green, s->green);
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
bar (struct S *s)
|
||||
{
|
||||
foo (s);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct S s;
|
||||
|
||||
s.red = 7.4;
|
||||
s.green = 6;
|
||||
s.blue = &s;
|
||||
|
||||
bar (&s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */
|
60
gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c
Normal file
60
gcc/testsuite/gcc.dg/ipa/ipa-sra-14.c
Normal file
@ -0,0 +1,60 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
/* Check of a transitive recursive structure split. */
|
||||
|
||||
struct S
|
||||
{
|
||||
float red;
|
||||
void *blue;
|
||||
int green;
|
||||
};
|
||||
|
||||
|
||||
static int done = 0;
|
||||
|
||||
void __attribute__((noipa))
|
||||
check (float r, int g, int g2)
|
||||
{
|
||||
if (r < 7.39 || r > 7.41
|
||||
|| g != 6 || g2 != 6)
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
static void __attribute__((noinline)) bar (struct S s);
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
foo (struct S s)
|
||||
{
|
||||
if (!done)
|
||||
{
|
||||
done = 1;
|
||||
bar (s);
|
||||
}
|
||||
check (s.red, s.green, s.green);
|
||||
}
|
||||
|
||||
static void
|
||||
__attribute__((noinline))
|
||||
bar (struct S s)
|
||||
{
|
||||
foo (s);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct S s;
|
||||
|
||||
s.red = 7.4;
|
||||
s.green = 6;
|
||||
s.blue = &s;
|
||||
|
||||
bar (s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */
|
61
gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c
Normal file
61
gcc/testsuite/gcc.dg/ipa/ipa-sra-15.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
/* Check of a recursive by-reference structure split. The recursive functions
|
||||
have to be pure right from the start, otherwise the current AA would detect
|
||||
possible modification of data. */
|
||||
|
||||
struct S
|
||||
{
|
||||
float red;
|
||||
void *blue;
|
||||
int green;
|
||||
};
|
||||
|
||||
void __attribute__((noipa))
|
||||
check (float r, int g, int g2)
|
||||
{
|
||||
if (r < 7.39 || r > 7.41
|
||||
|| g != 6 || g2 != 6)
|
||||
__builtin_abort ();
|
||||
return;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline, pure)) bar (struct S *s, int rec);
|
||||
|
||||
static int
|
||||
__attribute__((noinline, pure))
|
||||
foo (struct S *s , int rec)
|
||||
{
|
||||
int t = 0;
|
||||
if (rec)
|
||||
t = bar (s, 0);
|
||||
check (s->red, s->green, s->green);
|
||||
return t;
|
||||
}
|
||||
|
||||
static int
|
||||
__attribute__((noinline, pure))
|
||||
bar (struct S *s, int rec)
|
||||
{
|
||||
int t = foo (s, rec);
|
||||
return t + t;
|
||||
}
|
||||
|
||||
volatile int g;
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct S s;
|
||||
|
||||
s.red = 7.4;
|
||||
s.green = 6;
|
||||
s.blue = &s;
|
||||
|
||||
g = bar (&s, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "component at byte offset" 4 "sra" } } */
|
74
gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c
Normal file
74
gcc/testsuite/gcc.dg/ipa/ipa-sra-16.c
Normal file
@ -0,0 +1,74 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra -fdump-tree-optimized" } */
|
||||
|
||||
/* Testing removal of unused parameters in recursive calls. */
|
||||
|
||||
extern int work_1 (int);
|
||||
extern int work_2 (int);
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo (int l, int w1, int w2, int useless, int useless2);
|
||||
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bar_1 (int l, int w1, int w2, int useless, int useless2)
|
||||
{
|
||||
return work_1 (w1) + foo (l, w1, w2, useless2, useless);
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
baz_1 (int useless, int useless2, int l, int w1, int w2)
|
||||
{
|
||||
return bar_1 (l, w1, w2, useless, useless2);
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bax_1 (int l, int w1, int w2, int useless, int useless2)
|
||||
{
|
||||
return baz_1 (useless, useless2, l, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bar_2 (int l, int w1, int w2, int useless, int useless2)
|
||||
{
|
||||
return foo (l, w1, w2, useless2 + 5, useless);
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
baz_2 (int useless, int useless2, int l, int w1, int w2)
|
||||
{
|
||||
return bar_2 (l, w1, w2, useless, useless2);
|
||||
}
|
||||
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bax_2 (int l, int w1, int w2, int useless, int useless2)
|
||||
{
|
||||
return work_2 (w2) + baz_2 (useless, useless2, l, w1, w2);
|
||||
}
|
||||
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo (int l, int w1, int w2, int useless, int useless2)
|
||||
{
|
||||
int r = 0;
|
||||
if (!l)
|
||||
return r;
|
||||
if (l % 2)
|
||||
r = bax_1 (l - 1, w1, w2, useless, useless2);
|
||||
else
|
||||
r = bax_2 (l - 1, w1, w2, useless, useless2);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
entry (int l, int w1, int w2, int noneed, int noneed2)
|
||||
{
|
||||
return foo (l, w2, w2, noneed2, noneed2 + 4);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will remove parameter" 14 "sra" } } */
|
||||
/* { dg-final { scan-tree-dump-not "useless" "optimized"} } */
|
102
gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c
Normal file
102
gcc/testsuite/gcc.dg/ipa/ipa-sra-17.c
Normal file
@ -0,0 +1,102 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-ipa-sra -fdump-tree-optimized" } */
|
||||
|
||||
#define DOIT
|
||||
#define DONT
|
||||
|
||||
|
||||
extern int extern_leaf (int);
|
||||
|
||||
/* ----- 1 ----- */
|
||||
#ifdef DOIT
|
||||
static int __attribute__((noinline))
|
||||
whee_1 (int i, int j)
|
||||
{
|
||||
return extern_leaf (i * j) + 1;
|
||||
}
|
||||
|
||||
static int foo_1 (int i, int j);
|
||||
|
||||
static int __attribute__((noinline))
|
||||
baz_1 (int i, int j)
|
||||
{
|
||||
int a = 5;
|
||||
if (j)
|
||||
a = foo_1 (i, j - 1);
|
||||
return whee_1 (i, j) + a + 1;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bar_1 (int i, int j)
|
||||
{
|
||||
return baz_1 (i, j) + 1;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo_1 (int i, int j)
|
||||
{
|
||||
return bar_1 (i, j) + 1;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
inter_1 (int i, int j)
|
||||
{
|
||||
return foo_1 (i, j) + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----- 2 ----- */
|
||||
#ifdef DONT
|
||||
static int __attribute__((noinline))
|
||||
whee_2 (int i, int j)
|
||||
{
|
||||
return extern_leaf (i * j) + 2;
|
||||
}
|
||||
|
||||
static int foo_2 (int i, int j);
|
||||
|
||||
static int __attribute__((noinline))
|
||||
baz_2 (int i, int j)
|
||||
{
|
||||
int a = 6;
|
||||
if (j)
|
||||
a = foo_2 (i, j - 1);
|
||||
return whee_2 (i, j) + a + 2;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
bar_2 (int i, int j)
|
||||
{
|
||||
return baz_2 (i, j) + 2;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
foo_2 (int i, int j)
|
||||
{
|
||||
return bar_2 (i, j) + 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----- entries ----- */
|
||||
#ifdef DOIT
|
||||
int
|
||||
entry_1 (int i, int j)
|
||||
{
|
||||
inter_1 (i, j);
|
||||
return i + j + 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DONT
|
||||
int
|
||||
entry_2 (int i, int j)
|
||||
{
|
||||
#ifdef DOIT
|
||||
inter_1 (i, j);
|
||||
#endif
|
||||
return i + j + bar_2 (i, j);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will remove return value" 5 "sra" } } */
|
||||
/* { dg-final { scan-tree-dump-times "return;" 5 "optimized"} } */
|
49
gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c
Normal file
49
gcc/testsuite/gcc.dg/ipa/ipa-sra-18.c
Normal file
@ -0,0 +1,49 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-ipa-sra" } */
|
||||
|
||||
struct S
|
||||
{
|
||||
long a, b;
|
||||
};
|
||||
|
||||
extern void leaf_a (int );
|
||||
extern void leaf_b (int, int);
|
||||
extern void leaf_c (int, int);
|
||||
|
||||
extern void leaf_sa (struct S);
|
||||
|
||||
static void baz (int i, int j, int k, int l, struct S a, struct S b);
|
||||
|
||||
extern int gi;
|
||||
|
||||
static void __attribute__((noinline))
|
||||
foo (int i, int j, int k, int l, struct S a, struct S b)
|
||||
{
|
||||
gi += l;
|
||||
baz (i, j, k, l, a, b);
|
||||
}
|
||||
|
||||
static void __attribute__((noinline))
|
||||
bar (int i, int j, int k, int l, struct S a, struct S b)
|
||||
{
|
||||
foo (i, j, k, l, a, b);
|
||||
leaf_sa (b);
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((noinline))
|
||||
baz (int i, int j, int k, int l, struct S a, struct S b)
|
||||
{
|
||||
if (--k)
|
||||
bar (i, j, k, l, a, b);
|
||||
leaf_b (i, k);
|
||||
}
|
||||
|
||||
void
|
||||
entry (int i, int j, int k, int l, struct S a, struct S b)
|
||||
{
|
||||
foo (i, j, k, l, a, b);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Will remove parameter 1" 3 "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Will remove parameter 4" 3 "sra" } } */
|
31
gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c
Normal file
31
gcc/testsuite/gcc.dg/ipa/ipa-sra-19.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef int __attribute__((__vector_size__(16))) vectype;
|
||||
|
||||
vectype dk();
|
||||
vectype k();
|
||||
|
||||
int b;
|
||||
vectype *j;
|
||||
inline int c(vectype *d) {
|
||||
vectype e;
|
||||
vectype f;
|
||||
vectype g = *d;
|
||||
vectype h = g;
|
||||
vectype i = h;
|
||||
f = i == dk();
|
||||
e = f == b;
|
||||
k(e);
|
||||
}
|
||||
|
||||
static void m(vectype *d) {
|
||||
int l = c(d);
|
||||
if (l)
|
||||
c(j);
|
||||
}
|
||||
|
||||
void o(void) {
|
||||
vectype n;
|
||||
m(&n);
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
|
||||
struct bovid
|
||||
{
|
||||
float red;
|
||||
int green;
|
||||
void *blue;
|
||||
};
|
||||
|
||||
static int
|
||||
__attribute__((noinline))
|
||||
ox (struct bovid *cow)
|
||||
{
|
||||
cow->red = cow->red + cow->green + cow->green;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int something;
|
||||
|
||||
static int
|
||||
__attribute__((noinline))
|
||||
ox_improved (struct bovid *calf)
|
||||
{
|
||||
if (something > 0)
|
||||
calf->red = calf->red + calf->green;
|
||||
else
|
||||
calf->red = calf->green + 87;
|
||||
something = 77;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct bovid cow;
|
||||
|
||||
cow.red = 7.4;
|
||||
cow.green = 6;
|
||||
cow.blue = &cow;
|
||||
|
||||
ox (&cow);
|
||||
|
||||
ox_improved (&cow);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "About to replace expr cow_.*D.->red with \\*ISRA" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump "About to replace expr cow_.*D.->green with ISRA" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump "About to replace expr calf_.*D.->red with \\*ISRA" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump "About to replace expr calf_.*D.->green with ISRA" "eipa_sra" } } */
|
38
gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c
Normal file
38
gcc/testsuite/gcc.dg/ipa/ipa-sra-20.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O1 -fipa-sra" } */
|
||||
|
||||
typedef struct {
|
||||
int a;
|
||||
} b;
|
||||
typedef struct {
|
||||
double c;
|
||||
double a;
|
||||
} d;
|
||||
typedef struct {
|
||||
d e;
|
||||
d f;
|
||||
} g;
|
||||
g h;
|
||||
b i, m;
|
||||
int j, k, l, n, o;
|
||||
static b q(d s) {
|
||||
int r = s.c ?: 0;
|
||||
if (r)
|
||||
if (j)
|
||||
l = j - 2;
|
||||
o = k;
|
||||
n = l;
|
||||
i = m;
|
||||
return m;
|
||||
}
|
||||
static void t(g s) {
|
||||
{
|
||||
d p = s.e;
|
||||
int r = p.c ?: 0;
|
||||
if (r) {
|
||||
l = j - 2;
|
||||
}
|
||||
}
|
||||
b f = q(s.f);
|
||||
}
|
||||
void main() { t(h); }
|
33
gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c
Normal file
33
gcc/testsuite/gcc.dg/ipa/ipa-sra-21.c
Normal file
@ -0,0 +1,33 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2" } */
|
||||
|
||||
typedef int a;
|
||||
typedef int b;
|
||||
int c, e;
|
||||
void i();
|
||||
void n(d, ab, f, ae, af, action, ag, ah, ai, g, h, aj, ak, al, j, k, am, an, ao,
|
||||
l, m) int action,
|
||||
ag;
|
||||
int f, ae, af;
|
||||
int ah, ai;
|
||||
int j, k;
|
||||
int l, m;
|
||||
a aj, am;
|
||||
int ak, al, an, ao, g, h;
|
||||
char d, ab;
|
||||
{
|
||||
if (c)
|
||||
i(e);
|
||||
}
|
||||
void o(d, ab, action, at, ag, g, h, aj, ak, al, au, av, am, an, ao, aw, ax, ay,
|
||||
az, ba, bb, ai) int action,
|
||||
ag;
|
||||
int at, ai;
|
||||
int au, av, aw, ax;
|
||||
b ay, ba;
|
||||
int az, bb;
|
||||
int g, h;
|
||||
int ak, al, an, ao;
|
||||
a aj, am;
|
||||
char d, ab;
|
||||
{ n(); }
|
56
gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c
Normal file
56
gcc/testsuite/gcc.dg/ipa/ipa-sra-22.c
Normal file
@ -0,0 +1,56 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra" } */
|
||||
|
||||
struct W
|
||||
{
|
||||
int a, b;
|
||||
};
|
||||
|
||||
union U
|
||||
{
|
||||
struct W w;
|
||||
long l;
|
||||
};
|
||||
|
||||
struct Z
|
||||
{
|
||||
int k;
|
||||
union U u;
|
||||
};
|
||||
|
||||
struct S
|
||||
{
|
||||
int i, j;
|
||||
struct Z z;
|
||||
char buf[64];
|
||||
};
|
||||
|
||||
struct W gw;
|
||||
|
||||
|
||||
static long
|
||||
__attribute__((noinline))
|
||||
foo (struct Z z)
|
||||
{
|
||||
return z.u.l;
|
||||
}
|
||||
|
||||
static long
|
||||
__attribute__((noinline))
|
||||
bar (struct S s)
|
||||
{
|
||||
if (s.i > 100)
|
||||
return s.z.u.w.a;
|
||||
else
|
||||
return foo (s.z);
|
||||
}
|
||||
|
||||
volatile long g;
|
||||
|
||||
long
|
||||
entry (struct S *p)
|
||||
{
|
||||
struct S s = *p;
|
||||
|
||||
return bar (s) | 2;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-options "-O2 -fno-ipa-cp -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
struct bovid
|
||||
{
|
||||
@ -34,5 +34,6 @@ void caller (void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "base: z, remove_param" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump "base: calf, remove_param" "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump "Will split parameter 0" "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump "Will remove parameter 1" "sra" } } */
|
||||
/* { dg-final { scan-ipa-dump "Will remove parameter 2" "sra" } } */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-options "-O2 -fipa-sra -fno-ipa-pure-const -fdump-ipa-sra" } */
|
||||
|
||||
static int
|
||||
__attribute__((noinline))
|
||||
@ -61,7 +61,5 @@ void caller (void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump "About to replace expr \\*i_.*D. with ISRA" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump "About to replace expr \\*l_.*D. with ISRA" "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump-times "About to replace expr \*j_.*D. with ISRA" 0 "eipa_sra" } } */
|
||||
/* { dg-final { scan-tree-dump-times "About to replace expr \*k_.*D. with ISRA" 0 "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-ipa-sra" } */
|
||||
|
||||
static int *
|
||||
__attribute__((noinline,used))
|
||||
@ -16,4 +16,4 @@ int *caller (void)
|
||||
|
||||
return ox (&a, &b);
|
||||
}
|
||||
/* { dg-final { scan-tree-dump-times "base: j, remove_param" 0 "eipa_sra" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Will split parameter" 0 "sra" } } */
|
||||
|
@ -1,33 +0,0 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-slim" } */
|
||||
/* { dg-require-effective-target non_strict_align } */
|
||||
|
||||
struct bovid
|
||||
{
|
||||
float a;
|
||||
int b;
|
||||
struct bovid *next;
|
||||
};
|
||||
|
||||
static int
|
||||
__attribute__((noinline))
|
||||
foo (struct bovid *cow, int i)
|
||||
{
|
||||
i++;
|
||||
if (cow->next)
|
||||
foo (cow->next, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct bovid cow;
|
||||
|
||||
cow.a = 7.4;
|
||||
cow.b = 6;
|
||||
cow.next = (struct bovid *) 0;
|
||||
|
||||
return foo (&cow, 0);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "foo " 1 "eipa_sra" } } */
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-ipa-cp -fno-early-inlining -fdump-tree-optimized -fno-ipa-icf" } */
|
||||
/* { dg-options "-O3 -fipa-cp -fipa-cp-clone -fdump-ipa-cp -fno-early-inlining -fno-ipa-sra -fdump-tree-optimized -fno-ipa-icf" } */
|
||||
/* { dg-add-options bind_pic_locally } */
|
||||
|
||||
int array[100];
|
||||
@ -72,7 +72,7 @@ main()
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully2" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully/" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Creating a specialized node of i_can_be_propagated_fully\[./\]" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-not "Creating a specialized node of i_can_not_be_propagated_fully2" "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-not "Creating a specialized node of i_can_not_be_propagated_fully/" "cp" } } */
|
||||
/* { dg-final { scan-tree-dump-not "i_can_be_propagated_fully \\(" "optimized" } } */
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Verify that IPA-CP can make edges direct based on aggregate contents. */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O3 -fno-early-inlining -fdump-ipa-cp -fdump-ipa-inline" } */
|
||||
/* { dg-options "-O3 -fno-early-inlining -fno-ipa-sra -fdump-ipa-cp -fdump-ipa-inline" } */
|
||||
|
||||
struct S
|
||||
{
|
||||
|
@ -13,4 +13,4 @@ static void fn1(c) unsigned char c;
|
||||
|
||||
void fn3() { fn1 (267); }
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[11, 35\\\]" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[11, 35\\\]" "cp" } } */
|
||||
|
@ -28,5 +28,5 @@ int main ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[6," "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 999\\\]" "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[6," "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[0, 999\\\]" "cp" } } */
|
||||
|
@ -31,5 +31,5 @@ int main ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[4," "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\\[0, 11\\\]" "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[4," "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump "Setting value range of param 0 \\(now 0\\) \\\[0, 11\\\]" "cp" } } */
|
||||
|
@ -27,4 +27,4 @@ int main ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[0, 9\\\]" 2 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[0, 9\\\]" 2 "cp" } } */
|
||||
|
@ -29,4 +29,4 @@ int main ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[-10, 9\\\]" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[-10, 9\\\]" 1 "cp" } } */
|
||||
|
@ -39,4 +39,4 @@ main ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\\[-10, 9\\\]" 1 "cp" } } */
|
||||
/* { dg-final { scan-ipa-dump-times "Setting value range of param 0 \\(now 0\\) \\\[-10, 9\\\]" 1 "cp" } } */
|
||||
|
@ -13,7 +13,7 @@ static int func2(void);
|
||||
|
||||
asm("firstasm");
|
||||
|
||||
NOREORDER __attribute__((noinline)) int bozo(void)
|
||||
NOREORDER __attribute__((noipa)) int bozo(void)
|
||||
{
|
||||
f2(3);
|
||||
func2();
|
||||
@ -21,14 +21,14 @@ NOREORDER __attribute__((noinline)) int bozo(void)
|
||||
|
||||
asm("jukjuk");
|
||||
|
||||
NOREORDER __attribute__((noinline)) static int func1(void)
|
||||
NOREORDER __attribute__((noipa)) static int func1(void)
|
||||
{
|
||||
f2(1);
|
||||
}
|
||||
|
||||
asm("barbar");
|
||||
|
||||
NOREORDER __attribute__((noinline)) static int func2(void)
|
||||
NOREORDER __attribute__((noipa)) static int func2(void)
|
||||
{
|
||||
func1();
|
||||
}
|
||||
|
57
gcc/testsuite/gcc.dg/sso/ipa-sra-1.c
Normal file
57
gcc/testsuite/gcc.dg/sso/ipa-sra-1.c
Normal file
@ -0,0 +1,57 @@
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O2 -fipa-sra" } */
|
||||
|
||||
|
||||
struct __attribute__((scalar_storage_order("little-endian"))) LE
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
};
|
||||
|
||||
struct __attribute__((scalar_storage_order("big-endian"))) BE
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
};
|
||||
|
||||
struct LE gle;
|
||||
struct BE gbe;
|
||||
|
||||
#define VAL 0x12345678
|
||||
|
||||
void __attribute__((noipa))
|
||||
fill (void)
|
||||
{
|
||||
gle.i = VAL;
|
||||
gle.j = 0xdeadbeef;
|
||||
gbe.i = VAL;
|
||||
gbe.j = 0x11223344;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
readLE (struct LE p)
|
||||
{
|
||||
return p.i;
|
||||
}
|
||||
|
||||
static int __attribute__((noinline))
|
||||
readBE (struct BE p)
|
||||
{
|
||||
return p.i;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
fill ();
|
||||
|
||||
r = readLE (gle);
|
||||
if (r != VAL)
|
||||
__builtin_abort ();
|
||||
r = readBE (gbe);
|
||||
if (r != VAL)
|
||||
__builtin_abort ();
|
||||
|
||||
return 0;
|
||||
}
|
@ -14,7 +14,7 @@ very_long_function(int a)
|
||||
int
|
||||
blah ()
|
||||
{
|
||||
very_long_function (1);
|
||||
return very_long_function (1);
|
||||
}
|
||||
/* One appearance for dump, one self recursive call and one call from main. */
|
||||
/* { dg-final { scan-tree-dump-times "very_long_function.constprop \\(\\)" 3 "optimized"} } */
|
||||
|
@ -5009,8 +5009,7 @@ ipa_tm_create_version (struct cgraph_node *old_node)
|
||||
}
|
||||
|
||||
tree_function_versioning (old_decl, new_decl,
|
||||
NULL, false, NULL,
|
||||
false, NULL, NULL);
|
||||
NULL, NULL, false, NULL, NULL);
|
||||
}
|
||||
|
||||
record_tm_clone_pair (old_decl, new_decl);
|
||||
|
@ -130,7 +130,6 @@ static void copy_bind_expr (tree *, int *, copy_body_data *);
|
||||
static void declare_inline_vars (tree, tree);
|
||||
static void remap_save_expr (tree *, hash_map<tree, tree> *, int *);
|
||||
static void prepend_lexical_block (tree current_block, tree new_block);
|
||||
static tree copy_decl_to_var (tree, copy_body_data *);
|
||||
static tree copy_result_decl_to_var (tree, copy_body_data *);
|
||||
static tree copy_decl_maybe_to_var (tree, copy_body_data *);
|
||||
static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *);
|
||||
@ -192,7 +191,21 @@ remap_ssa_name (tree name, copy_body_data *id)
|
||||
|
||||
n = id->decl_map->get (name);
|
||||
if (n)
|
||||
return unshare_expr (*n);
|
||||
{
|
||||
/* WHen we perform edge redirection as part of CFG copy, IPA-SRA can
|
||||
remove an unused LHS from a call statement. Such LHS can however
|
||||
still appear in debug statements, but their value is lost in this
|
||||
function and we do not want to map them. */
|
||||
if (id->killed_new_ssa_names
|
||||
&& id->killed_new_ssa_names->contains (*n))
|
||||
{
|
||||
gcc_assert (processing_debug_stmt);
|
||||
processing_debug_stmt = -1;
|
||||
return name;
|
||||
}
|
||||
|
||||
return unshare_expr (*n);
|
||||
}
|
||||
|
||||
if (processing_debug_stmt)
|
||||
{
|
||||
@ -1902,6 +1915,21 @@ remap_gimple_stmt (gimple *stmt, copy_body_data *id)
|
||||
gcc_assert (n);
|
||||
gimple_set_block (copy, *n);
|
||||
}
|
||||
if (id->param_body_adjs)
|
||||
{
|
||||
gimple_seq extra_stmts = NULL;
|
||||
id->param_body_adjs->modify_gimple_stmt (©, &extra_stmts);
|
||||
if (!gimple_seq_empty_p (extra_stmts))
|
||||
{
|
||||
memset (&wi, 0, sizeof (wi));
|
||||
wi.info = id;
|
||||
for (gimple_stmt_iterator egsi = gsi_start (extra_stmts);
|
||||
!gsi_end_p (egsi);
|
||||
gsi_next (&egsi))
|
||||
walk_gimple_op (gsi_stmt (egsi), remap_gimple_op_r, &wi);
|
||||
gimple_seq_add_seq (&stmts, extra_stmts);
|
||||
}
|
||||
}
|
||||
|
||||
if (id->reset_location)
|
||||
gimple_set_location (copy, input_location);
|
||||
@ -2865,10 +2893,24 @@ redirect_all_calls (copy_body_data * id, basic_block bb)
|
||||
gimple *stmt = gsi_stmt (si);
|
||||
if (is_gimple_call (stmt))
|
||||
{
|
||||
tree old_lhs = gimple_call_lhs (stmt);
|
||||
struct cgraph_edge *edge = id->dst_node->get_edge (stmt);
|
||||
if (edge)
|
||||
{
|
||||
edge->redirect_call_stmt_to_callee ();
|
||||
gimple *new_stmt = edge->redirect_call_stmt_to_callee ();
|
||||
/* If IPA-SRA transformation, run as part of edge redirection,
|
||||
removed the LHS because it is unused, save it to
|
||||
killed_new_ssa_names so that we can prune it from debug
|
||||
statements. */
|
||||
if (old_lhs
|
||||
&& TREE_CODE (old_lhs) == SSA_NAME
|
||||
&& !gimple_call_lhs (new_stmt))
|
||||
{
|
||||
if (!id->killed_new_ssa_names)
|
||||
id->killed_new_ssa_names = new hash_set<tree> (16);
|
||||
id->killed_new_ssa_names->add (old_lhs);
|
||||
}
|
||||
|
||||
if (stmt == last && id->call_stmt && maybe_clean_eh_stmt (stmt))
|
||||
gimple_purge_dead_eh_edges (bb);
|
||||
}
|
||||
@ -3189,6 +3231,8 @@ copy_body (copy_body_data *id,
|
||||
body = copy_cfg_body (id, entry_block_map, exit_block_map,
|
||||
new_entry);
|
||||
copy_debug_stmts (id);
|
||||
delete id->killed_new_ssa_names;
|
||||
id->killed_new_ssa_names = NULL;
|
||||
|
||||
return body;
|
||||
}
|
||||
@ -4908,6 +4952,38 @@ 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);
|
||||
|
||||
if (id->src_node->clone.performed_splits)
|
||||
{
|
||||
/* 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 (id->src_node->clone.performed_splits);
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
ipa_param_performed_split ps
|
||||
= (*id->src_node->clone.performed_splits)[i];
|
||||
ps.dummy_decl = remap_decl (ps.dummy_decl, id);
|
||||
vec_safe_push (id->dst_node->clone.performed_splits, ps);
|
||||
}
|
||||
|
||||
if (flag_checking)
|
||||
{
|
||||
len = vec_safe_length (id->dst_node->clone.performed_splits);
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
ipa_param_performed_split *ps1
|
||||
= &(*id->dst_node->clone.performed_splits)[i];
|
||||
for (unsigned j = i + 1; j < len; j++)
|
||||
{
|
||||
ipa_param_performed_split *ps2
|
||||
= &(*id->dst_node->clone.performed_splits)[j];
|
||||
gcc_assert (ps1->dummy_decl != ps2->dummy_decl
|
||||
|| ps1->unit_offset != ps2->unit_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dump_enabled_p ())
|
||||
{
|
||||
char buf[128];
|
||||
@ -5733,7 +5809,11 @@ copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy)
|
||||
return copy;
|
||||
}
|
||||
|
||||
static tree
|
||||
/* Create a new VAR_DECL that is indentical in all respect to DECL except that
|
||||
DECL can be either a VAR_DECL, a PARM_DECL or RESULT_DECL. The original
|
||||
DECL must come from ID->src_fn and the copy will be part of ID->dst_fn. */
|
||||
|
||||
tree
|
||||
copy_decl_to_var (tree decl, copy_body_data *id)
|
||||
{
|
||||
tree copy, type;
|
||||
@ -5816,38 +5896,24 @@ copy_decl_maybe_to_var (tree decl, copy_body_data *id)
|
||||
return copy_decl_no_change (decl, id);
|
||||
}
|
||||
|
||||
/* Return a copy of the function's argument tree. */
|
||||
/* Return a copy of the function's argument tree without any modifications. */
|
||||
|
||||
static tree
|
||||
copy_arguments_for_versioning (tree orig_parm, copy_body_data * id,
|
||||
bitmap args_to_skip, tree *vars)
|
||||
copy_arguments_nochange (tree orig_parm, copy_body_data * id)
|
||||
{
|
||||
tree arg, *parg;
|
||||
tree new_parm = NULL;
|
||||
int i = 0;
|
||||
|
||||
parg = &new_parm;
|
||||
|
||||
for (arg = orig_parm; arg; arg = DECL_CHAIN (arg), i++)
|
||||
if (!args_to_skip || !bitmap_bit_p (args_to_skip, i))
|
||||
{
|
||||
tree new_tree = remap_decl (arg, id);
|
||||
if (TREE_CODE (new_tree) != PARM_DECL)
|
||||
new_tree = id->copy_decl (arg, id);
|
||||
lang_hooks.dup_lang_specific_decl (new_tree);
|
||||
*parg = new_tree;
|
||||
parg = &DECL_CHAIN (new_tree);
|
||||
}
|
||||
else if (!id->decl_map->get (arg))
|
||||
{
|
||||
/* Make an equivalent VAR_DECL. If the argument was used
|
||||
as temporary variable later in function, the uses will be
|
||||
replaced by local variable. */
|
||||
tree var = copy_decl_to_var (arg, id);
|
||||
insert_decl_map (id, arg, var);
|
||||
/* Declare this new variable. */
|
||||
DECL_CHAIN (var) = *vars;
|
||||
*vars = var;
|
||||
}
|
||||
for (arg = orig_parm; arg; arg = DECL_CHAIN (arg))
|
||||
{
|
||||
tree new_tree = remap_decl (arg, id);
|
||||
if (TREE_CODE (new_tree) != PARM_DECL)
|
||||
new_tree = id->copy_decl (arg, id);
|
||||
lang_hooks.dup_lang_specific_decl (new_tree);
|
||||
*parg = new_tree;
|
||||
parg = &DECL_CHAIN (new_tree);
|
||||
}
|
||||
return new_parm;
|
||||
}
|
||||
|
||||
@ -5883,6 +5949,18 @@ tree_versionable_function_p (tree fndecl)
|
||||
static void
|
||||
update_clone_info (copy_body_data * id)
|
||||
{
|
||||
vec<ipa_param_performed_split, va_gc> *cur_performed_splits
|
||||
= id->dst_node->clone.performed_splits;
|
||||
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)
|
||||
return;
|
||||
@ -5896,10 +5974,55 @@ update_clone_info (copy_body_data * id)
|
||||
{
|
||||
struct ipa_replace_map *replace_info;
|
||||
replace_info = (*node->clone.tree_map)[i];
|
||||
walk_tree (&replace_info->old_tree, copy_tree_body_r, id, NULL);
|
||||
walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL);
|
||||
}
|
||||
}
|
||||
if (node->clone.performed_splits)
|
||||
{
|
||||
unsigned len = vec_safe_length (node->clone.performed_splits);
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
ipa_param_performed_split *ps
|
||||
= &(*node->clone.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. */
|
||||
unsigned dst_len = vec_safe_length (node->clone.performed_splits);
|
||||
ipa_param_performed_split *first = &(*cur_performed_splits)[0];
|
||||
for (unsigned i = 0; i < dst_len; i++)
|
||||
if ((*node->clone.performed_splits)[i].dummy_decl
|
||||
== first->dummy_decl)
|
||||
{
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
vec_safe_push (node->clone.performed_splits,
|
||||
(*cur_performed_splits)[i]);
|
||||
if (flag_checking)
|
||||
{
|
||||
for (unsigned i = 0; i < dst_len; i++)
|
||||
{
|
||||
ipa_param_performed_split *ps1
|
||||
= &(*node->clone.performed_splits)[i];
|
||||
for (unsigned j = i + 1; j < dst_len; j++)
|
||||
{
|
||||
ipa_param_performed_split *ps2
|
||||
= &(*node->clone.performed_splits)[j];
|
||||
gcc_assert (ps1->dummy_decl != ps2->dummy_decl
|
||||
|| ps1->unit_offset != ps2->unit_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node->clones)
|
||||
node = node->clones;
|
||||
else if (node->next_sibling_clone)
|
||||
@ -5921,19 +6044,18 @@ update_clone_info (copy_body_data * id)
|
||||
tree with another tree while duplicating the function's
|
||||
body, TREE_MAP represents the mapping between these
|
||||
trees. If UPDATE_CLONES is set, the call_stmt fields
|
||||
of edges of clones of the function will be updated.
|
||||
of edges of clones of the function will be updated.
|
||||
|
||||
If non-NULL ARGS_TO_SKIP determine function parameters to remove
|
||||
from new version.
|
||||
If SKIP_RETURN is true, the new version will return void.
|
||||
If non-NULL BLOCK_TO_COPY determine what basic blocks to copy.
|
||||
If non-NULL PARAM_ADJUSTMENTS determines how function prototype (i.e. the
|
||||
function parameters and return value) should be modified).
|
||||
If non-NULL BLOCKS_TO_COPY determine what basic blocks to copy.
|
||||
If non_NULL NEW_ENTRY determine new entry BB of the clone.
|
||||
*/
|
||||
void
|
||||
tree_function_versioning (tree old_decl, tree new_decl,
|
||||
vec<ipa_replace_map *, va_gc> *tree_map,
|
||||
bool update_clones, bitmap args_to_skip,
|
||||
bool skip_return, bitmap blocks_to_copy,
|
||||
ipa_param_adjustments *param_adjustments,
|
||||
bool update_clones, bitmap blocks_to_copy,
|
||||
basic_block new_entry)
|
||||
{
|
||||
struct cgraph_node *old_version_node;
|
||||
@ -5945,7 +6067,6 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
basic_block old_entry_block, bb;
|
||||
auto_vec<gimple *, 10> init_stmts;
|
||||
tree vars = NULL_TREE;
|
||||
bitmap debug_args_to_skip = args_to_skip;
|
||||
|
||||
gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL
|
||||
&& TREE_CODE (new_decl) == FUNCTION_DECL);
|
||||
@ -6021,96 +6142,78 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl
|
||||
= copy_static_chain (p, &id);
|
||||
|
||||
auto_vec<int, 16> new_param_indices;
|
||||
ipa_param_adjustments *old_param_adjustments
|
||||
= old_version_node->clone.param_adjustments;
|
||||
if (old_param_adjustments)
|
||||
old_param_adjustments->get_updated_indices (&new_param_indices);
|
||||
|
||||
/* If there's a tree_map, prepare for substitution. */
|
||||
if (tree_map)
|
||||
for (i = 0; i < tree_map->length (); i++)
|
||||
{
|
||||
gimple *init;
|
||||
replace_info = (*tree_map)[i];
|
||||
if (replace_info->replace_p)
|
||||
{
|
||||
int parm_num = -1;
|
||||
if (!replace_info->old_tree)
|
||||
{
|
||||
int p = replace_info->parm_num;
|
||||
tree parm;
|
||||
tree req_type, new_type;
|
||||
|
||||
for (parm = DECL_ARGUMENTS (old_decl); p;
|
||||
parm = DECL_CHAIN (parm))
|
||||
p--;
|
||||
replace_info->old_tree = parm;
|
||||
parm_num = replace_info->parm_num;
|
||||
req_type = TREE_TYPE (parm);
|
||||
new_type = TREE_TYPE (replace_info->new_tree);
|
||||
if (!useless_type_conversion_p (req_type, new_type))
|
||||
{
|
||||
if (fold_convertible_p (req_type, replace_info->new_tree))
|
||||
replace_info->new_tree
|
||||
= fold_build1 (NOP_EXPR, req_type,
|
||||
replace_info->new_tree);
|
||||
else if (TYPE_SIZE (req_type) == TYPE_SIZE (new_type))
|
||||
replace_info->new_tree
|
||||
= fold_build1 (VIEW_CONVERT_EXPR, req_type,
|
||||
replace_info->new_tree);
|
||||
else
|
||||
{
|
||||
if (dump_file)
|
||||
{
|
||||
fprintf (dump_file, " const ");
|
||||
print_generic_expr (dump_file,
|
||||
replace_info->new_tree);
|
||||
fprintf (dump_file,
|
||||
" can't be converted to param ");
|
||||
print_generic_expr (dump_file, parm);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
replace_info->old_tree = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
int p = replace_info->parm_num;
|
||||
if (old_param_adjustments)
|
||||
p = new_param_indices[p];
|
||||
|
||||
tree parm;
|
||||
tree req_type, new_type;
|
||||
|
||||
for (parm = DECL_ARGUMENTS (old_decl); p;
|
||||
parm = DECL_CHAIN (parm))
|
||||
p--;
|
||||
tree old_tree = parm;
|
||||
req_type = TREE_TYPE (parm);
|
||||
new_type = TREE_TYPE (replace_info->new_tree);
|
||||
if (!useless_type_conversion_p (req_type, new_type))
|
||||
{
|
||||
if (fold_convertible_p (req_type, replace_info->new_tree))
|
||||
replace_info->new_tree
|
||||
= fold_build1 (NOP_EXPR, req_type, replace_info->new_tree);
|
||||
else if (TYPE_SIZE (req_type) == TYPE_SIZE (new_type))
|
||||
replace_info->new_tree
|
||||
= fold_build1 (VIEW_CONVERT_EXPR, req_type,
|
||||
replace_info->new_tree);
|
||||
else
|
||||
gcc_assert (TREE_CODE (replace_info->old_tree) == PARM_DECL);
|
||||
if (replace_info->old_tree)
|
||||
{
|
||||
init = setup_one_parameter (&id, replace_info->old_tree,
|
||||
replace_info->new_tree, id.src_fn,
|
||||
NULL,
|
||||
&vars);
|
||||
if (init)
|
||||
init_stmts.safe_push (init);
|
||||
if (MAY_HAVE_DEBUG_BIND_STMTS && args_to_skip)
|
||||
if (dump_file)
|
||||
{
|
||||
if (parm_num == -1)
|
||||
{
|
||||
tree parm;
|
||||
int p;
|
||||
for (parm = DECL_ARGUMENTS (old_decl), p = 0; parm;
|
||||
parm = DECL_CHAIN (parm), p++)
|
||||
if (parm == replace_info->old_tree)
|
||||
{
|
||||
parm_num = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parm_num != -1)
|
||||
{
|
||||
if (debug_args_to_skip == args_to_skip)
|
||||
{
|
||||
debug_args_to_skip = BITMAP_ALLOC (NULL);
|
||||
bitmap_copy (debug_args_to_skip, args_to_skip);
|
||||
}
|
||||
bitmap_clear_bit (debug_args_to_skip, parm_num);
|
||||
}
|
||||
fprintf (dump_file, " const ");
|
||||
print_generic_expr (dump_file,
|
||||
replace_info->new_tree);
|
||||
fprintf (dump_file,
|
||||
" can't be converted to param ");
|
||||
print_generic_expr (dump_file, parm);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
old_tree = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_tree)
|
||||
{
|
||||
init = setup_one_parameter (&id, old_tree, replace_info->new_tree,
|
||||
id.src_fn, NULL, &vars);
|
||||
if (init)
|
||||
init_stmts.safe_push (init);
|
||||
}
|
||||
}
|
||||
/* Copy the function's arguments. */
|
||||
if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
|
||||
|
||||
ipa_param_body_adjustments *param_body_adjs = NULL;
|
||||
if (param_adjustments)
|
||||
{
|
||||
param_body_adjs = new ipa_param_body_adjustments (param_adjustments,
|
||||
new_decl, old_decl,
|
||||
&id, &vars, tree_map);
|
||||
id.param_body_adjs = param_body_adjs;
|
||||
DECL_ARGUMENTS (new_decl) = param_body_adjs->get_new_param_chain ();
|
||||
}
|
||||
else if (DECL_ARGUMENTS (old_decl) != NULL_TREE)
|
||||
DECL_ARGUMENTS (new_decl)
|
||||
= copy_arguments_for_versioning (DECL_ARGUMENTS (old_decl), &id,
|
||||
args_to_skip, &vars);
|
||||
= copy_arguments_nochange (DECL_ARGUMENTS (old_decl), &id);
|
||||
|
||||
DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id);
|
||||
BLOCK_SUPERCONTEXT (DECL_INITIAL (new_decl)) = new_decl;
|
||||
@ -6123,12 +6226,19 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
|
||||
if (DECL_RESULT (old_decl) == NULL_TREE)
|
||||
;
|
||||
else if (skip_return && !VOID_TYPE_P (TREE_TYPE (DECL_RESULT (old_decl))))
|
||||
else if (param_adjustments && param_adjustments->m_skip_return
|
||||
&& !VOID_TYPE_P (TREE_TYPE (DECL_RESULT (old_decl))))
|
||||
{
|
||||
tree resdecl_repl = copy_result_decl_to_var (DECL_RESULT (old_decl),
|
||||
&id);
|
||||
declare_inline_vars (NULL, resdecl_repl);
|
||||
insert_decl_map (&id, DECL_RESULT (old_decl), resdecl_repl);
|
||||
|
||||
DECL_RESULT (new_decl)
|
||||
= build_decl (DECL_SOURCE_LOCATION (DECL_RESULT (old_decl)),
|
||||
RESULT_DECL, NULL_TREE, void_type_node);
|
||||
DECL_CONTEXT (DECL_RESULT (new_decl)) = new_decl;
|
||||
DECL_IS_MALLOC (new_decl) = false;
|
||||
cfun->returns_struct = 0;
|
||||
cfun->returns_pcc_struct = 0;
|
||||
}
|
||||
@ -6221,29 +6331,30 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_args_to_skip && MAY_HAVE_DEBUG_BIND_STMTS)
|
||||
if (param_body_adjs && MAY_HAVE_DEBUG_BIND_STMTS)
|
||||
{
|
||||
tree parm;
|
||||
vec<tree, va_gc> **debug_args = NULL;
|
||||
unsigned int len = 0;
|
||||
for (parm = DECL_ARGUMENTS (old_decl), i = 0;
|
||||
parm; parm = DECL_CHAIN (parm), i++)
|
||||
if (bitmap_bit_p (debug_args_to_skip, i) && is_gimple_reg (parm))
|
||||
{
|
||||
tree ddecl;
|
||||
unsigned reset_len = param_body_adjs->m_reset_debug_decls.length ();
|
||||
|
||||
if (debug_args == NULL)
|
||||
{
|
||||
debug_args = decl_debug_args_insert (new_decl);
|
||||
len = vec_safe_length (*debug_args);
|
||||
}
|
||||
ddecl = make_node (DEBUG_EXPR_DECL);
|
||||
DECL_ARTIFICIAL (ddecl) = 1;
|
||||
TREE_TYPE (ddecl) = TREE_TYPE (parm);
|
||||
SET_DECL_MODE (ddecl, DECL_MODE (parm));
|
||||
vec_safe_push (*debug_args, DECL_ORIGIN (parm));
|
||||
vec_safe_push (*debug_args, ddecl);
|
||||
}
|
||||
for (i = 0; i < reset_len; i++)
|
||||
{
|
||||
tree parm = param_body_adjs->m_reset_debug_decls[i];
|
||||
gcc_assert (is_gimple_reg (parm));
|
||||
tree ddecl;
|
||||
|
||||
if (debug_args == NULL)
|
||||
{
|
||||
debug_args = decl_debug_args_insert (new_decl);
|
||||
len = vec_safe_length (*debug_args);
|
||||
}
|
||||
ddecl = make_node (DEBUG_EXPR_DECL);
|
||||
DECL_ARTIFICIAL (ddecl) = 1;
|
||||
TREE_TYPE (ddecl) = TREE_TYPE (parm);
|
||||
SET_DECL_MODE (ddecl, DECL_MODE (parm));
|
||||
vec_safe_push (*debug_args, DECL_ORIGIN (parm));
|
||||
vec_safe_push (*debug_args, ddecl);
|
||||
}
|
||||
if (debug_args != NULL)
|
||||
{
|
||||
/* On the callee side, add
|
||||
@ -6269,7 +6380,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
if (var == NULL_TREE)
|
||||
break;
|
||||
vexpr = make_node (DEBUG_EXPR_DECL);
|
||||
parm = (**debug_args)[i];
|
||||
tree parm = (**debug_args)[i];
|
||||
DECL_ARTIFICIAL (vexpr) = 1;
|
||||
TREE_TYPE (vexpr) = TREE_TYPE (parm);
|
||||
SET_DECL_MODE (vexpr, DECL_MODE (parm));
|
||||
@ -6281,9 +6392,7 @@ tree_function_versioning (tree old_decl, tree new_decl,
|
||||
while (i > len);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_args_to_skip && debug_args_to_skip != args_to_skip)
|
||||
BITMAP_FREE (debug_args_to_skip);
|
||||
delete param_body_adjs;
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
free_dominance_info (CDI_POST_DOMINATORS);
|
||||
|
||||
|
@ -172,6 +172,15 @@ struct copy_body_data
|
||||
outside of the inlined function, this should be the number
|
||||
of basic blocks in the caller before inlining. Zero otherwise. */
|
||||
int add_clobbers_to_eh_landing_pads;
|
||||
|
||||
/* Class managing changes to function parameters and return value planned
|
||||
during IPA stage. */
|
||||
class ipa_param_body_adjustments *param_body_adjs;
|
||||
|
||||
/* Hash set of SSA names that have been killed during call graph edge
|
||||
redirection and should not be introduced into debug statements or NULL if no
|
||||
SSA_NAME was deleted during redirections happened. */
|
||||
hash_set <tree> *killed_new_ssa_names;
|
||||
};
|
||||
|
||||
/* Weights of constructions for estimate_num_insns. */
|
||||
@ -240,6 +249,7 @@ extern bool debug_find_tree (tree, tree);
|
||||
extern tree copy_fn (tree, tree&, tree&);
|
||||
extern const char *copy_forbidden (struct function *fun);
|
||||
extern tree copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy);
|
||||
extern tree copy_decl_to_var (tree, copy_body_data *);
|
||||
|
||||
/* This is in tree-inline.c since the routine uses
|
||||
data structures from the inliner. */
|
||||
|
@ -355,7 +355,6 @@ extern gimple_opt_pass *make_pass_early_tree_profile (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_cleanup_eh (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_sra (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_sra_early (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_early_ipa_sra (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_tail_recursion (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_tail_calls (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_fix_loops (gcc::context *ctxt);
|
||||
@ -500,6 +499,7 @@ extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt);
|
||||
extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt);
|
||||
extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt);
|
||||
extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt);
|
||||
extern ipa_opt_pass_d *make_pass_ipa_sra (gcc::context *ctxt);
|
||||
extern ipa_opt_pass_d *make_pass_ipa_icf (gcc::context *ctxt);
|
||||
extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt);
|
||||
extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
|
||||
|
1859
gcc/tree-sra.c
1859
gcc/tree-sra.c
File diff suppressed because it is too large
Load Diff
31
gcc/tree-sra.h
Normal file
31
gcc/tree-sra.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* Scalar Replacement of Aggregates (SRA) converts some structure
|
||||
references into scalar references, exposing them to the scalar
|
||||
optimizers.
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
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/>. */
|
||||
|
||||
bool type_internals_preclude_sra_p (tree type, const char **msg);
|
||||
|
||||
/* Return true iff TYPE is stdarg va_list type (which early SRA and IPA-SRA
|
||||
should leave alone). */
|
||||
|
||||
static inline bool
|
||||
is_va_list_type (tree type)
|
||||
{
|
||||
return TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node);
|
||||
}
|
Loading…
Reference in New Issue
Block a user