/* Tree inlining.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Alexandre Oliva <aoliva@redhat.com>
{
new = make_ssa_name (new, NULL);
insert_decl_map (id, name, new);
- if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
- {
- SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
- if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
- set_default_def (SSA_NAME_VAR (new), new);
- }
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new)
= SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
TREE_TYPE (new) = TREE_TYPE (SSA_NAME_VAR (new));
+ if (IS_EMPTY_STMT (SSA_NAME_DEF_STMT (name)))
+ {
+ /* By inlining function having uninitialized variable, we might
+ extend the lifetime (variable might get reused). This cause
+ ICE in the case we end up extending lifetime of SSA name across
+ abnormal edge, but also increase register presure.
+
+ We simply initialize all uninitialized vars by 0 except for case
+ we are inlining to very first BB. We can avoid this for all
+ BBs that are not withing strongly connected regions of the CFG,
+ but this is bit expensive to test.
+ */
+ if (id->entry_bb && is_gimple_reg (SSA_NAME_VAR (name))
+ && TREE_CODE (SSA_NAME_VAR (name)) != PARM_DECL
+ && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR, 0)->dest
+ || EDGE_COUNT (id->entry_bb->preds) != 1))
+ {
+ block_stmt_iterator bsi = bsi_last (id->entry_bb);
+ tree init_stmt
+ = build_gimple_modify_stmt (new,
+ fold_convert (TREE_TYPE (new),
+ integer_zero_node));
+ bsi_insert_after (&bsi, init_stmt, BSI_NEW_STMT);
+ SSA_NAME_DEF_STMT (new) = init_stmt;
+ SSA_NAME_IS_DEFAULT_DEF (new) = 0;
+ }
+ else
+ {
+ SSA_NAME_DEF_STMT (new) = build_empty_stmt ();
+ if (gimple_default_def (id->src_cfun, SSA_NAME_VAR (name)) == name)
+ set_default_def (SSA_NAME_VAR (new), new);
+ }
+ }
}
else
insert_decl_map (id, name, new);
tree map = remap_ssa_name (def, id);
/* Watch out RESULT_DECLs whose SSA names map directly
to them. */
- if (TREE_CODE (map) == SSA_NAME)
+ if (TREE_CODE (map) == SSA_NAME
+ && IS_EMPTY_STMT (SSA_NAME_DEF_STMT (map)))
set_default_def (t, map);
}
add_referenced_var (t);
static tree
remap_type_1 (tree type, copy_body_data *id)
{
- tree *node;
tree new, t;
- if (type == NULL)
- return type;
-
- /* See if we have remapped this type. */
- node = (tree *) pointer_map_contains (id->decl_map, type);
- if (node)
- return *node;
-
- /* The type only needs remapping if it's variably modified. */
- if (! variably_modified_type_p (type, id->src_fn))
- {
- insert_decl_map (id, type, type);
- return type;
- }
-
/* We do need a copy. build and register it now. If this is a pointer or
reference type, remap the designated type and make a new pointer or
reference type. */
remap_type (tree type, copy_body_data *id)
{
tree *node;
+ tree tmp;
if (type == NULL)
return type;
return type;
}
- return remap_type_1 (type, id);
+ id->remapping_type_depth++;
+ tmp = remap_type_1 (type, id);
+ id->remapping_type_depth--;
+
+ return tmp;
}
static tree
tree type = TREE_TYPE (TREE_TYPE (*n));
new = unshare_expr (*n);
old = *tp;
- *tp = fold_indirect_ref_1 (type, new);
+ *tp = gimple_fold_indirect_ref (new);
if (! *tp)
{
if (TREE_CODE (new) == ADDR_EXPR)
- *tp = TREE_OPERAND (new, 0);
+ {
+ *tp = fold_indirect_ref_1 (type, new);
+ /* ??? We should either assert here or build
+ a VIEW_CONVERT_EXPR instead of blindly leaking
+ incompatible types to our IL. */
+ if (! *tp)
+ *tp = TREE_OPERAND (new, 0);
+ }
else
{
*tp = build1 (INDIRECT_REF, type, new);
tweak some special cases. */
copy_tree_r (tp, walk_subtrees, NULL);
- /* Global variables we didn't seen yet needs to go into referenced
- vars. */
- if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL)
+ /* Global variables we haven't seen yet needs to go into referenced
+ vars. If not referenced from types only. */
+ if (gimple_in_ssa_p (cfun) && TREE_CODE (*tp) == VAR_DECL
+ && id->remapping_type_depth == 0)
add_referenced_var (*tp);
/* If EXPR has block defined, map it to newly constructed block.
and friends are up-to-date. */
else if (TREE_CODE (*tp) == ADDR_EXPR)
{
+ int invariant = TREE_INVARIANT (*tp);
walk_tree (&TREE_OPERAND (*tp, 0), copy_body_r, id, NULL);
/* Handle the case where we substituted an INDIRECT_REF
into the operand of the ADDR_EXPR. */
*tp = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0);
else
recompute_tree_invariant_for_addr_expr (*tp);
+ /* If this used to be invariant, but is not any longer,
+ then regimplification is probably needed. */
+ if (invariant && !TREE_INVARIANT (*tp))
+ id->regimplify = true;
*walk_subtrees = 0;
}
}
tree stmt = bsi_stmt (bsi);
tree orig_stmt = stmt;
+ id->regimplify = false;
walk_tree (&stmt, copy_body_r, id, NULL);
/* RETURN_EXPR might be removed,
/* With return slot optimization we can end up with
non-gimple (foo *)&this->m, fix that here. */
- if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
- && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == NOP_EXPR
- && !is_gimple_val (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0)))
+ if ((TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
+ && TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == NOP_EXPR
+ && !is_gimple_val (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0)))
+ || id->regimplify)
gimplify_stmt (&stmt);
bsi_insert_after (©_bsi, stmt, BSI_NEW_STMT);
walk_tree (&new_arg, copy_body_r, id, NULL);
gcc_assert (new_arg);
+ /* With return slot optimization we can end up with
+ non-gimple (foo *)&this->m, fix that here. */
+ if (TREE_CODE (new_arg) != SSA_NAME
+ && TREE_CODE (new_arg) != FUNCTION_DECL
+ && !is_gimple_val (new_arg))
+ {
+ tree stmts = NULL_TREE;
+ new_arg = force_gimple_operand (new_arg, &stmts,
+ true, NULL);
+ bsi_insert_on_edge_immediate (new_edge, stmts);
+ }
add_phi_arg (new_phi, new_arg, new_edge);
}
}
if (value
&& value != error_mark_node
&& !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)))
- rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+ {
+ if (fold_convertible_p (TREE_TYPE (p), value))
+ rhs = fold_build1 (NOP_EXPR, TREE_TYPE (p), value);
+ else
+ /* ??? For valid (GIMPLE) programs we should not end up here.
+ Still if something has gone wrong and we end up with truly
+ mismatched types here, fall back to using a VIEW_CONVERT_EXPR
+ to not leak invalid GIMPLE to the following passes. */
+ rhs = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (p), value);
+ }
/* If the parameter is never assigned to, has no SSA_NAMEs created,
we may not need to create a new variable here at all. Instead, we may
return;
}
+ /* If the value of argument is never used, don't care about initializing
+ it. */
+ if (gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p))
+ {
+ gcc_assert (!value || !TREE_SIDE_EFFECTS (value));
+ return;
+ }
+
/* Initialize this VAR_DECL from the equivalent argument. Convert
the argument to the proper type in case it was promoted. */
if (value)
{
var = return_slot;
gcc_assert (TREE_CODE (var) != SSA_NAME);
+ TREE_ADDRESSABLE (var) |= TREE_ADDRESSABLE (result);
}
if ((TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
/* We cannot inline functions that take a variable number of
arguments. */
case BUILT_IN_VA_START:
- case BUILT_IN_STDARG_START:
case BUILT_IN_NEXT_ARG:
case BUILT_IN_VA_END:
inline_forbidden_reason
return NULL_TREE;
}
+static tree
+inline_forbidden_p_2 (tree *nodep, int *walk_subtrees,
+ void *fnp)
+{
+ tree node = *nodep;
+ tree fn = (tree) fnp;
+
+ if (TREE_CODE (node) == LABEL_DECL && DECL_CONTEXT (node) == fn)
+ {
+ inline_forbidden_reason
+ = G_("function %q+F can never be inlined "
+ "because it saves address of local label in a static variable");
+ return node;
+ }
+
+ if (TYPE_P (node))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+
/* Return subexpression representing possible alloca call, if any. */
static tree
inline_forbidden_p (tree fndecl)
block_stmt_iterator bsi;
basic_block bb;
tree ret = NULL_TREE;
+ struct function *fun = DECL_STRUCT_FUNCTION (fndecl);
+ tree step;
- FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (fndecl))
+ FOR_EACH_BB_FN (bb, fun)
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
- inline_forbidden_p_1, fndecl);
+ inline_forbidden_p_1, fndecl);
if (ret)
goto egress;
}
+ for (step = fun->unexpanded_var_list; step; step = TREE_CHAIN (step))
+ {
+ tree decl = TREE_VALUE (step);
+ if (TREE_CODE (decl) == VAR_DECL
+ && TREE_STATIC (decl)
+ && !DECL_EXTERNAL (decl)
+ && DECL_INITIAL (decl))
+ ret = walk_tree_without_duplicates (&DECL_INITIAL (decl),
+ inline_forbidden_p_2, fndecl);
+ if (ret)
+ goto egress;
+ }
+
egress:
input_location = saved_loc;
return ret;
case COMPOUND_EXPR:
case BIND_EXPR:
case WITH_CLEANUP_EXPR:
+ case PAREN_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
case OMP_RETURN:
case OMP_CONTINUE:
case OMP_SECTIONS_SWITCH:
+ case OMP_ATOMIC_STORE:
break;
/* We don't account constants for now. Assume that the cost is amortized
break;
case SWITCH_EXPR:
- /* TODO: Cost of a switch should be derived from the number of
- branches. */
- d->count += d->weights->switch_cost;
+ /* Take into account cost of the switch + guess 2 conditional jumps for
+ each case label.
+
+ TODO: once the switch expansion logic is sufficiently separated, we can
+ do better job on estimating cost of the switch. */
+ d->count += TREE_VEC_LENGTH (SWITCH_LABELS (x)) * 2;
break;
/* Few special cases of expensive operations. This is useful
case CALL_EXPR:
{
tree decl = get_callee_fndecl (x);
+ tree addr = CALL_EXPR_FN (x);
+ tree funtype = TREE_TYPE (addr);
+
+ gcc_assert (POINTER_TYPE_P (funtype));
+ funtype = TREE_TYPE (funtype);
if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_MD)
cost = d->weights->target_builtin_call_cost;
break;
}
+ if (decl)
+ funtype = TREE_TYPE (decl);
+
/* Our cost must be kept in sync with cgraph_estimate_size_after_inlining
- that does use function declaration to figure out the arguments. */
- if (!decl)
+ that does use function declaration to figure out the arguments.
+
+ When we deal with function with no body nor prototype, base estimates on
+ actual parameters of the call expression. Otherwise use either the actual
+ arguments types or function declaration for more precise answer. */
+ if (decl && DECL_ARGUMENTS (decl))
+ {
+ tree arg;
+ for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
+ d->count += estimate_move_cost (TREE_TYPE (arg));
+ }
+ else if (funtype && prototype_p (funtype))
+ {
+ tree t;
+ for (t = TYPE_ARG_TYPES (funtype); t; t = TREE_CHAIN (t))
+ d->count += estimate_move_cost (TREE_VALUE (t));
+ }
+ else
{
tree a;
call_expr_arg_iterator iter;
FOR_EACH_CALL_EXPR_ARG (a, iter, x)
d->count += estimate_move_cost (TREE_TYPE (a));
}
- else
- {
- tree arg;
- for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
- d->count += estimate_move_cost (TREE_TYPE (arg));
- }
d->count += cost;
break;
case OMP_ORDERED:
case OMP_CRITICAL:
case OMP_ATOMIC:
+ case OMP_ATOMIC_LOAD:
/* OpenMP directives are generally very expensive. */
d->count += d->weights->omp_cost;
break;
eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST);
eni_inlining_weights.target_builtin_call_cost = 1;
eni_inlining_weights.div_mod_cost = 10;
- eni_inlining_weights.switch_cost = 1;
eni_inlining_weights.omp_cost = 40;
eni_size_weights.call_cost = 1;
eni_size_weights.target_builtin_call_cost = 1;
eni_size_weights.div_mod_cost = 1;
- eni_size_weights.switch_cost = 10;
eni_size_weights.omp_cost = 40;
/* Estimating time for call is difficult, since we have no idea what the
eni_time_weights.call_cost = 10;
eni_time_weights.target_builtin_call_cost = 10;
eni_time_weights.div_mod_cost = 10;
- eni_time_weights.switch_cost = 4;
eni_time_weights.omp_cost = 40;
}
/* Walk to the last sub-block. */
for (blk_p = &BLOCK_SUBBLOCKS (current_block);
*blk_p;
- blk_p = &TREE_CHAIN (*blk_p))
+ blk_p = &BLOCK_CHAIN (*blk_p))
;
*blk_p = new_block;
BLOCK_SUPERCONTEXT (new_block) = current_block;
{
copy_body_data *id;
tree t;
- tree use_retvar;
+ tree retvar, use_retvar;
tree fn;
struct pointer_map_t *st;
tree return_slot;
id->src_cfun = DECL_STRUCT_FUNCTION (fn);
id->call_expr = t;
+ gcc_assert (!id->src_cfun->after_inlining);
+
+ id->entry_bb = bb;
initialize_inlined_parameters (id, t, fn, bb);
if (DECL_INITIAL (fn))
else
modify_dest = NULL;
+ /* If we are inlining a call to the C++ operator new, we don't want
+ to use type based alias analysis on the return value. Otherwise
+ we may get confused if the compiler sees that the inlined new
+ function returns a pointer which was just deleted. See bug
+ 33407. */
+ if (DECL_IS_OPERATOR_NEW (fn))
+ {
+ return_slot = NULL;
+ modify_dest = NULL;
+ }
+
/* Declare the return variable for the function. */
- declare_return_variable (id, return_slot,
- modify_dest, &use_retvar);
+ retvar = declare_return_variable (id, return_slot,
+ modify_dest, &use_retvar);
+
+ if (DECL_IS_OPERATOR_NEW (fn))
+ {
+ gcc_assert (TREE_CODE (retvar) == VAR_DECL
+ && POINTER_TYPE_P (TREE_TYPE (retvar)));
+ DECL_NO_TBAA_P (retvar) = 1;
+ }
/* This is it. Duplicate the callee body. Assume callee is
pre-gimplified. Note that we must not alter the caller
if (pointer_set_contains (statements, bsi_stmt (bsi)))
{
tree old_stmt = bsi_stmt (bsi);
+ tree old_call = get_call_expr_in (old_stmt);
+
if (fold_stmt (bsi_stmt_ptr (bsi)))
{
update_stmt (bsi_stmt (bsi));
- if (maybe_clean_or_replace_eh_stmt (old_stmt, bsi_stmt (bsi)))
- tree_purge_dead_eh_edges (BASIC_BLOCK (first));
+ if (old_call)
+ cgraph_update_edges_for_call_stmt (old_stmt, old_call,
+ bsi_stmt (bsi));
+ if (maybe_clean_or_replace_eh_stmt (old_stmt,
+ bsi_stmt (bsi)))
+ tree_purge_dead_eh_edges (BASIC_BLOCK (first));
}
}
}
id.dst_fn = current_function_decl;
id.src_cfun = cfun;
id.decl_map = pointer_map_create ();
+ id.copy_decl = copy_decl_no_change;
type = remap_type_1 (type, &id);
pointer_map_destroy (id.decl_map);
+ TYPE_CANONICAL (type) = type;
+
return type;
}