On Tue, May 13, 2025 at 12:47 AM Andrew Pinski <quic_apin...@quicinc.com> wrote: > > 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.
It looks like a very narrow special case to me where handling it does come at a cost in compile-time and also code complexity. Do you have statistics on wheter it is really a narrow special-case, like, can you count the number of times this hits during bootstrap (for > 1 BB functions) compared to the times it does not hit? Aka which % of time does it help? It might be more useful to have a degraded mode for when we approach O(n*n) we'd give up on coalescing rather than just handling the very extreme case of all-all conflicts? Richard. > 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 >