diff options
Diffstat (limited to 'gcc/tree-inline.c')
-rw-r--r-- | gcc/tree-inline.c | 97 |
1 files changed, 81 insertions, 16 deletions
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 813f18d..d68190f 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -107,6 +107,21 @@ int flag_inline_trees = 0; o Provide heuristics to clamp inlining of recursive template 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. */ + +eni_weights eni_size_weights; + +/* Weights that estimate_num_insns uses to estimate the time necessary + to execute the produced code. */ + +eni_weights eni_time_weights; + /* Prototypes. */ static tree declare_return_variable (copy_body_data *, tree, tree, tree *); @@ -1904,14 +1919,26 @@ estimate_move_cost (tree type) return ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); } +/* Arguments for estimate_num_insns_1. */ + +struct eni_data +{ + /* Used to return the number of insns. */ + int count; + + /* Weights of various constructs. */ + eni_weights *weights; +}; + /* Used by estimate_num_insns. Estimate number of instructions seen by given statement. */ static tree estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) { - int *count = (int *) data; + struct eni_data *d = data; tree x = *tp; + unsigned cost; if (IS_TYPE_OR_DECL_P (x)) { @@ -2026,7 +2053,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) /* Otherwise it's a store, so fall through to compute the move cost. */ case CONSTRUCTOR: - *count += estimate_move_cost (TREE_TYPE (x)); + d->count += estimate_move_cost (TREE_TYPE (x)); break; /* Assign cost of 1 to usual operations. @@ -2090,8 +2117,6 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case POSTDECREMENT_EXPR: case POSTINCREMENT_EXPR: - case SWITCH_EXPR: - case ASM_EXPR: case REALIGN_LOAD_EXPR: @@ -2116,7 +2141,13 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case VEC_INTERLEAVE_LOW_EXPR: case RESX_EXPR: - *count += 1; + d->count += 1; + break; + + case SWITCH_EXPR: + /* TODO: Cost of a switch should be derived from the number of + branches. */ + d->count += d->weights->switch_cost; break; /* Few special cases of expensive operations. This is useful @@ -2131,13 +2162,14 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case FLOOR_MOD_EXPR: case ROUND_MOD_EXPR: case RDIV_EXPR: - *count += 10; + d->count += d->weights->div_mod_cost; break; case CALL_EXPR: { tree decl = get_callee_fndecl (x); tree arg; + cost = d->weights->call_cost; if (decl && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL) switch (DECL_FUNCTION_CODE (decl)) { @@ -2146,6 +2178,10 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) return NULL_TREE; case BUILT_IN_EXPECT: return NULL_TREE; + /* Prefetch instruction is not expensive. */ + case BUILT_IN_PREFETCH: + cost = 1; + break; default: break; } @@ -2155,15 +2191,15 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) if (!decl) { for (arg = TREE_OPERAND (x, 1); arg; arg = TREE_CHAIN (arg)) - *count += estimate_move_cost (TREE_TYPE (TREE_VALUE (arg))); + d->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)); + d->count += estimate_move_cost (TREE_TYPE (arg)); } - *count += PARAM_VALUE (PARAM_INLINE_CALL_COST); + d->count += cost; break; } @@ -2177,7 +2213,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) case OMP_CRITICAL: case OMP_ATOMIC: /* OpenMP directives are generally very expensive. */ - *count += 40; + d->count += d->weights->omp_cost; break; default: @@ -2186,16 +2222,20 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data) return NULL; } -/* Estimate number of instructions that will be created by expanding EXPR. */ +/* Estimate number of instructions that will be created by expanding EXPR. + WEIGHTS contains weigths attributed to various constructs. */ int -estimate_num_insns (tree expr) +estimate_num_insns (tree expr, eni_weights *weights) { - int num = 0; struct pointer_set_t *visited_nodes; basic_block bb; block_stmt_iterator bsi; struct function *my_function; + struct eni_data data; + + data.count = 0; + data.weights = weights; /* If we're given an entire function, walk the CFG. */ if (TREE_CODE (expr) == FUNCTION_DECL) @@ -2210,15 +2250,40 @@ estimate_num_insns (tree expr) bsi_next (&bsi)) { walk_tree (bsi_stmt_ptr (bsi), estimate_num_insns_1, - &num, visited_nodes); + &data, visited_nodes); } } pointer_set_destroy (visited_nodes); } else - walk_tree_without_duplicates (&expr, estimate_num_insns_1, &num); + walk_tree_without_duplicates (&expr, estimate_num_insns_1, &data); - return num; + return data.count; +} + +/* Initializes weights used by estimate_num_insns. */ + +void +init_inline_once (void) +{ + eni_inlining_weights.call_cost = PARAM_VALUE (PARAM_INLINE_CALL_COST); + 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.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 + called function does. In the current uses of eni_time_weights, + underestimating the cost does less harm than overestimating it, so + we choose a rather small walue here. */ + eni_time_weights.call_cost = 10; + eni_time_weights.div_mod_cost = 10; + eni_time_weights.switch_cost = 4; + eni_time_weights.omp_cost = 40; } typedef struct function *function_p; |