diff options
author | Jan Hubicka <jh@suse.cz> | 2020-10-26 18:19:48 +0100 |
---|---|---|
committer | Jan Hubicka <jh@suse.cz> | 2020-10-26 18:19:48 +0100 |
commit | f20a6c57f0f26d9c60d6d6182f1e2181f727c834 (patch) | |
tree | 27c496c30e568070afa9a437c707bd911b31db10 /gcc/predict.c | |
parent | 63b2149fb4b0bd16c44ab9485cfdc37149e97b97 (diff) | |
download | gcc-f20a6c57f0f26d9c60d6d6182f1e2181f727c834.zip gcc-f20a6c57f0f26d9c60d6d6182f1e2181f727c834.tar.gz gcc-f20a6c57f0f26d9c60d6d6182f1e2181f727c834.tar.bz2 |
Implement three-level optimize_for_size predicates
this patch implements thre two-state optimize_for_size predicates, so with -Os
and with profile feedback for never executed code it returns OPTIMIZE_SIZE_MAX
while in cases we decide to optimize for size based on branch prediction logic
it return OPTIMIZE_SIZE_BALLANCED.
The idea is that for places where we guess that code is unlikely we do not
want to do extreme optimizations for size that leads to many fold slowdowns
(using idiv rather than few shigts or using rep based inlined stringops).
I will update RTL handling code to also support this with BB granuality (which
we don't currently). LLVM has -Os and -Oz levels where -Oz is our -Os and
LLVM's -Os would ocrrespond to OPTIMIZE_SIZE_BALLANCED. I wonder if we want
to export this to command line somehow? For me it would be definitly useful
to test things, I am not sure how "weaker" -Os is desired in practice.
gcc/ChangeLog:
* cgraph.h (cgraph_node::optimize_for_size_p): Return
optimize_size_level.
(cgraph_node::optimize_for_size_p): Update.
* coretypes.h (enum optimize_size_level): New enum.
* predict.c (unlikely_executed_edge_p): Microoptimize.
(optimize_function_for_size_p): Return optimize_size_level.
(optimize_bb_for_size_p): Likewise.
(optimize_edge_for_size_p): Likewise.
(optimize_insn_for_size_p): Likewise.
(optimize_loop_nest_for_size_p): Likewise.
* predict.h (optimize_function_for_size_p): Update declaration.
(optimize_bb_for_size_p): Update declaration.
(optimize_edge_for_size_p): Update declaration.
(optimize_insn_for_size_p): Update declaration.
(optimize_loop_for_size_p): Update declaration.
(optimize_loop_nest_for_size_p): Update declaration.
Diffstat (limited to 'gcc/predict.c')
-rw-r--r-- | gcc/predict.c | 65 |
1 files changed, 51 insertions, 14 deletions
diff --git a/gcc/predict.c b/gcc/predict.c index 5983889..361c401 100644 --- a/gcc/predict.c +++ b/gcc/predict.c @@ -243,7 +243,7 @@ probably_never_executed_bb_p (struct function *fun, const_basic_block bb) static bool unlikely_executed_edge_p (edge e) { - return (e->count () == profile_count::zero () + return (e->src->count == profile_count::zero () || e->probability == profile_probability::never ()) || (e->flags & (EDGE_EH | EDGE_FAKE)); } @@ -260,13 +260,15 @@ probably_never_executed_edge_p (struct function *fun, edge e) /* Return true if function FUN should always be optimized for size. */ -bool +optimize_size_level optimize_function_for_size_p (struct function *fun) { if (!fun || !fun->decl) - return optimize_size; + return optimize_size ? OPTIMIZE_SIZE_MAX : OPTIMIZE_SIZE_NO; cgraph_node *n = cgraph_node::get (fun->decl); - return n && n->optimize_for_size_p (); + if (n) + return n->optimize_for_size_p (); + return OPTIMIZE_SIZE_NO; } /* Return true if function FUN should always be optimized for speed. */ @@ -289,11 +291,16 @@ function_optimization_type (struct function *fun) /* Return TRUE if basic block BB should be optimized for size. */ -bool +optimize_size_level optimize_bb_for_size_p (const_basic_block bb) { - return (optimize_function_for_size_p (cfun) - || (bb && !maybe_hot_bb_p (cfun, bb))); + enum optimize_size_level ret = optimize_function_for_size_p (cfun); + + if (bb && ret < OPTIMIZE_SIZE_MAX && bb->count == profile_count::zero ()) + ret = OPTIMIZE_SIZE_MAX; + if (bb && ret < OPTIMIZE_SIZE_BALANCED && !maybe_hot_bb_p (cfun, bb)) + ret = OPTIMIZE_SIZE_BALANCED; + return ret; } /* Return TRUE if basic block BB should be optimized for speed. */ @@ -316,10 +323,16 @@ bb_optimization_type (const_basic_block bb) /* Return TRUE if edge E should be optimized for size. */ -bool +optimize_size_level optimize_edge_for_size_p (edge e) { - return optimize_function_for_size_p (cfun) || !maybe_hot_edge_p (e); + enum optimize_size_level ret = optimize_function_for_size_p (cfun); + + if (ret < OPTIMIZE_SIZE_MAX && unlikely_executed_edge_p (e)) + ret = OPTIMIZE_SIZE_MAX; + if (ret < OPTIMIZE_SIZE_BALANCED && !maybe_hot_edge_p (e)) + ret = OPTIMIZE_SIZE_BALANCED; + return ret; } /* Return TRUE if edge E should be optimized for speed. */ @@ -332,10 +345,13 @@ optimize_edge_for_speed_p (edge e) /* Return TRUE if the current function is optimized for size. */ -bool +optimize_size_level optimize_insn_for_size_p (void) { - return optimize_function_for_size_p (cfun) || !crtl->maybe_hot_insn_p; + enum optimize_size_level ret = optimize_function_for_size_p (cfun); + if (ret < OPTIMIZE_SIZE_BALANCED && !crtl->maybe_hot_insn_p) + ret = OPTIMIZE_SIZE_BALANCED; + return ret; } /* Return TRUE if the current function is optimized for speed. */ @@ -348,7 +364,7 @@ optimize_insn_for_speed_p (void) /* Return TRUE if LOOP should be optimized for size. */ -bool +optimize_size_level optimize_loop_for_size_p (class loop *loop) { return optimize_bb_for_size_p (loop->header); @@ -392,10 +408,31 @@ optimize_loop_nest_for_speed_p (class loop *loop) /* Return TRUE if nest rooted at LOOP should be optimized for size. */ -bool +optimize_size_level optimize_loop_nest_for_size_p (class loop *loop) { - return !optimize_loop_nest_for_speed_p (loop); + enum optimize_size_level ret = optimize_loop_for_size_p (loop); + class loop *l = loop; + + l = loop->inner; + while (l && l != loop) + { + if (ret == OPTIMIZE_SIZE_NO) + break; + ret = MIN (optimize_loop_for_size_p (l), ret); + if (l->inner) + l = l->inner; + else if (l->next) + l = l->next; + else + { + while (l != loop && !l->next) + l = loop_outer (l); + if (l != loop) + l = l->next; + } + } + return ret; } /* Return true if edge E is likely to be well predictable by branch |