On Fri, 8 Nov 2024, Richard Sandiford wrote: > For the aarch64 simd clones patches, it would be useful to be able to > push a function declaration onto the cfun stack, even though it has no > function body associated with it. That is, we want cfun to be null, > current_function_decl to be the decl itself, and the target and > optimisation flags to reflect the declaration. > > This patch adds a push/pop_function_decl pair to do that. > > I think the more direct way of doing what I want to do under the > existing interface would have been: > > push_cfun (nullptr); > invoke_set_current_function_hook (fndecl); > pop_cfun (); > > where invoke_set_current_function_hook would need to become public. > But it seemed safer to use the higher-level routines, since it makes > sure that the target/optimisation changes are synchronised with the > function changes. In particular, if cfun was null before the > sequence above, the pop_cfun would leave the flags unchanged, > rather than restore them to the state before the push_cfun. > > I realise this might seem a bit clunky though, so please let me know > if you think there's a cleaner way. I did briefly consider trying > to clean up all the cfun/current_function_decl stuff, but I don't think > I'll have time for that before stage 1. > > Bootstrapped & regression-tested on aarch64-linux-gnu. OK for trunk?
I think this is reasonable, thus OK unless you hear otherwise over the weekend. Richard. > Thanks, > Richard > > > gcc/ > * function.h (push_function_decl, pop_function_decl): Declare. > * function.cc (set_function_decl): New function, extracted from... > (set_cfun): ...here. > (push_function_decl): New function, extracted from... > (push_cfun): ...here. > (pop_cfun_1): New function, extracted from... > (pop_cfun): ...here. > (pop_function_decl): New function. > --- > gcc/function.cc | 80 +++++++++++++++++++++++++++++++++++++++++-------- > gcc/function.h | 2 ++ > 2 files changed, 69 insertions(+), 13 deletions(-) > > diff --git a/gcc/function.cc b/gcc/function.cc > index 73490f0da10..bf74e1ea208 100644 > --- a/gcc/function.cc > +++ b/gcc/function.cc > @@ -4707,40 +4707,74 @@ invoke_set_current_function_hook (tree fndecl) > } > } > > -/* cfun should never be set directly; use this function. */ > +/* Set cfun to NEW_CFUN and switch to the optimization and target options > + associated with NEW_FNDECL. > > -void > -set_cfun (struct function *new_cfun, bool force) > + FORCE says whether we should do the switch even if NEW_CFUN is the current > + function, e.g. because there has been a change in optimization or target > + options. */ > + > +static void > +set_function_decl (function *new_cfun, tree new_fndecl, bool force) > { > if (cfun != new_cfun || force) > { > cfun = new_cfun; > - invoke_set_current_function_hook (new_cfun ? new_cfun->decl : > NULL_TREE); > + invoke_set_current_function_hook (new_fndecl); > redirect_edge_var_map_empty (); > } > } > > +/* cfun should never be set directly; use this function. */ > + > +void > +set_cfun (struct function *new_cfun, bool force) > +{ > + set_function_decl (new_cfun, new_cfun ? new_cfun->decl : NULL_TREE, force); > +} > + > /* Initialized with NOGC, making this poisonous to the garbage collector. */ > > static vec<function *> cfun_stack; > > -/* Push the current cfun onto the stack, and set cfun to new_cfun. Also set > - current_function_decl accordingly. */ > +/* Push the current cfun onto the stack, then switch to function NEW_CFUN > + and FUNCTION_DECL NEW_FNDECL. FORCE is as for set_function_decl. */ > > -void > -push_cfun (struct function *new_cfun) > +static void > +push_function_decl (function *new_cfun, tree new_fndecl, bool force) > { > gcc_assert ((!cfun && !current_function_decl) > || (cfun && current_function_decl == cfun->decl)); > cfun_stack.safe_push (cfun); > - current_function_decl = new_cfun ? new_cfun->decl : NULL_TREE; > - set_cfun (new_cfun); > + current_function_decl = new_fndecl; > + set_function_decl (new_cfun, new_fndecl, force); > } > > -/* Pop cfun from the stack. Also set current_function_decl accordingly. */ > +/* Push the current cfun onto the stack and switch to function declaration > + NEW_FNDECL, which might or might not have a function body. FORCE is as > for > + set_function_decl. */ > > void > -pop_cfun (void) > +push_function_decl (tree new_fndecl, bool force) > +{ > + force |= current_function_decl != new_fndecl; > + push_function_decl (DECL_STRUCT_FUNCTION (new_fndecl), new_fndecl, force); > +} > + > +/* Push the current cfun onto the stack, and set cfun to new_cfun. Also set > + current_function_decl accordingly. */ > + > +void > +push_cfun (struct function *new_cfun) > +{ > + push_function_decl (new_cfun, new_cfun ? new_cfun->decl : NULL_TREE, > false); > +} > + > +/* A common subroutine for pop_cfun and pop_function_decl. FORCE is as > + for set_function_decl. */ > + > +static void > +pop_cfun_1 (bool force) > { > struct function *new_cfun = cfun_stack.pop (); > /* When in_dummy_function, we do have a cfun but current_function_decl is > @@ -4750,10 +4784,30 @@ pop_cfun (void) > gcc_checking_assert (in_dummy_function > || !cfun > || current_function_decl == cfun->decl); > - set_cfun (new_cfun); > + set_cfun (new_cfun, force); > current_function_decl = new_cfun ? new_cfun->decl : NULL_TREE; > } > > +/* Pop cfun from the stack. Also set current_function_decl accordingly. */ > + > +void > +pop_cfun (void) > +{ > + pop_cfun_1 (false); > +} > + > +/* Undo push_function_decl. */ > + > +void > +pop_function_decl (void) > +{ > + /* If the previous cfun was null, the options should be reset to the > + global set. Checking the current cfun against the new (popped) cfun > + wouldn't catch this if the current function decl has no function > + struct. */ > + pop_cfun_1 (!cfun_stack.last ()); > +} > + > /* Return value of funcdef and increase it. */ > int > get_next_funcdef_no (void) > diff --git a/gcc/function.h b/gcc/function.h > index 243f5dd1b8c..92ba93c3f70 100644 > --- a/gcc/function.h > +++ b/gcc/function.h > @@ -701,6 +701,8 @@ extern void number_blocks (tree); > extern void set_cfun (struct function *new_cfun, bool force = false); > extern void push_cfun (struct function *new_cfun); > extern void pop_cfun (void); > +extern void push_function_decl (tree, bool = false); > +extern void pop_function_decl (void); > > extern int get_next_funcdef_no (void); > extern int get_last_funcdef_no (void); > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)