diff options
Diffstat (limited to 'gcc/tree-inline.c')
-rw-r--r-- | gcc/tree-inline.c | 110 |
1 files changed, 90 insertions, 20 deletions
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 120bab0fb21..efbba304f9d 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -173,6 +173,11 @@ remap_decl (tree decl, inline_data *id) /* Make a copy of the variable or label. */ tree t = copy_decl_for_inlining (decl, fn, VARRAY_TREE (id->fns, 0)); + /* Remember it, so that if we encounter this local entity again + we can reuse this copy. Do this early because remap_type may + need this decl for TYPE_STUB_DECL. */ + insert_decl_map (id, decl, t); + /* Remap types, if necessary. */ TREE_TYPE (t) = remap_type (TREE_TYPE (t), id); if (TREE_CODE (t) == TYPE_DECL) @@ -215,9 +220,6 @@ remap_decl (tree decl, inline_data *id) } #endif - /* Remember it, so that if we encounter this local entity - again we can reuse this copy. */ - insert_decl_map (id, decl, t); return t; } @@ -286,6 +288,9 @@ remap_type (tree type, inline_data *id) TYPE_NEXT_VARIANT (new) = NULL; } + if (TYPE_STUB_DECL (type)) + TYPE_STUB_DECL (new) = remap_decl (TYPE_STUB_DECL (type), id); + /* Lazily create pointer and reference types. */ TYPE_POINTER_TO (new) = NULL; TYPE_REFERENCE_TO (new) = NULL; @@ -1014,6 +1019,17 @@ inline_forbidden_p_1 (tree *nodep, int *walk_subtrees ATTRIBUTE_UNUSED, "it uses non-local goto"); return node; + case BUILT_IN_RETURN: + case BUILT_IN_APPLY_ARGS: + /* If a __builtin_apply_args caller would be inlined, + it would be saving arguments of the function it has + been inlined into. Similarly __builtin_return would + return from the function the inline has been inlined into. */ + inline_forbidden_reason + = N_("%Jfunction %qF can never be inlined because " + "it uses __builtin_return or __builtin_apply_args"); + return node; + default: break; } @@ -1165,6 +1181,23 @@ inlinable_function_p (tree fn) return inlinable; } +/* Estimate the cost of a memory move. Use machine dependent + word size and take possible memcpy call into account. */ + +int +estimate_move_cost (tree type) +{ + HOST_WIDE_INT size; + + size = int_size_in_bytes (type); + + if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO) + /* Cost of a memcpy call, 3 arguments and the call. */ + return 4; + else + return ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); +} + /* Used by estimate_num_insns. Estimate number of instructions seen by given statement. */ @@ -1243,28 +1276,50 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) *walk_subtrees = 0; return NULL; - /* Recognize assignments of large structures and constructors of - big arrays. */ + /* Try to estimate the cost of assignments. We have three cases to + deal with: + 1) Simple assignments to registers; + 2) Stores to things that must live in memory. This includes + "normal" stores to scalars, but also assignments of large + structures, or constructors of big arrays; + 3) TARGET_EXPRs. + + Let us look at the first two cases, assuming we have "a = b + C": + <modify_expr <var_decl "a"> <plus_expr <var_decl "b"> <constant C>> + If "a" is a GIMPLE register, the assignment to it is free on almost + any target, because "a" usually ends up in a real register. Hence + the only cost of this expression comes from the PLUS_EXPR, and we + can ignore the MODIFY_EXPR. + If "a" is not a GIMPLE register, the assignment to "a" will most + likely be a real store, so the cost of the MODIFY_EXPR is the cost + of moving something into "a", which we compute using the function + estimate_move_cost. + + The third case deals with TARGET_EXPRs, for which the semantics are + that a temporary is assigned, unless the TARGET_EXPR itself is being + assigned to something else. In the latter case we do not need the + temporary. E.g. in <modify_expr <var_decl "a"> <target_expr>>, the + MODIFY_EXPR is free. */ case INIT_EXPR: case MODIFY_EXPR: - x = TREE_OPERAND (x, 0); - /* FALLTHRU */ + /* Is the right and side a TARGET_EXPR? */ + if (TREE_CODE (TREE_OPERAND (x, 1)) == TARGET_EXPR) + break; + /* ... fall through ... */ + case TARGET_EXPR: + x = TREE_OPERAND (x, 0); + /* Is this an assignments to a register? */ + if (is_gimple_reg (x)) + break; + /* Otherwise it's a store, so fall through to compute the move cost. */ + case CONSTRUCTOR: - { - HOST_WIDE_INT size; - - size = int_size_in_bytes (TREE_TYPE (x)); - - if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO) - *count += 10; - else - *count += ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); - } + *count += estimate_move_cost (TREE_TYPE (x)); break; - /* Assign cost of 1 to usual operations. - ??? We may consider mapping RTL costs to this. */ + /* Assign cost of 1 to usual operations. + ??? We may consider mapping RTL costs to this. */ case COND_EXPR: case PLUS_EXPR: @@ -1351,6 +1406,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case CALL_EXPR: { tree decl = get_callee_fndecl (x); + tree arg; if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (decl)) @@ -1363,7 +1419,21 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) default: break; } - *count += 10; + + /* 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) + { + for (arg = TREE_OPERAND (x, 1); arg; arg = TREE_CHAIN (arg)) + *count += estimate_move_cost (TREE_TYPE (TREE_VALUE (arg))); + } + else + { + for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg)) + *count += estimate_move_cost (TREE_TYPE (arg)); + } + + *count += PARAM_VALUE (PARAM_INLINE_CALL_COST); break; } default: |