Hi, this is preparation work to move DECL_ARGUMENTS and DECL_RESULT into function sections during WPA. Even with some work to release unused ones, there are 4M of PARM_DECLs and 2M of RESULT_DECLs streamed during LTO (for 6M of function_decls) making them one of the most common nodes.
This patch makes ipa-cp and ipa-prop to not use DECL_ARGUMENTS during WPA stage. this only needed to tamn debug info, move logic doing casts from get_replacement_map to tree_function_versioning and stream move_cost that is computed form parm type. Martin, does this patch look OK? Honza * ipa-cp.c (gather_context_independent_values): Use ipa_get_param_move_cost. (get_replacement_map): Remove PARAM; move parameter folding into tree-inline.c (create_specialized_node): Update. * ipa-prop.c (ipa_populate_param_decls): Do not look for origins; assert that we have gimple body; update move_cost. (count_formal_params): Assert that we have gimple body. (ipa_alloc_node_params): Break out from ... (ipa_initialize_node_params): ... here. (ipa_get_vector_of_formal_parms): ICE when used in WPA. (ipa_write_node_info): Stream move costs. (ipa_read_node_info): Read move costs. (ipa_update_after_lto_read): Do not recompute node params. * ipa-prop.h (ipa_param_descriptor): Add move_cost. (ipa_get_param): Check we are not in WPA. (ipa_get_param_move_cost): New. * tree-inline.c (tree_function_versioning): Fold replacement as needed. Index: ipa-cp.c =================================================================== *** ipa-cp.c (revision 201291) --- ipa-cp.c (working copy) *************** gather_context_independent_values (struc *** 1758,1770 **** } else if (removable_params_cost && !ipa_is_param_used (info, i)) ! *removable_params_cost ! += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i))); } else if (removable_params_cost && !ipa_is_param_used (info, i)) *removable_params_cost ! += estimate_move_cost (TREE_TYPE (ipa_get_param (info, i))); if (known_aggs) { --- 1758,1769 ---- } else if (removable_params_cost && !ipa_is_param_used (info, i)) ! *removable_params_cost += ipa_get_param_move_cost (info, i); } else if (removable_params_cost && !ipa_is_param_used (info, i)) *removable_params_cost ! += ipa_get_param_move_cost (info, i); if (known_aggs) { *************** gather_edges_for_value (struct ipcp_valu *** 2480,2515 **** Return it or NULL if for some reason it cannot be created. */ static struct ipa_replace_map * ! get_replacement_map (tree value, tree parm, int parm_num) { - tree req_type = TREE_TYPE (parm); struct ipa_replace_map *replace_map; - if (!useless_type_conversion_p (req_type, TREE_TYPE (value))) - { - if (fold_convertible_p (req_type, value)) - value = fold_build1 (NOP_EXPR, req_type, value); - else if (TYPE_SIZE (req_type) == TYPE_SIZE (TREE_TYPE (value))) - value = fold_build1 (VIEW_CONVERT_EXPR, req_type, value); - else - { - if (dump_file) - { - fprintf (dump_file, " const "); - print_generic_expr (dump_file, value, 0); - fprintf (dump_file, " can't be converted to param "); - print_generic_expr (dump_file, parm, 0); - fprintf (dump_file, "\n"); - } - return NULL; - } - } replace_map = ggc_alloc_ipa_replace_map (); if (dump_file) { ! fprintf (dump_file, " replacing param "); ! print_generic_expr (dump_file, parm, 0); fprintf (dump_file, " with const "); print_generic_expr (dump_file, value, 0); fprintf (dump_file, "\n"); --- 2479,2494 ---- Return it or NULL if for some reason it cannot be created. */ static struct ipa_replace_map * ! get_replacement_map (tree value, int parm_num) { struct ipa_replace_map *replace_map; replace_map = ggc_alloc_ipa_replace_map (); if (dump_file) { ! fprintf (dump_file, " replacing param %i", parm_num); ! fprintf (dump_file, " with const "); print_generic_expr (dump_file, value, 0); fprintf (dump_file, "\n"); *************** create_specialized_node (struct cgraph_n *** 2697,2703 **** { struct ipa_replace_map *replace_map; ! replace_map = get_replacement_map (t, ipa_get_param (info, i), i); if (replace_map) vec_safe_push (replace_trees, replace_map); } --- 2676,2682 ---- { struct ipa_replace_map *replace_map; ! replace_map = get_replacement_map (t, i); if (replace_map) vec_safe_push (replace_trees, replace_map); } Index: ipa-prop.c =================================================================== *** ipa-prop.c (revision 201291) --- ipa-prop.c (working copy) *************** ipa_populate_param_decls (struct cgraph_ *** 130,145 **** tree parm; int param_num; - /* We do not copy DECL_ARGUMENTS to virtual clones. */ - while (node->clone_of) - node = node->clone_of; - fndecl = node->symbol.decl; fnargs = DECL_ARGUMENTS (fndecl); param_num = 0; for (parm = fnargs; parm; parm = DECL_CHAIN (parm)) { descriptors[param_num].decl = parm; param_num++; } } --- 130,143 ---- tree parm; int param_num; fndecl = node->symbol.decl; + gcc_assert (gimple_has_body_p (fndecl)); fnargs = DECL_ARGUMENTS (fndecl); param_num = 0; for (parm = fnargs; parm; parm = DECL_CHAIN (parm)) { descriptors[param_num].decl = parm; + descriptors[param_num].move_cost = estimate_move_cost (TREE_TYPE (parm)); param_num++; } } *************** count_formal_params (tree fndecl) *** 151,156 **** --- 149,155 ---- { tree parm; int count = 0; + gcc_assert (gimple_has_body_p (fndecl)); for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) count++; *************** count_formal_params (tree fndecl) *** 158,163 **** --- 157,174 ---- return count; } + /* Initialize the ipa_node_params structure associated with NODE + to hold PARAM_COUNT parameters. */ + + void + ipa_alloc_node_params (struct cgraph_node *node, int param_count) + { + struct ipa_node_params *info = IPA_NODE_REF (node); + + if (!info->descriptors.exists () && param_count) + info->descriptors.safe_grow_cleared (param_count); + } + /* Initialize the ipa_node_params structure associated with NODE by counting the function parameters, creating the descriptors and populating their param_decls. */ *************** ipa_initialize_node_params (struct cgrap *** 169,183 **** if (!info->descriptors.exists ()) { ! int param_count; ! gcc_assert (!node->clone_of); ! ! param_count = count_formal_params (node->symbol.decl); ! if (param_count) ! { ! info->descriptors.safe_grow_cleared (param_count); ! ipa_populate_param_decls (node, info->descriptors); ! } } } --- 180,187 ---- if (!info->descriptors.exists ()) { ! ipa_alloc_node_params (node, count_formal_params (node->symbol.decl)); ! ipa_populate_param_decls (node, info->descriptors); } } *************** ipa_get_vector_of_formal_parms (tree fnd *** 3064,3069 **** --- 3068,3074 ---- int count; tree parm; + gcc_assert (!flag_wpa); count = count_formal_params (fndecl); args.create (count); for (parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) *************** ipa_write_node_info (struct output_block *** 3856,3861 **** --- 3861,3869 ---- node_ref = lto_symtab_encoder_encode (encoder, (symtab_node) node); streamer_write_uhwi (ob, node_ref); + streamer_write_uhwi (ob, ipa_get_param_count (info)); + for (j = 0; j < ipa_get_param_count (info); j++) + streamer_write_uhwi (ob, ipa_get_param_move_cost (info, j)); bp = bitpack_create (ob->main_stream); gcc_assert (info->uses_analysis_done || ipa_get_param_count (info) == 0); *************** ipa_read_node_info (struct lto_input_blo *** 3896,3903 **** struct cgraph_edge *e; struct bitpack_d bp; ! ipa_initialize_node_params (node); bp = streamer_read_bitpack (ib); if (ipa_get_param_count (info) != 0) info->uses_analysis_done = true; --- 3904,3914 ---- struct cgraph_edge *e; struct bitpack_d bp; ! ipa_alloc_node_params (node, streamer_read_uhwi (ib)); + for (k = 0; k < ipa_get_param_count (info); k++) + info->descriptors[k].move_cost = streamer_read_uhwi (ib); + bp = streamer_read_bitpack (ib); if (ipa_get_param_count (info) != 0) info->uses_analysis_done = true; *************** ipa_prop_read_jump_functions (void) *** 4049,4061 **** void ipa_update_after_lto_read (void) { - struct cgraph_node *node; - ipa_check_create_node_params (); ipa_check_create_edge_args (); - - FOR_EACH_DEFINED_FUNCTION (node) - ipa_initialize_node_params (node); } void --- 4060,4067 ---- Index: ipa-prop.h =================================================================== *** ipa-prop.h (revision 201291) --- ipa-prop.h (working copy) *************** struct ipa_param_descriptor *** 320,325 **** --- 320,326 ---- says how many there are. If any use could not be described by means of ipa-prop structures, this is IPA_UNDESCRIBED_USE. */ int controlled_uses; + unsigned int move_cost : 31; /* The parameter is used. */ unsigned used : 1; }; *************** ipa_get_param_count (struct ipa_node_par *** 377,385 **** --- 378,396 ---- static inline tree ipa_get_param (struct ipa_node_params *info, int i) { + gcc_checking_assert (!flag_wpa); return info->descriptors[i].decl; } + /* Return the move cost of Ith formal parameter of the function corresponding + to INFO. */ + + static inline int + ipa_get_param_move_cost (struct ipa_node_params *info, int i) + { + return info->descriptors[i].move_cost; + } + /* Set the used flag corresponding to the Ith formal parameter of the function associated with INFO to VAL. */ Index: tree-inline.c =================================================================== *** tree-inline.c (revision 201291) --- tree-inline.c (working copy) *************** tree_function_versioning (tree old_decl, *** 5146,5162 **** { int i = replace_info->parm_num; tree parm; for (parm = DECL_ARGUMENTS (old_decl); i; parm = DECL_CHAIN (parm)) i --; replace_info->old_tree = parm; } - gcc_assert (TREE_CODE (replace_info->old_tree) == PARM_DECL); - 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); } } /* Copy the function's arguments. */ --- 5150,5192 ---- { int i = replace_info->parm_num; tree parm; + tree req_type; + for (parm = DECL_ARGUMENTS (old_decl); i; parm = DECL_CHAIN (parm)) i --; replace_info->old_tree = parm; + req_type = TREE_TYPE (parm); + if (!useless_type_conversion_p (req_type, TREE_TYPE (replace_info->new_tree))) + { + 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 (TREE_TYPE (replace_info->new_tree))) + 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, 0); + fprintf (dump_file, " can't be converted to param "); + print_generic_expr (dump_file, parm, 0); + fprintf (dump_file, "\n"); + } + replace_info->old_tree = NULL; + } + } + } + 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); } } } /* Copy the function's arguments. */