Add push/pop_function_decl

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.

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.
This commit is contained in:
Richard Sandiford 2024-11-11 12:32:13 +00:00
parent e22d80d4f0
commit 9d14f677a0
2 changed files with 71 additions and 15 deletions

View File

@ -4707,40 +4707,74 @@ invoke_set_current_function_hook (tree fndecl)
} }
} }
/* Set cfun to NEW_CFUN and switch to the optimization and target options
associated with NEW_FNDECL.
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_fndecl);
redirect_edge_var_map_empty ();
}
}
/* cfun should never be set directly; use this function. */ /* cfun should never be set directly; use this function. */
void void
set_cfun (struct function *new_cfun, bool force) set_cfun (struct function *new_cfun, bool force)
{ {
if (cfun != new_cfun || force) set_function_decl (new_cfun, new_cfun ? new_cfun->decl : NULL_TREE, force);
{
cfun = new_cfun;
invoke_set_current_function_hook (new_cfun ? new_cfun->decl : NULL_TREE);
redirect_edge_var_map_empty ();
}
} }
/* Initialized with NOGC, making this poisonous to the garbage collector. */ /* Initialized with NOGC, making this poisonous to the garbage collector. */
static vec<function *> cfun_stack; static vec<function *> cfun_stack;
/* 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. */
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_fndecl;
set_function_decl (new_cfun, new_fndecl, force);
}
/* 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
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 /* Push the current cfun onto the stack, and set cfun to new_cfun. Also set
current_function_decl accordingly. */ current_function_decl accordingly. */
void void
push_cfun (struct function *new_cfun) push_cfun (struct function *new_cfun)
{ {
gcc_assert ((!cfun && !current_function_decl) push_function_decl (new_cfun, new_cfun ? new_cfun->decl : NULL_TREE, false);
|| (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);
} }
/* Pop cfun from the stack. Also set current_function_decl accordingly. */ /* A common subroutine for pop_cfun and pop_function_decl. FORCE is as
for set_function_decl. */
void static void
pop_cfun (void) pop_cfun_1 (bool force)
{ {
struct function *new_cfun = cfun_stack.pop (); struct function *new_cfun = cfun_stack.pop ();
/* When in_dummy_function, we do have a cfun but current_function_decl is /* 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 gcc_checking_assert (in_dummy_function
|| !cfun || !cfun
|| current_function_decl == cfun->decl); || current_function_decl == cfun->decl);
set_cfun (new_cfun); set_cfun (new_cfun, force);
current_function_decl = new_cfun ? new_cfun->decl : NULL_TREE; 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. */ /* Return value of funcdef and increase it. */
int int
get_next_funcdef_no (void) get_next_funcdef_no (void)

View File

@ -701,6 +701,8 @@ extern void number_blocks (tree);
extern void set_cfun (struct function *new_cfun, bool force = false); extern void set_cfun (struct function *new_cfun, bool force = false);
extern void push_cfun (struct function *new_cfun); extern void push_cfun (struct function *new_cfun);
extern void pop_cfun (void); 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_next_funcdef_no (void);
extern int get_last_funcdef_no (void); extern int get_last_funcdef_no (void);