From: Richard Sandiford <[email protected]>
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(-)
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index f7282dbe36f..626e1eab929 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3267,13 +3267,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
@@ -3289,74 +3329,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 10bb1e421e9..7dac3ed8e6c 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 8cd6701ca4f..4c8b7840fc3 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
--
2.54.0