https://gcc.gnu.org/g:9d14f677a0da80bc6355955469c69709b1d3c67e

commit r15-5084-g9d14f677a0da80bc6355955469c69709b1d3c67e
Author: Richard Sandiford <richard.sandif...@arm.com>
Date:   Mon Nov 11 12:32:13 2024 +0000

    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.

Diff:
---
 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 73490f0da10a..bf74e1ea208d 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 243f5dd1b8c8..92ba93c3f70f 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);

Reply via email to