#include "fibheap.h"
#include "params.h"
#include "gimple-pretty-print.h"
+#include "ipa-inline.h"
/* Per basic block info. */
dump_split_point (FILE * file, struct split_point *current)
{
fprintf (file,
- "Split point at BB %i header time:%i header size: %i"
- " split time: %i split size: %i\n bbs: ",
+ "Split point at BB %i\n"
+ " header time: %i header size: %i\n"
+ " split time: %i split size: %i\n bbs: ",
current->entry_bb->index, current->header_time,
current->header_size, current->split_time, current->split_size);
dump_bitmap (file, current->split_bbs);
into different partitions. This would require tracking of
EH regions and checking in consider_split_point if they
are not used elsewhere. */
- if (gimple_code (stmt) == GIMPLE_RESX
- && stmt_can_throw_external (stmt))
+ if (gimple_code (stmt) == GIMPLE_RESX)
{
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Cannot split: external resx.\n");
+ fprintf (dump_file, "Cannot split: resx.\n");
can_split = false;
}
if (gimple_code (stmt) == GIMPLE_EH_DISPATCH)
split_function (struct split_point *split_point)
{
VEC (tree, heap) *args_to_pass = NULL;
- bitmap args_to_skip = BITMAP_ALLOC (NULL);
+ bitmap args_to_skip;
tree parm;
int num = 0;
- struct cgraph_node *node;
+ struct cgraph_node *node, *cur_node = cgraph_get_node (current_function_decl);
basic_block return_bb = find_return_bb ();
basic_block call_bb;
gimple_stmt_iterator gsi;
tree retval = NULL, real_retval = NULL;
bool split_part_return_p = false;
gimple last_stmt = NULL;
- bool conv_needed = false;
unsigned int i;
tree arg;
dump_split_point (dump_file, split_point);
}
+ if (cur_node->local.can_change_signature)
+ args_to_skip = BITMAP_ALLOC (NULL);
+ else
+ args_to_skip = NULL;
+
/* Collect the parameters of new function and args_to_skip bitmap. */
for (parm = DECL_ARGUMENTS (current_function_decl);
parm; parm = DECL_CHAIN (parm), num++)
- if (!is_gimple_reg (parm)
- || !gimple_default_def (cfun, parm)
- || !bitmap_bit_p (split_point->ssa_names_to_pass,
- SSA_NAME_VERSION (gimple_default_def (cfun, parm))))
+ if (args_to_skip
+ && (!is_gimple_reg (parm)
+ || !gimple_default_def (cfun, parm)
+ || !bitmap_bit_p (split_point->ssa_names_to_pass,
+ SSA_NAME_VERSION (gimple_default_def (cfun,
+ parm)))))
bitmap_set_bit (args_to_skip, num);
else
{
- arg = gimple_default_def (cfun, parm);
- if (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm))
- != TYPE_MAIN_VARIANT (TREE_TYPE (arg)))
+ /* This parm might not have been used up to now, but is going to be
+ used, hence register it. */
+ add_referenced_var (parm);
+ if (is_gimple_reg (parm))
{
- conv_needed = true;
- arg = fold_convert (DECL_ARG_TYPE (parm), arg);
+ arg = gimple_default_def (cfun, parm);
+ if (!arg)
+ {
+ arg = make_ssa_name (parm, gimple_build_nop ());
+ set_default_def (parm, arg);
+ }
}
+ else
+ arg = parm;
+
+ if (!useless_type_conversion_p (DECL_ARG_TYPE (parm), TREE_TYPE (arg)))
+ arg = fold_convert (DECL_ARG_TYPE (parm), arg);
VEC_safe_push (tree, heap, args_to_pass, arg);
}
/* If RETURN_BB has virtual operand PHIs, they must be removed and the
virtual operand marked for renaming as we change the CFG in a way that
- tree-inline is not able to compensate for.
+ tree-inline is not able to compensate for.
Note this can happen whether or not we have a return value. If we have
a return value, then RETURN_BB may have PHIs for real operands too. */
if (return_bb != EXIT_BLOCK_PTR)
{
+ bool phi_p = false;
for (gsi = gsi_start_phis (return_bb); !gsi_end_p (gsi);)
{
gimple stmt = gsi_stmt (gsi);
}
mark_virtual_phi_result_for_renaming (stmt);
remove_phi_node (&gsi, true);
+ phi_p = true;
}
+ /* In reality we have to rename the reaching definition of the
+ virtual operand at return_bb as we will eventually release it
+ when we remove the code region we outlined.
+ So we have to rename all immediate virtual uses of that region
+ if we didn't see a PHI definition yet. */
+ /* ??? In real reality we want to set the reaching vdef of the
+ entry of the SESE region as the vuse of the call and the reaching
+ vdef of the exit of the SESE region as the vdef of the call. */
+ if (!phi_p)
+ for (gsi = gsi_start_bb (return_bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple stmt = gsi_stmt (gsi);
+ if (gimple_vuse (stmt))
+ {
+ gimple_set_vuse (stmt, NULL_TREE);
+ update_stmt (stmt);
+ }
+ if (gimple_vdef (stmt))
+ break;
+ }
}
/* Now create the actual clone. */
rebuild_cgraph_edges ();
- node = cgraph_function_versioning (cgraph_node (current_function_decl),
- NULL, NULL,
- args_to_skip,
+ node = cgraph_function_versioning (cur_node, NULL, NULL, args_to_skip,
split_point->split_bbs,
split_point->entry_bb, "part");
/* For usual cloning it is enough to clear builtin only when signature
DECL_BUILT_IN_CLASS (node->decl) = NOT_BUILT_IN;
DECL_FUNCTION_CODE (node->decl) = (enum built_in_function) 0;
}
- cgraph_node_remove_callees (cgraph_node (current_function_decl));
+ cgraph_node_remove_callees (cur_node);
if (!split_part_return_p)
TREE_THIS_VOLATILE (node->decl) = 1;
if (dump_file)
/* Produce the call statement. */
gsi = gsi_last_bb (call_bb);
- if (conv_needed)
- FOR_EACH_VEC_ELT (tree, args_to_pass, i, arg)
- if (!is_gimple_val (arg))
- {
- arg = force_gimple_operand_gsi (&gsi, arg, true, NULL_TREE,
- false, GSI_NEW_STMT);
- VEC_replace (tree, args_to_pass, i, arg);
- }
+ FOR_EACH_VEC_ELT (tree, args_to_pass, i, arg)
+ if (!is_gimple_val (arg))
+ {
+ arg = force_gimple_operand_gsi (&gsi, arg, true, NULL_TREE,
+ false, GSI_CONTINUE_LINKING);
+ VEC_replace (tree, args_to_pass, i, arg);
+ }
call = gimple_build_call_vec (node->decl, args_to_pass);
gimple_set_block (call, DECL_INITIAL (current_function_decl));
}
}
if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
- gimple_call_set_lhs (call, build_simple_mem_ref (retval));
+ {
+ gimple_call_set_lhs (call, build_simple_mem_ref (retval));
+ gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+ }
else
- gimple_call_set_lhs (call, retval);
+ {
+ tree restype;
+ restype = TREE_TYPE (DECL_RESULT (current_function_decl));
+ gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+ if (!useless_type_conversion_p (TREE_TYPE (retval), restype))
+ {
+ gimple cpy;
+ tree tem = create_tmp_reg (restype, NULL);
+ tem = make_ssa_name (tem, call);
+ cpy = gimple_build_assign_with_ops (NOP_EXPR, retval,
+ tem, NULL_TREE);
+ gsi_insert_after (&gsi, cpy, GSI_NEW_STMT);
+ retval = tem;
+ }
+ gimple_call_set_lhs (call, retval);
+ update_stmt (call);
+ }
}
- gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+ else
+ gsi_insert_after (&gsi, call, GSI_NEW_STMT);
}
/* We don't use return block (there is either no return in function or
multiple of them). So create new basic block with return statement.
}
free_dominance_info (CDI_DOMINATORS);
free_dominance_info (CDI_POST_DOMINATORS);
- compute_inline_parameters (node);
+ compute_inline_parameters (node, true);
}
/* Execute function splitting pass. */
basic_block bb;
int overall_time = 0, overall_size = 0;
int todo = 0;
- struct cgraph_node *node = cgraph_node (current_function_decl);
+ struct cgraph_node *node = cgraph_get_node (current_function_decl);
if (flags_from_decl_or_type (current_function_decl) & ECF_NORETURN)
{
}
/* This can be relaxed; function might become inlinable after splitting
away the uninlinable part. */
- if (!node->local.inlinable)
+ if (!inline_summary (node)->inlinable)
{
if (dump_file)
fprintf (dump_file, "Not splitting: not inlinable.\n");
return 0;
}
- if (node->local.disregard_inline_limits)
+ if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
{
if (dump_file)
fprintf (dump_file, "Not splitting: disregarding inline limits.\n");
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
+ TODO_verify_all /* todo_flags_finish */
}
};
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
+ TODO_verify_all /* todo_flags_finish */
}
};