+/* 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. */
+
+static gimple
+remap_gimple_stmt (gimple stmt, copy_body_data *id)
+{
+ gimple copy = NULL;
+ struct walk_stmt_info wi;
+ tree new_block;
+ bool skip_first = false;
+
+ /* Begin by recognizing trees that we'll completely rewrite for the
+ inlining context. Our output for these trees is completely
+ different from out input (e.g. RETURN_EXPR is deleted, and morphs
+ into an edge). Further down, we'll handle trees that get
+ duplicated and/or tweaked. */
+
+ /* When requested, GIMPLE_RETURNs should be transformed to just the
+ contained GIMPLE_ASSIGN. The branch semantics of the return will
+ be handled elsewhere by manipulating the CFG rather than the
+ statement. */
+ if (gimple_code (stmt) == GIMPLE_RETURN && id->transform_return_to_modify)
+ {
+ tree retval = gimple_return_retval (stmt);
+
+ /* If we're returning something, just turn that into an
+ assignment into the equivalent of the original RESULT_DECL.
+ If RETVAL is just the result decl, the result decl has
+ already been set (e.g. a recent "foo (&result_decl, ...)");
+ just toss the entire GIMPLE_RETURN. */
+ if (retval && TREE_CODE (retval) != RESULT_DECL)
+ {
+ copy = gimple_build_assign (id->retvar, retval);
+ /* id->retvar is already substituted. Skip it on later remapping. */
+ skip_first = true;
+ }
+ else
+ return gimple_build_nop ();
+ }
+ else if (gimple_has_substatements (stmt))
+ {
+ gimple_seq s1, s2;
+
+ /* When cloning bodies from the C++ front end, we will be handed bodies
+ in High GIMPLE form. Handle here all the High GIMPLE statements that
+ have embedded statements. */
+ switch (gimple_code (stmt))
+ {
+ case GIMPLE_BIND:
+ copy = copy_gimple_bind (stmt, id);
+ break;
+
+ case GIMPLE_CATCH:
+ s1 = remap_gimple_seq (gimple_catch_handler (stmt), id);
+ copy = gimple_build_catch (gimple_catch_types (stmt), s1);
+ break;
+
+ case GIMPLE_EH_FILTER:
+ s1 = remap_gimple_seq (gimple_eh_filter_failure (stmt), id);
+ copy = gimple_build_eh_filter (gimple_eh_filter_types (stmt), s1);
+ break;
+
+ case GIMPLE_TRY:
+ s1 = remap_gimple_seq (gimple_try_eval (stmt), id);
+ s2 = remap_gimple_seq (gimple_try_cleanup (stmt), id);
+ copy = gimple_build_try (s1, s2, gimple_try_kind (stmt));
+ break;
+
+ case GIMPLE_WITH_CLEANUP_EXPR:
+ s1 = remap_gimple_seq (gimple_wce_cleanup (stmt), id);
+ copy = gimple_build_wce (s1);
+ break;
+
+ case GIMPLE_OMP_PARALLEL:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_parallel
+ (s1,
+ gimple_omp_parallel_clauses (stmt),
+ gimple_omp_parallel_child_fn (stmt),
+ gimple_omp_parallel_data_arg (stmt));
+ break;
+
+ case GIMPLE_OMP_TASK:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_task
+ (s1,
+ gimple_omp_task_clauses (stmt),
+ gimple_omp_task_child_fn (stmt),
+ gimple_omp_task_data_arg (stmt),
+ gimple_omp_task_copy_fn (stmt),
+ gimple_omp_task_arg_size (stmt),
+ gimple_omp_task_arg_align (stmt));
+ break;
+
+ case GIMPLE_OMP_FOR:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id);
+ copy = gimple_build_omp_for (s1, gimple_omp_for_clauses (stmt),
+ gimple_omp_for_collapse (stmt), s2);
+ {
+ size_t i;
+ for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
+ {
+ gimple_omp_for_set_index (copy, i,
+ gimple_omp_for_index (stmt, i));
+ gimple_omp_for_set_initial (copy, i,
+ gimple_omp_for_initial (stmt, i));
+ gimple_omp_for_set_final (copy, i,
+ gimple_omp_for_final (stmt, i));
+ gimple_omp_for_set_incr (copy, i,
+ gimple_omp_for_incr (stmt, i));
+ gimple_omp_for_set_cond (copy, i,
+ gimple_omp_for_cond (stmt, i));
+ }
+ }
+ break;
+
+ case GIMPLE_OMP_MASTER:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_master (s1);
+ break;
+
+ case GIMPLE_OMP_ORDERED:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_ordered (s1);
+ break;
+
+ case GIMPLE_OMP_SECTION:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_section (s1);
+ break;
+
+ case GIMPLE_OMP_SECTIONS:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_sections
+ (s1, gimple_omp_sections_clauses (stmt));
+ break;
+
+ case GIMPLE_OMP_SINGLE:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy = gimple_build_omp_single
+ (s1, gimple_omp_single_clauses (stmt));
+ break;
+
+ case GIMPLE_OMP_CRITICAL:
+ s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+ copy
+ = gimple_build_omp_critical (s1, gimple_omp_critical_name (stmt));
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ {
+ if (gimple_assign_copy_p (stmt)
+ && gimple_assign_lhs (stmt) == gimple_assign_rhs1 (stmt)
+ && auto_var_in_fn_p (gimple_assign_lhs (stmt), id->src_fn))
+ {
+ /* Here we handle statements that are not completely rewritten.
+ First we detect some inlining-induced bogosities for
+ discarding. */
+
+ /* Some assignments VAR = VAR; don't generate any rtl code
+ and thus don't count as variable modification. Avoid
+ keeping bogosities like 0 = 0. */
+ tree decl = gimple_assign_lhs (stmt), value;
+ tree *n;
+
+ n = (tree *) pointer_map_contains (id->decl_map, decl);
+ if (n)
+ {
+ value = *n;
+ STRIP_TYPE_NOPS (value);
+ if (TREE_CONSTANT (value) || TREE_READONLY (value))
+ return gimple_build_nop ();
+ }
+ }
+
+ if (gimple_debug_bind_p (stmt))
+ {
+ copy = gimple_build_debug_bind (gimple_debug_bind_get_var (stmt),
+ gimple_debug_bind_get_value (stmt),
+ stmt);
+ VEC_safe_push (gimple, heap, id->debug_stmts, copy);
+ return copy;
+ }
+
+ /* 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
+ block. When inlining we want statements without a block to
+ appear in the block of the function call. */
+ new_block = id->block;
+ if (gimple_block (copy))
+ {
+ tree *n;
+ n = (tree *) pointer_map_contains (id->decl_map, gimple_block (copy));
+ gcc_assert (n);
+ new_block = *n;
+ }
+
+ gimple_set_block (copy, new_block);
+
+ if (gimple_debug_bind_p (copy))
+ return copy;
+
+ /* Remap all the operands in COPY. */
+ memset (&wi, 0, sizeof (wi));
+ wi.info = id;
+ if (skip_first)
+ walk_tree (gimple_op_ptr (copy, 1), remap_gimple_op_r, &wi, NULL);
+ else
+ walk_gimple_op (copy, remap_gimple_op_r, &wi);
+
+ /* Clear the copied virtual operands. We are not remapping them here
+ but are going to recreate them from scratch. */
+ if (gimple_has_mem_ops (copy))
+ {
+ gimple_set_vdef (copy, NULL_TREE);
+ gimple_set_vuse (copy, NULL_TREE);
+ }
+
+ return copy;
+}
+
+