With some functions, there might be the case where every stack variable is a live at the end of a basic block. If that is the case then it is known that all stack variables will conflict with each other so there is no reason to go through figuring out what variables conflict with each other. Since we hold the live variables in a bitmap, we can just count the number of bits and compare it to the number of stack variables. Currently the bitmap is a linked-list of 128bits each, on average there is going to be less than 128 stack variables in a function so this is not adding much overhead to check.
In the case of the testcase from PR 114480 with `-fstack-reuse=none`, this reduces `expand var` from 70s down to less than 1s. Bootstrapped and tested on x86_64-linux-gnu. gcc/ChangeLog: * cfgexpand.cc (add_scope_conflicts): Return true if all variables are alive at the end of a basic block. (partition_stack_vars): Take a new argument, all_active. Return early if all_active is true after the qsort. (expand_used_vars): Update call to partition_stack_vars. Signed-off-by: Andrew Pinski <quic_apin...@quicinc.com> --- gcc/cfgexpand.cc | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 277ef659f30..e84f12a5e93 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -941,21 +941,23 @@ add_scope_conflicts_1 (vars_ssa_cache &cache, basic_block bb, bitmap work, bool } /* Generate stack partition conflicts between all partitions that are - simultaneously live. */ + simultaneously live. Returns true if it is known that every stack + vars will conflict with each other. */ -static void +static bool add_scope_conflicts (void) { /* If there is only one variable, there is nothing to be done as there is only possible partition. */ if (stack_vars_num == 1) - return; + return true; basic_block bb; bool changed; bitmap work = BITMAP_ALLOC (NULL); int *rpo; int n_bbs; + bool all_active = false; vars_ssa_cache cache; @@ -987,20 +989,41 @@ add_scope_conflicts (void) active = (bitmap)bb->aux; add_scope_conflicts_1 (cache, bb, work, false); if (bitmap_ior_into (active, work)) - changed = true; + { + /* If all of the stack variables + are alive at the end at any of the basic blocks, + then we know all of them will conflict with each + other. */ + unsigned numactive = bitmap_count_bits (active); + if (numactive == stack_vars_num) + { + all_active = true; + changed = false; + break; + } + changed = true; + } } } - FOR_EACH_BB_FN (bb, cfun) - add_scope_conflicts_1 (cache, bb, work, true); + if (!all_active) + { + FOR_EACH_BB_FN (bb, cfun) + add_scope_conflicts_1 (cache, bb, work, true); + } if (dump_file && (dump_flags & TDF_DETAILS)) - cache.dump (dump_file); + { + cache.dump (dump_file); + if (all_active) + fprintf (dump_file, "All stack variables conflict.\n"); + } free (rpo); BITMAP_FREE (work); FOR_ALL_BB_FN (bb, cfun) BITMAP_FREE (bb->aux); + return all_active; } /* A subroutine of partition_stack_vars. A comparison function for qsort, @@ -1233,7 +1256,7 @@ union_stack_vars (unsigned a, unsigned b) */ static void -partition_stack_vars (void) +partition_stack_vars (bool all_active) { unsigned si, sj, n = stack_vars_num; @@ -1246,6 +1269,9 @@ partition_stack_vars (void) qsort (stack_vars_sorted, n, sizeof (unsigned), stack_var_cmp); + if (all_active) + return; + for (si = 0; si < n; ++si) { unsigned i = stack_vars_sorted[si]; @@ -2580,7 +2606,7 @@ expand_used_vars (bitmap forced_stack_vars) { bool has_addressable_vars = false; - add_scope_conflicts (); + bool all_active = add_scope_conflicts (); /* If stack protection is enabled, we don't share space between vulnerable data and non-vulnerable data. */ @@ -2596,7 +2622,7 @@ expand_used_vars (bitmap forced_stack_vars) /* Now that we have collected all stack variables, and have computed a minimal interference graph, attempt to save some stack space. */ - partition_stack_vars (); + partition_stack_vars (all_active); if (dump_file) dump_stack_var_partition (); } -- 2.43.0