https://gcc.gnu.org/g:d68cbbb3ae0010446c76dacd20b5c225e0535812
commit r17-2206-gd68cbbb3ae0010446c76dacd20b5c225e0535812 Author: Richard Sandiford <[email protected]> Date: Thu May 14 22:51:49 2026 +0100 i386: Split out call_saved_registers_type detection 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. Diff: --- 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 8689ba5c883a..da6e45f3f29b 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 d11fa2df35d7..870dcb68d2f2 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 01cab02f0d37..2e5a225574b9 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
