diff options
Diffstat (limited to 'gcc/tree-inline.c')
-rw-r--r-- | gcc/tree-inline.c | 179 |
1 files changed, 109 insertions, 70 deletions
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index b83c52f..5ada378 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -64,7 +64,7 @@ along with GCC; see the file COPYING3. If not see MODIFY_EXPRs that store to a dedicated returned-value variable. The duplicated eh_region info of the copy will later be appended to the info for the caller; the eh_region info in copied throwing - statements and RESX_EXPRs is adjusted accordingly. + statements and RESX statements are adjusted accordingly. Cloning: (only in C++) We have one body for a con/de/structor, and multiple function decls, each with a unique parameter list. @@ -1105,12 +1105,6 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) TREE_BLOCK (*tp) = new_block; } - if (TREE_CODE (*tp) == RESX_EXPR && id->eh_region_offset) - TREE_OPERAND (*tp, 0) = - build_int_cst (NULL_TREE, - id->eh_region_offset - + TREE_INT_CST_LOW (TREE_OPERAND (*tp, 0))); - if (TREE_CODE (*tp) != OMP_CLAUSE) TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id); @@ -1150,6 +1144,35 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; } +/* Helper for remap_gimple_stmt. Given an EH region number for the + source function, map that to the duplicate EH region number in + the destination function. */ + +static int +remap_eh_region_nr (int old_nr, copy_body_data *id) +{ + eh_region old_r, new_r; + void **slot; + + old_r = get_eh_region_from_number_fn (id->src_cfun, old_nr); + slot = pointer_map_contains (id->eh_map, old_r); + new_r = (eh_region) *slot; + + return new_r->index; +} + +/* Similar, but operate on INTEGER_CSTs. */ + +static tree +remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id) +{ + int old_nr, new_nr; + + old_nr = tree_low_cst (old_t_nr, 0); + new_nr = remap_eh_region_nr (old_nr, id); + + return build_int_cst (NULL, new_nr); +} /* Helper for copy_bb. Remap statement STMT using the inlining information in ID. Return the new statement copy. */ @@ -1339,9 +1362,59 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) VEC_safe_push (gimple, heap, id->debug_stmts, copy); return copy; } - else - /* Create a new deep copy of the statement. */ - copy = gimple_copy (stmt); + + /* Create a new deep copy of the statement. */ + copy = gimple_copy (stmt); + + /* Remap the region numbers for __builtin_eh_{pointer,filter}, + RESX and EH_DISPATCH. */ + if (id->eh_map) + switch (gimple_code (copy)) + { + case GIMPLE_CALL: + { + tree r, fndecl = gimple_call_fndecl (copy); + if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_EH_COPY_VALUES: + r = gimple_call_arg (copy, 1); + r = remap_eh_region_tree_nr (r, id); + gimple_call_set_arg (copy, 1, r); + /* FALLTHRU */ + + case BUILT_IN_EH_POINTER: + case BUILT_IN_EH_FILTER: + r = gimple_call_arg (copy, 0); + r = remap_eh_region_tree_nr (r, id); + gimple_call_set_arg (copy, 0, r); + break; + + default: + break; + } + } + break; + + case GIMPLE_RESX: + { + int r = gimple_resx_region (copy); + r = remap_eh_region_nr (r, id); + gimple_resx_set_region (copy, r); + } + break; + + case GIMPLE_EH_DISPATCH: + { + int r = gimple_eh_dispatch_region (copy); + r = remap_eh_region_nr (r, id); + gimple_eh_dispatch_set_region (copy, r); + } + break; + + default: + break; + } } /* If STMT has a block defined, map it to the newly constructed @@ -1377,12 +1450,6 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id) gimple_set_vuse (copy, NULL_TREE); } - /* We have to handle EH region remapping of GIMPLE_RESX specially because - the region number is not an operand. */ - if (gimple_code (stmt) == GIMPLE_RESX && id->eh_region_offset) - { - gimple_resx_set_region (copy, gimple_resx_region (stmt) + id->eh_region_offset); - } return copy; } @@ -1617,43 +1684,8 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale, cfun->calls_setjmp = true; } - /* If you think we can abort here, you are wrong. - There is no region 0 in gimple. */ - gcc_assert (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) != 0); - - if (stmt_could_throw_p (stmt) - /* When we are cloning for inlining, we are supposed to - construct a clone that calls precisely the same functions - as original. However IPA optimizers might've proved - earlier some function calls as non-trapping that might - render some basic blocks dead that might become - unreachable. - - We can't update SSA with unreachable blocks in CFG and thus - we prevent the scenario by preserving even the "dead" eh - edges until the point they are later removed by - fixup_cfg pass. */ - || (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES - && lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) > 0)) - { - int region = lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt); - - /* Add an entry for the copied tree in the EH hashtable. - When cloning or versioning, use the hashtable in - cfun, and just copy the EH number. When inlining, use the - hashtable in the caller, and adjust the region number. */ - if (region > 0) - add_stmt_to_eh_region (stmt, region + id->eh_region_offset); - - /* If this tree doesn't have a region associated with it, - and there is a "current region," - then associate this tree with the current region - and add edges associated with this region. */ - if (lookup_stmt_eh_region_fn (id->src_cfun, orig_stmt) <= 0 - && id->eh_region > 0 - && stmt_could_throw_p (stmt)) - add_stmt_to_eh_region (stmt, id->eh_region); - } + maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt, + id->eh_map, id->eh_lp_nr); if (gimple_in_ssa_p (cfun) && !is_gimple_debug (stmt)) { @@ -1822,7 +1854,9 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb) } } - if (can_throw) + if (gimple_code (copy_stmt) == GIMPLE_EH_DISPATCH) + make_eh_dispatch_edges (copy_stmt); + else if (can_throw) make_eh_edges (copy_stmt); if (nonlocal_goto) @@ -2025,11 +2059,8 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency, /* Duplicate any exception-handling regions. */ if (cfun->eh) - { - id->eh_region_offset - = duplicate_eh_regions (cfun_to_copy, remap_decl_1, id, - 0, id->eh_region); - } + id->eh_map = duplicate_eh_regions (cfun_to_copy, NULL, id->eh_lp_nr, + remap_decl_1, id); /* Use aux pointers to map the original blocks to copy. */ FOR_EACH_BB_FN (bb, cfun_to_copy) @@ -2062,6 +2093,12 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency, entry_block_map->aux = NULL; exit_block_map->aux = NULL; + if (id->eh_map) + { + pointer_map_destroy (id->eh_map); + id->eh_map = NULL; + } + return new_fndecl; } @@ -3190,14 +3227,6 @@ estimate_num_insns (gimple stmt, eni_weights *weights) lhs = gimple_assign_lhs (stmt); rhs = gimple_assign_rhs1 (stmt); - /* EH magic stuff is most probably going to be optimized out. - We rarely really need to save EH info for unwinding - nested exceptions. */ - if (TREE_CODE (lhs) == FILTER_EXPR - || TREE_CODE (lhs) == EXC_PTR_EXPR - || TREE_CODE (rhs) == FILTER_EXPR - || TREE_CODE (rhs) == EXC_PTR_EXPR) - return 0; if (is_gimple_reg (lhs)) cost = 0; else @@ -3308,9 +3337,19 @@ estimate_num_insns (gimple stmt, eni_weights *weights) return 0; case GIMPLE_ASM: - case GIMPLE_RESX: return 1; + case GIMPLE_RESX: + /* This is either going to be an external function call with one + argument, or two register copy statements plus a goto. */ + return 2; + + case GIMPLE_EH_DISPATCH: + /* ??? This is going to turn into a switch statement. Ideally + we'd have a look at the eh region and estimate the number of + edges involved. */ + return 10; + case GIMPLE_BIND: return estimate_num_insns_seq (gimple_bind_body (stmt), weights); @@ -3551,7 +3590,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id) #endif /* We will be inlining this callee. */ - id->eh_region = lookup_stmt_eh_region (stmt); + id->eh_lp_nr = lookup_stmt_eh_lp (stmt); /* Update the callers EH personality. */ if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl)) @@ -4935,7 +4974,7 @@ maybe_inline_call_in_expr (tree exp) id.do_not_unshare = true; /* We're not inside any EH region. */ - id.eh_region = -1; + id.eh_lp_nr = 0; t = copy_tree_body (&id); pointer_map_destroy (decl_map); |