Hi, with improvements on devirtualization side, the thunks are getting more problematic for optimizers. Inliner won't inline them, profiling won't instrument them and there are other places where they bock optimization.
This patch solves part of the problem by making gimple thunks to go same way as regular functions. I will cleanup the code and work on getting asm thunks inlined incrementally. This patch also makes it possible for functions to be created in SSA form by making init_datastructures and into_ssa passes to gate themself out when function is in SSA already. I suppose in future we may want to have other places that produce SSA functions themselves intead of going throught he into-ssa path. Bootstrapped/regtested x86_64-linux, will commit it later this weekend after testing on pcc64 too if there are no complains. Honza * tree-into-ssa.c (gate_into_ssa): New. (pass_data_build_ssa): Use it. * cgraph.h (expand_thunk): Update prototype. * cgraphunit.c (analyze_function): Expand thunks early. (expand_thunk): Fix DECL_CONTEXT of reust_decl; build proper cgraph; set in_ssa_p; clear bogus TREE_ASM_WRITTEN; set lowered flag; do not add new function. (assemble_thunks_and_aliases): Update. * tree-ssa.c (gate_init_datastructures): New gate. (pass_data_init_datastructures): Use it. Index: tree-into-ssa.c =================================================================== --- tree-into-ssa.c (revision 202565) +++ tree-into-ssa.c (working copy) @@ -2409,6 +2409,14 @@ rewrite_into_ssa (void) return 0; } +/* Gate for IPCP optimization. */ + +static bool +gate_into_ssa (void) +{ + /* Do nothing for funcions that was produced already in SSA form. */ + return !(cfun->curr_properties & PROP_ssa); +} namespace { @@ -2417,7 +2425,7 @@ const pass_data pass_data_build_ssa = GIMPLE_PASS, /* type */ "ssa", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - false, /* has_gate */ + true, /* has_gate */ true, /* has_execute */ TV_TREE_SSA_OTHER, /* tv_id */ PROP_cfg, /* properties_required */ @@ -2435,6 +2443,7 @@ public: {} /* opt_pass methods: */ + bool gate () { return gate_into_ssa (); } unsigned int execute () { return rewrite_into_ssa (); } }; // class pass_build_ssa Index: cgraph.h =================================================================== --- cgraph.h (revision 202565) +++ cgraph.h (working copy) @@ -757,7 +757,7 @@ void fixup_same_cpp_alias_visibility (sy IN_SSA is true if the gimple is in SSA. */ basic_block init_lowered_empty_function (tree, bool); void cgraph_reset_node (struct cgraph_node *); -void expand_thunk (struct cgraph_node *); +bool expand_thunk (struct cgraph_node *, bool); /* In cgraphclones.c */ Index: cgraphunit.c =================================================================== --- cgraphunit.c (revision 202565) +++ cgraphunit.c (working copy) @@ -592,15 +592,21 @@ analyze_function (struct cgraph_node *no location_t saved_loc = input_location; input_location = DECL_SOURCE_LOCATION (decl); - if (node->symbol.alias) - symtab_resolve_alias - ((symtab_node) node, (symtab_node) cgraph_get_node (node->symbol.alias_target)); - else if (node->thunk.thunk_p) + if (node->thunk.thunk_p) { cgraph_create_edge (node, cgraph_get_node (node->thunk.alias), - NULL, 0, CGRAPH_FREQ_BASE); + NULL, 0, CGRAPH_FREQ_BASE); + if (!expand_thunk (node, false)) + { + node->thunk.alias = NULL; + node->symbol.analyzed = true; + return; + } node->thunk.alias = NULL; } + if (node->symbol.alias) + symtab_resolve_alias + ((symtab_node) node, (symtab_node) cgraph_get_node (node->symbol.alias_target)); else if (node->dispatcher_function) { /* Generate the dispatcher body of multi-versioned functions. */ @@ -1432,10 +1438,12 @@ thunk_adjust (gimple_stmt_iterator * bsi return ret; } -/* Produce assembler for thunk NODE. */ +/* Expand thunk NODE to gimple if possible. + When OUTPUT_ASM_THUNK is true, also produce assembler for + thunks that are not lowered. */ -void -expand_thunk (struct cgraph_node *node) +bool +expand_thunk (struct cgraph_node *node, bool output_asm_thunks) { bool this_adjusting = node->thunk.this_adjusting; HOST_WIDE_INT fixed_offset = node->thunk.fixed_offset; @@ -1445,14 +1453,6 @@ expand_thunk (struct cgraph_node *node) tree thunk_fndecl = node->symbol.decl; tree a; - if (in_lto_p) - cgraph_get_body (node); - a = DECL_ARGUMENTS (thunk_fndecl); - - current_function_decl = thunk_fndecl; - - /* Ensure thunks are emitted in their correct sections. */ - resolve_unique_section (thunk_fndecl, 0, flag_function_sections); if (this_adjusting && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, @@ -1461,10 +1461,23 @@ expand_thunk (struct cgraph_node *node) const char *fnname; tree fn_block; tree restype = TREE_TYPE (TREE_TYPE (thunk_fndecl)); + + if (!output_asm_thunks) + return false; + + if (in_lto_p) + cgraph_get_body (node); + a = DECL_ARGUMENTS (thunk_fndecl); + current_function_decl = thunk_fndecl; + + /* Ensure thunks are emitted in their correct sections. */ + resolve_unique_section (thunk_fndecl, 0, flag_function_sections); + DECL_RESULT (thunk_fndecl) = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl), RESULT_DECL, 0, restype); + DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl; fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl)); /* The back end expects DECL_INITIAL to contain a BLOCK, so we @@ -1506,6 +1519,15 @@ expand_thunk (struct cgraph_node *node) gimple call; gimple ret; + if (in_lto_p) + cgraph_get_body (node); + a = DECL_ARGUMENTS (thunk_fndecl); + + current_function_decl = thunk_fndecl; + + /* Ensure thunks are emitted in their correct sections. */ + resolve_unique_section (thunk_fndecl, 0, flag_function_sections); + DECL_IGNORED_P (thunk_fndecl) = 1; bitmap_obstack_initialize (NULL); @@ -1520,6 +1542,7 @@ expand_thunk (struct cgraph_node *node) DECL_ARTIFICIAL (resdecl) = 1; DECL_IGNORED_P (resdecl) = 1; DECL_RESULT (thunk_fndecl) = resdecl; + DECL_CONTEXT (DECL_RESULT (thunk_fndecl)) = thunk_fndecl; } else resdecl = DECL_RESULT (thunk_fndecl); @@ -1556,6 +1579,7 @@ expand_thunk (struct cgraph_node *node) for (i = 1, arg = DECL_CHAIN (a); i < nargs; i++, arg = DECL_CHAIN (arg)) vargs.quick_push (arg); call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs); + node->callees->call_stmt = call; vargs.release (); gimple_call_set_from_thunk (call, true); if (restmp) @@ -1624,6 +1648,9 @@ expand_thunk (struct cgraph_node *node) remove_edge (single_succ_edge (bb)); } + cfun->gimple_df->in_ssa_p = true; + /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */ + TREE_ASM_WRITTEN (thunk_fndecl) = false; delete_unreachable_blocks (); update_ssa (TODO_update_ssa); #ifdef ENABLE_CHECKING @@ -1633,12 +1660,12 @@ expand_thunk (struct cgraph_node *node) /* Since we want to emit the thunk, we explicitly mark its name as referenced. */ node->thunk.thunk_p = false; - rebuild_cgraph_edges (); - cgraph_add_new_function (thunk_fndecl, true); + node->lowered = true; bitmap_obstack_release (NULL); } current_function_decl = NULL; set_cfun (NULL); + return true; } /* Assemble thunks and aliases associated to NODE. */ @@ -1657,7 +1684,7 @@ assemble_thunks_and_aliases (struct cgra e = e->next_caller; assemble_thunks_and_aliases (thunk); - expand_thunk (thunk); + expand_thunk (thunk, true); } else e = e->next_caller; Index: tree-ssa.c =================================================================== --- tree-ssa.c (revision 202565) +++ tree-ssa.c (working copy) @@ -1084,10 +1084,19 @@ static unsigned int execute_init_datastructures (void) { /* Allocate hash tables, arrays and other structures. */ init_tree_ssa (cfun); return 0; } +/* Gate for IPCP optimization. */ + +static bool +gate_init_datastructures (void) +{ + /* Do nothing for funcions that was produced already in SSA form. */ + return !(cfun->curr_properties & PROP_ssa); +} + namespace { const pass_data pass_data_init_datastructures = @@ -1095,7 +1105,7 @@ const pass_data pass_data_init_datastruc GIMPLE_PASS, /* type */ "*init_datastructures", /* name */ OPTGROUP_NONE, /* optinfo_flags */ - false, /* has_gate */ + true, /* has_gate */ true, /* has_execute */ TV_NONE, /* tv_id */ PROP_cfg, /* properties_required */ @@ -1113,6 +1123,7 @@ public: {} /* opt_pass methods: */ + bool gate () { return gate_init_datastructures (); } unsigned int execute () { return execute_init_datastructures (); } }; // class pass_init_datastructures