[v3,1/4] i386: Split out call_saved_registers_type detection

Message ID 20260706213320.3909242-2-hjl.tools@gmail.com
State New
Headers
Series x86: Implement TARGET_FNTYPE_ABI |

Commit Message

H.J. Lu July 6, 2026, 9:33 p.m. UTC
  From: Richard Sandiford <rdsandiford@googlemail.com>

There are currently two places that want to query a function's
call_saved_registers_type: ix86_set_func_type (when setting up
cfun->machine) and ix86_type_no_callee_saved_registers_p
(a derived query).  The upcoming function_abi patch will add
another one, so this patch splits the code out into a subroutine.

ix86_set_func_type did some of the detection first, into
no_callee_saved_registers, but then ignored the result if
cfun->machine->func_type had already been set.  The patch therefore
moves all of the detection after the cfun->machine->func_type test,
rather than moving all of it before.

gcc/
	* config/i386/i386-protos.h (ix86_fntype_call_saved_registers):
	Declare.
	* config/i386/i386-options.cc (ix86_fntype_call_saved_registers): New
	function, split out from...
	(ix86_set_func_type): ...here.  Avoid calling it if the result
	would be ignored.
	* config/i386/i386.cc (ix86_type_no_callee_saved_registers_p): Use
	ix86_fntype_call_saved_registers instead of querying attributes
	directly.
---
 gcc/config/i386/i386-options.cc | 135 ++++++++++++++++----------------
 gcc/config/i386/i386-protos.h   |   2 +
 gcc/config/i386/i386.cc         |   8 +-
 3 files changed, 74 insertions(+), 71 deletions(-)
  

Patch

diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 8689ba5c883..da6e45f3f29 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3265,13 +3265,53 @@  ix86_simd_clone_adjust (struct cgraph_node *node)
   ix86_set_current_function (node->decl);
 }
 
+/* Return the call_saved_registers_type for function type FNTYPE.
+   If LOC is nonnull, report incompatible attributes against that
+   location, otherwise remain silent.  */
 
+call_saved_registers_type
+ix86_fntype_call_saved_registers (const_tree fntype, location_t *loc)
+{
+  auto call_saved_registers = TYPE_DEFAULT_CALL_SAVED_REGISTERS;
+  const char *interrupt_conflict = nullptr;
+  if (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (fntype)))
+    {
+      call_saved_registers = TYPE_PRESERVE_NONE;
+      interrupt_conflict = "preserve_none";
+    }
+  else if (lookup_attribute ("no_callee_saved_registers",
+			     TYPE_ATTRIBUTES (fntype)))
+    {
+      call_saved_registers = TYPE_NO_CALLEE_SAVED_REGISTERS;
+      interrupt_conflict = "no_callee_saved_registers";
+    }
+  else if (lookup_attribute ("no_caller_saved_registers",
+			     TYPE_ATTRIBUTES (fntype)))
+    call_saved_registers = TYPE_NO_CALLER_SAVED_REGISTERS;
+
+  if (lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fntype)))
+    {
+      if (loc && interrupt_conflict)
+	error_at (*loc, "%qs and %qs attributes are not compatible",
+		  "interrupt", interrupt_conflict);
+      return TYPE_NO_CALLER_SAVED_REGISTERS;
+    }
+
+  return call_saved_registers;
+}
 
 /* Set the func_type field from the function FNDECL.  */
 
 static void
 ix86_set_func_type (tree fndecl)
 {
+  if (cfun->machine->func_type != TYPE_UNKNOWN)
+    return;
+
+  cfun->machine->call_saved_registers
+    = ix86_fntype_call_saved_registers (TREE_TYPE (fndecl),
+					&DECL_SOURCE_LOCATION (fndecl));
+
   /* No need to save and restore callee-saved registers for a noreturn
      function with nothrow or compiled with -fno-exceptions unless when
      compiling with -O0 or -Og, except that it interferes with debugging
@@ -3287,74 +3327,37 @@  ix86_set_func_type (tree fndecl)
      function is marked with TREE_THIS_VOLATILE in the IR output, which
      leads to the incompatible attribute error in LTO1.  Ignore the
      interrupt function in this case.  */
-  enum call_saved_registers_type no_callee_saved_registers
-    = TYPE_DEFAULT_CALL_SAVED_REGISTERS;
-  if (lookup_attribute ("preserve_none",
-			     TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
-    no_callee_saved_registers = TYPE_PRESERVE_NONE;
-  else if ((lookup_attribute ("no_callee_saved_registers",
-			      TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
-	   || (ix86_noreturn_no_callee_saved_registers
-	       && TREE_THIS_VOLATILE (fndecl)
-	       && optimize
-	       && !optimize_debug
-	       && (TREE_NOTHROW (fndecl) || !flag_exceptions)
-	       && !lookup_attribute ("interrupt",
-				     TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))
-	       && !lookup_attribute ("no_caller_saved_registers",
-				 TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))))
-    no_callee_saved_registers = TYPE_NO_CALLEE_SAVED_REGISTERS;
-
-  if (cfun->machine->func_type == TYPE_UNKNOWN)
+  if (cfun->machine->call_saved_registers == TYPE_DEFAULT_CALL_SAVED_REGISTERS
+      && ix86_noreturn_no_callee_saved_registers
+      && TREE_THIS_VOLATILE (fndecl)
+      && optimize
+      && !optimize_debug
+      && (TREE_NOTHROW (fndecl) || !flag_exceptions))
+    cfun->machine->call_saved_registers = TYPE_NO_CALLEE_SAVED_REGISTERS;
+
+  if (lookup_attribute ("interrupt",
+			TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
     {
-      if (lookup_attribute ("interrupt",
-			    TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
-	{
-	  if (ix86_function_naked (fndecl))
-	    error_at (DECL_SOURCE_LOCATION (fndecl),
-		      "interrupt and naked attributes are not compatible");
-
-	  if (no_callee_saved_registers)
-	    {
-	      const char *attr;
-	      if (no_callee_saved_registers == TYPE_PRESERVE_NONE)
-		attr = "preserve_none";
-	      else
-		attr = "no_callee_saved_registers";
-	      error_at (DECL_SOURCE_LOCATION (fndecl),
-			"%qs and %qs attributes are not compatible",
-			"interrupt", attr);
-	    }
-
-	  int nargs = 0;
-	  for (tree arg = DECL_ARGUMENTS (fndecl);
-	       arg;
-	       arg = TREE_CHAIN (arg))
-	    nargs++;
-	  cfun->machine->call_saved_registers
-	    = TYPE_NO_CALLER_SAVED_REGISTERS;
-	  cfun->machine->func_type
-	    = nargs == 2 ? TYPE_EXCEPTION : TYPE_INTERRUPT;
-
-	  ix86_optimize_mode_switching[X86_DIRFLAG] = 1;
-
-	  /* Only dwarf2out.cc can handle -WORD(AP) as a pointer argument.  */
-	  if (write_symbols != NO_DEBUG && write_symbols != DWARF2_DEBUG)
-	    sorry ("only DWARF debug format is supported for interrupt "
-		   "service routine");
-	}
-      else
-	{
-	  cfun->machine->func_type = TYPE_NORMAL;
-	  if (no_callee_saved_registers)
-	    cfun->machine->call_saved_registers
-	      = no_callee_saved_registers;
-	  else if (lookup_attribute ("no_caller_saved_registers",
-				     TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
-	    cfun->machine->call_saved_registers
-	      = TYPE_NO_CALLER_SAVED_REGISTERS;
-	}
+      if (ix86_function_naked (fndecl))
+	error_at (DECL_SOURCE_LOCATION (fndecl),
+		  "interrupt and naked attributes are not compatible");
+
+      int nargs = 0;
+      for (tree arg = DECL_ARGUMENTS (fndecl);
+	   arg;
+	   arg = TREE_CHAIN (arg))
+	nargs++;
+      cfun->machine->func_type = nargs == 2 ? TYPE_EXCEPTION : TYPE_INTERRUPT;
+
+      ix86_optimize_mode_switching[X86_DIRFLAG] = 1;
+
+      /* Only dwarf2out.cc can handle -WORD(AP) as a pointer argument.  */
+      if (write_symbols != NO_DEBUG && write_symbols != DWARF2_DEBUG)
+	sorry ("only DWARF debug format is supported for interrupt "
+	       "service routine");
     }
+  else
+    cfun->machine->func_type = TYPE_NORMAL;
 }
 
 /* Set the indirect_branch_type field from the function FNDECL.  */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 65c15d0a319..bd3de588a4e 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -47,6 +47,8 @@  extern enum calling_abi ix86_function_type_abi (const_tree);
 extern bool ix86_use_pseudo_pic_reg (void);
 
 extern void ix86_reset_previous_fndecl (void);
+extern call_saved_registers_type
+  ix86_fntype_call_saved_registers (const_tree, location_t * = nullptr);
 
 extern bool ix86_using_red_zone (void);
 
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index a3919b630d3..d8a4df3a668 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -933,12 +933,10 @@  x86_64_elf_unique_section (tree decl, int reloc)
    attribute.  */
 
 bool
-ix86_type_no_callee_saved_registers_p (const_tree type)
+ix86_type_no_callee_saved_registers_p (const_tree fntype)
 {
-  return (lookup_attribute ("no_callee_saved_registers",
-			    TYPE_ATTRIBUTES (type)) != NULL
-	  || lookup_attribute ("preserve_none",
-			       TYPE_ATTRIBUTES (type)) != NULL);
+  auto type = ix86_fntype_call_saved_registers (fntype);
+  return type == TYPE_PRESERVE_NONE || type == TYPE_NO_CALLEE_SAVED_REGISTERS;
 }
 
 #ifdef COMMON_ASM_OP