#include "tree-mudflap.h"
#include "tree-flow.h"
#include "function.h"
-#include "ggc.h"
#include "tree-flow.h"
#include "diagnostic.h"
#include "except.h"
calls? */
-/* Weights that estimate_num_insns uses for heuristics in inlining. */
-
-eni_weights eni_inlining_weights;
-
/* Weights that estimate_num_insns uses to estimate the size of the
produced code. */
&& (TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL
|| !id->transform_return_to_modify))
{
+ struct ptr_info_def *pi;
new_tree = make_ssa_name (new_tree, NULL);
insert_decl_map (id, name, new_tree);
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree)
= SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name);
TREE_TYPE (new_tree) = TREE_TYPE (SSA_NAME_VAR (new_tree));
+ /* At least IPA points-to info can be directly transferred. */
+ if (id->src_cfun->gimple_df
+ && id->src_cfun->gimple_df->ipa_pta
+ && (pi = SSA_NAME_PTR_INFO (name))
+ && !pi->pt.anything)
+ {
+ struct ptr_info_def *new_pi = get_ptr_info (new_tree);
+ new_pi->pt = pi->pt;
+ }
if (gimple_nop_p (SSA_NAME_DEF_STMT (name)))
{
/* By inlining function having uninitialized variable, we might
&& (TREE_CODE (t) == VAR_DECL
|| TREE_CODE (t) == RESULT_DECL || TREE_CODE (t) == PARM_DECL))
{
- tree def = gimple_default_def (id->src_cfun, decl);
get_var_ann (t);
- if (TREE_CODE (decl) != PARM_DECL && def)
- {
- tree map = remap_ssa_name (def, id);
- /* Watch out RESULT_DECLs whose SSA names map directly
- to them. */
- if (TREE_CODE (map) == SSA_NAME
- && gimple_nop_p (SSA_NAME_DEF_STMT (map)))
- set_default_def (t, map);
- }
add_referenced_var (t);
}
return t;
for (old_var = decls; old_var; old_var = TREE_CHAIN (old_var))
{
tree new_var;
- tree origin_var = DECL_ORIGIN (old_var);
if (can_be_nonlocal (old_var, id))
{
if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
&& !DECL_IGNORED_P (old_var)
&& nonlocalized_list)
- VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+ VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
continue;
}
if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE)
&& !DECL_IGNORED_P (old_var)
&& nonlocalized_list)
- VEC_safe_push (tree, gc, *nonlocalized_list, origin_var);
+ VEC_safe_push (tree, gc, *nonlocalized_list, old_var);
}
else
{
}
if (BIND_EXPR_VARS (*tp))
- /* This will remap a lot of the same decls again, but this should be
- harmless. */
- BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
+ {
+ tree t;
+
+ /* This will remap a lot of the same decls again, but this should be
+ harmless. */
+ BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id);
+
+ /* Also copy value-expressions. */
+ for (t = BIND_EXPR_VARS (*tp); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == VAR_DECL
+ && DECL_HAS_VALUE_EXPR_P (t))
+ {
+ tree tem = DECL_VALUE_EXPR (t);
+ walk_tree (&tem, copy_tree_body_r, id, NULL);
+ SET_DECL_VALUE_EXPR (t, tem);
+ }
+ }
}
default:
break;
}
+
+ /* Reset alias info if we didn't apply measures to
+ keep it valid over inlining by setting DECL_PT_UID. */
+ if (!id->src_cfun->gimple_df
+ || !id->src_cfun->gimple_df->ipa_pta)
+ gimple_call_reset_alias_info (copy);
}
break;
bb->frequency,
copy_basic_block->frequency);
}
+ stmt = cgraph_redirect_edge_call_stmt_to_callee (edge);
}
break;
/* Constant propagation on argument done during inlining
may create new direct call. Produce an edge for it. */
if ((!edge
- || (edge->indirect_call
+ || (edge->indirect_inlining_edge
&& id->transform_call_graph_edges == CB_CGE_MOVE_CLONES))
- && is_gimple_call (stmt)
&& (fn = gimple_call_fndecl (stmt)) != NULL)
{
struct cgraph_node *dest = cgraph_node (fn);
cfun->last_verified = src_cfun->last_verified;
cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
- cfun->function_frequency = src_cfun->function_frequency;
cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
cfun->stdarg = src_cfun->stdarg;
cfun->dont_save_pending_sizes_p = src_cfun->dont_save_pending_sizes_p;
tree caller = id->dst_fn;
tree result = DECL_RESULT (callee);
tree callee_type = TREE_TYPE (result);
- tree caller_type = TREE_TYPE (TREE_TYPE (callee));
+ tree caller_type;
tree var, use;
+ /* Handle type-mismatches in the function declaration return type
+ vs. the call expression. */
+ if (modify_dest)
+ caller_type = TREE_TYPE (modify_dest);
+ else
+ caller_type = TREE_TYPE (TREE_TYPE (callee));
+
/* We don't need to do anything for functions that don't return
anything. */
if (!result || VOID_TYPE_P (callee_type))
if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (decl))
{
+ /* Builtins that expand to constants. */
case BUILT_IN_CONSTANT_P:
- return 0;
case BUILT_IN_EXPECT:
- return 0;
-
- /* Prefetch instruction is not expensive. */
- case BUILT_IN_PREFETCH:
- cost = weights->target_builtin_call_cost;
- break;
-
+ case BUILT_IN_OBJECT_SIZE:
+ case BUILT_IN_UNREACHABLE:
+ /* Simple register moves or loads from stack. */
+ case BUILT_IN_RETURN_ADDRESS:
+ case BUILT_IN_EXTRACT_RETURN_ADDR:
+ case BUILT_IN_FROB_RETURN_ADDR:
+ case BUILT_IN_RETURN:
+ case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+ case BUILT_IN_FRAME_ADDRESS:
+ case BUILT_IN_VA_END:
+ case BUILT_IN_STACK_SAVE:
+ case BUILT_IN_STACK_RESTORE:
/* Exception state returns or moves registers around. */
case BUILT_IN_EH_FILTER:
case BUILT_IN_EH_POINTER:
case BUILT_IN_EH_COPY_VALUES:
return 0;
+ /* builtins that are not expensive (that is they are most probably
+ expanded inline into resonably simple code). */
+ case BUILT_IN_ABS:
+ case BUILT_IN_ALLOCA:
+ case BUILT_IN_BSWAP32:
+ case BUILT_IN_BSWAP64:
+ case BUILT_IN_CLZ:
+ case BUILT_IN_CLZIMAX:
+ case BUILT_IN_CLZL:
+ case BUILT_IN_CLZLL:
+ case BUILT_IN_CTZ:
+ case BUILT_IN_CTZIMAX:
+ case BUILT_IN_CTZL:
+ case BUILT_IN_CTZLL:
+ case BUILT_IN_FFS:
+ case BUILT_IN_FFSIMAX:
+ case BUILT_IN_FFSL:
+ case BUILT_IN_FFSLL:
+ case BUILT_IN_IMAXABS:
+ case BUILT_IN_FINITE:
+ case BUILT_IN_FINITEF:
+ case BUILT_IN_FINITEL:
+ case BUILT_IN_FINITED32:
+ case BUILT_IN_FINITED64:
+ case BUILT_IN_FINITED128:
+ case BUILT_IN_FPCLASSIFY:
+ case BUILT_IN_ISFINITE:
+ case BUILT_IN_ISINF_SIGN:
+ case BUILT_IN_ISINF:
+ case BUILT_IN_ISINFF:
+ case BUILT_IN_ISINFL:
+ case BUILT_IN_ISINFD32:
+ case BUILT_IN_ISINFD64:
+ case BUILT_IN_ISINFD128:
+ case BUILT_IN_ISNAN:
+ case BUILT_IN_ISNANF:
+ case BUILT_IN_ISNANL:
+ case BUILT_IN_ISNAND32:
+ case BUILT_IN_ISNAND64:
+ case BUILT_IN_ISNAND128:
+ case BUILT_IN_ISNORMAL:
+ case BUILT_IN_ISGREATER:
+ case BUILT_IN_ISGREATEREQUAL:
+ case BUILT_IN_ISLESS:
+ case BUILT_IN_ISLESSEQUAL:
+ case BUILT_IN_ISLESSGREATER:
+ case BUILT_IN_ISUNORDERED:
+ case BUILT_IN_VA_ARG_PACK:
+ case BUILT_IN_VA_ARG_PACK_LEN:
+ case BUILT_IN_VA_COPY:
+ case BUILT_IN_TRAP:
+ case BUILT_IN_SAVEREGS:
+ case BUILT_IN_POPCOUNTL:
+ case BUILT_IN_POPCOUNTLL:
+ case BUILT_IN_POPCOUNTIMAX:
+ case BUILT_IN_POPCOUNT:
+ case BUILT_IN_PARITYL:
+ case BUILT_IN_PARITYLL:
+ case BUILT_IN_PARITYIMAX:
+ case BUILT_IN_PARITY:
+ case BUILT_IN_LABS:
+ case BUILT_IN_LLABS:
+ case BUILT_IN_PREFETCH:
+ cost = weights->target_builtin_call_cost;
+ break;
+
default:
break;
}
struct cgraph_edge *cs;
cs = cgraph_edge (node, stmt);
- if (cs)
+ if (cs && !cs->indirect_unknown_callee)
return cs->callee->decl;
return NULL_TREE;
/* If this call was originally indirect, we do not want to emit any
inlining related warnings or sorry messages because there are no
guarantees regarding those. */
- if (cg_edge->indirect_call)
+ if (cg_edge->indirect_inlining_edge)
goto egress;
if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))
cg_edge->frequency * REG_BR_PROB_BASE / CGRAPH_FREQ_BASE,
bb, return_block);
- /* Reset the escaped and callused solutions. */
+ /* Reset the escaped solution. */
if (cfun->gimple_df)
- {
- pt_solution_reset (&cfun->gimple_df->escaped);
- pt_solution_reset (&cfun->gimple_df->callused);
- }
+ pt_solution_reset (&cfun->gimple_df->escaped);
/* Clean up. */
if (id->debug_map)
copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
VAR_DECL, DECL_NAME (decl), type);
+ if (DECL_PT_UID_SET_P (decl))
+ SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn),
VAR_DECL, DECL_NAME (decl), type);
+ if (DECL_PT_UID_SET_P (decl))
+ SET_DECL_PT_UID (copy, DECL_PT_UID (decl));
TREE_READONLY (copy) = TREE_READONLY (decl);
TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
if (!DECL_BY_REFERENCE (decl))
(DECL_STRUCT_FUNCTION (old_decl));
initialize_cfun (new_decl, old_decl,
old_entry_block->count);
+ DECL_STRUCT_FUNCTION (new_decl)->gimple_df->ipa_pta
+ = id.src_cfun->gimple_df->ipa_pta;
push_cfun (DECL_STRUCT_FUNCTION (new_decl));
/* Copy the function's static chain. */
return false;
}
#endif
- tree caller, callee;
+ tree caller, callee, lhs;
caller = e->caller->decl;
callee = e->callee->decl;
return false;
}
+ /* Do not inline calls where we cannot triviall work around mismatches
+ in argument or return types. */
if (e->call_stmt
- && !gimple_check_call_args (e->call_stmt))
+ && ((DECL_RESULT (callee)
+ && !DECL_BY_REFERENCE (DECL_RESULT (callee))
+ && (lhs = gimple_call_lhs (e->call_stmt)) != NULL_TREE
+ && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)),
+ TREE_TYPE (lhs))
+ && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs))
+ || !gimple_check_call_args (e->call_stmt)))
{
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
gimple_call_set_cannot_inline (e->call_stmt, true);