"H.J. Lu" <[email protected]> writes: > Implement TARGET_FNTYPE_ABI to avoid spills of callee-saved registers > when calling functions with no_caller_saved_registers attribute. > > 1. For functions with no_callee_saved_registers attribute, frame register > is preserved to mitigate PR target/114116. MMX and x87 registers aren't > clobbered if MMX and x87 aren't enabled. > 2. For functions with no_caller_saved_registers attribute, MMX and x87 > registers are clobbered since saving and restoring registers doesn't > include MMX nor x87 registers. > 3. Don't mark disabled registers as call used to avoid reg_to_stack > crashes when x87 registers are still accessed even with -mno-mmx > -mno-80387. > 4. Add ABI_ORIGINAL which is the function ABI without attributes on > the current function. > 5. Add ABI_ALTERNATE which is the alternate function ABI from ABI_DEFAULT. > If ix86_abi is SYSV_ABI, ABI_ALTERNATE is the function ABI for MS_ABI. > Otherwise, ABI_ALTERNATE is the function ABI for SYSV_ABI. > > Tested on Linux/x86-64 and with CPython 3.14.4.
Like I mentioned in the PR trail for 125266, I don't think the ix86_original_abi stuff, and the use of cfun in ix86_conditional_register_usage, is correct. Maybe the simplest thing would be for me to come up with a counterproposal, based on this patch. It might be a few days before I can give it a go though. Thanks, Richard > > gcc/ > > PR target/124798 > * config/i386/i386-expand.cc: Include "function-abi.h". > (ix86_expand_call): Add call clobbers only when callee is > no-callee-saved and caller isn't. Use callee abi to get the > list of call clobbers. > * config/i386/i386-options.cc (ix86_init_machine_status): Call > ix86_init_original_abi. > * config/i386/i386-protos.h > (ix86_type_no_callee_saved_registers_p): Removed. > (ix86_init_original_abi): New. > * config/i386/i386.cc (ix86_conditional_register_usage): Mark > all, but frame pointer, are caller-saved in no-callee-saved and > preserve_none functions. Clear disabled registers in > call_used_regs. > (ix86_type_no_callee_saved_registers_p): Make it static. > (ix86_no_callee_saved_abi): New function. > (ix86_no_caller_saved_abi_void): Likewise. > (ix86_no_caller_saved_abi_ax): Likewise. > (ix86_no_caller_saved_abi_ax_dx): Likewise. > (ix86_no_caller_saved_abi_xmm0): Likewise. > (ix86_no_caller_saved_abi_xmm0_xmm1): Likewise. > (ix86_original_abi): Likewise. > (ix86_alternate_abi): Likewise. > (ix86_init_original_abi): Likewise. > (ix86_function_abi_id): Likewise. > (ix86_fntype_abi): Likewise. > (ix86_hard_regno_call_part_clobbered): Handle newly added ABIs. > (TARGET_FNTYPE_ABI): New. > * config/i386/i386.md: Add ABI_ORIGINAL, ABI_ALTERNATE, > ABI_NO_CALLEE_SAVED, ABI_NO_CALLER_SAVED_RETURN_VOID, > ABI_NO_CALLER_SAVED_RETURN_AX, ABI_NO_CALLER_SAVED_RETURN_AX_DX, > ABI_NO_CALLER_SAVED_RETURN_XMM0 and > ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1. > > gcc/testsuite/ > > PR target/124798 > * gcc.target/i386/no-callee-saved-18.c: Don't check frame > register. > * gcc.target/i386/no-callee-saved-19b.c: Update the expected > instruction order. > * gcc.target/i386/no-callee-saved-19d.c: Likewise. > * gcc.target/i386/no-callee-saved-19e.c: Likewise. > * gcc.target/i386/no-callee-saved-2.c: Check frame register isn't > saved nor restored in 64-bit mode. > * gcc.target/i386/no-callee-saved-8.c: Expect no saving nor > restoring caller-saved registers. > * gcc.target/i386/no-callee-saved-9.c: Likewise. > * gcc.target/i386/preserve-none-14.c: Don't check frame register. > * gcc.target/i386/preserve-none-23.c: Likewise. > * gcc.target/i386/preserve-none-7.c: Check frame register isn't > saved nor restored in 64-bit mode > * gcc.target/i386/no-caller-saved-1-ms.c: New test. > * gcc.target/i386/no-caller-saved-1-sysv.c: Likewise. > * gcc.target/i386/no-caller-saved-1.c: Likewise. > * gcc.target/i386/no-caller-saved-2.c: Likewise. > * gcc.target/i386/no-caller-saved-3.c: Likewise. > * gcc.target/i386/no-caller-saved-4.c: Likewise. > * gcc.target/i386/no-caller-saved-5.c: Likewise. > * gcc.target/i386/no-caller-saved-6.c: Likewise. > * gcc.target/i386/no-caller-saved-7.c: Likewise. > * gcc.target/i386/stack-check-17.c: Also expect 1 pop in 64-bit > mode. > > > -- > H.J. > > From 8f6ebc95073e972b75796e9109ca1242f7bee94d Mon Sep 17 00:00:00 2001 > From: "H.J. Lu" <[email protected]> > Date: Tue, 14 Apr 2026 18:37:20 +0800 > Subject: [PATCH v2] x86: Implement TARGET_FNTYPE_ABI > > Implement TARGET_FNTYPE_ABI to avoid spills of callee-saved registers > when calling functions with no_caller_saved_registers attribute. > > 1. For functions with no_callee_saved_registers attribute, frame register > is preserved to mitigate PR target/114116. MMX and x87 registers aren't > clobbered if MMX and x87 aren't enabled. > 2. For functions with no_caller_saved_registers attribute, MMX and x87 > registers are clobbered since saving and restoring registers doesn't > include MMX nor x87 registers. > 3. Don't mark disabled registers as call used to avoid reg_to_stack > crashes when x87 registers are still accessed even with -mno-mmx > -mno-80387. > 4. Add ABI_ORIGINAL which is the function ABI without attributes on > the current function. > 5. Add ABI_ALTERNATE which is the alternate function ABI from ABI_DEFAULT. > If ix86_abi is SYSV_ABI, ABI_ALTERNATE is the function ABI for MS_ABI. > Otherwise, ABI_ALTERNATE is the function ABI for SYSV_ABI. > > Tested on Linux/x86-64 and with CPython 3.14.4. > > gcc/ > > PR target/124798 > * config/i386/i386-expand.cc: Include "function-abi.h". > (ix86_expand_call): Add call clobbers only when callee is > no-callee-saved and caller isn't. Use callee abi to get the > list of call clobbers. > * config/i386/i386-options.cc (ix86_init_machine_status): Call > ix86_init_original_abi. > * config/i386/i386-protos.h > (ix86_type_no_callee_saved_registers_p): Removed. > (ix86_init_original_abi): New. > * config/i386/i386.cc (ix86_conditional_register_usage): Mark > all, but frame pointer, are caller-saved in no-callee-saved and > preserve_none functions. Clear disabled registers in > call_used_regs. > (ix86_type_no_callee_saved_registers_p): Make it static. > (ix86_no_callee_saved_abi): New function. > (ix86_no_caller_saved_abi_void): Likewise. > (ix86_no_caller_saved_abi_ax): Likewise. > (ix86_no_caller_saved_abi_ax_dx): Likewise. > (ix86_no_caller_saved_abi_xmm0): Likewise. > (ix86_no_caller_saved_abi_xmm0_xmm1): Likewise. > (ix86_original_abi): Likewise. > (ix86_alternate_abi): Likewise. > (ix86_init_original_abi): Likewise. > (ix86_function_abi_id): Likewise. > (ix86_fntype_abi): Likewise. > (ix86_hard_regno_call_part_clobbered): Handle newly added ABIs. > (TARGET_FNTYPE_ABI): New. > * config/i386/i386.md: Add ABI_ORIGINAL, ABI_ALTERNATE, > ABI_NO_CALLEE_SAVED, ABI_NO_CALLER_SAVED_RETURN_VOID, > ABI_NO_CALLER_SAVED_RETURN_AX, ABI_NO_CALLER_SAVED_RETURN_AX_DX, > ABI_NO_CALLER_SAVED_RETURN_XMM0 and > ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1. > > gcc/testsuite/ > > PR target/124798 > * gcc.target/i386/no-callee-saved-18.c: Don't check frame > register. > * gcc.target/i386/no-callee-saved-19b.c: Update the expected > instruction order. > * gcc.target/i386/no-callee-saved-19d.c: Likewise. > * gcc.target/i386/no-callee-saved-19e.c: Likewise. > * gcc.target/i386/no-callee-saved-2.c: Check frame register isn't > saved nor restored in 64-bit mode. > * gcc.target/i386/no-callee-saved-8.c: Expect no saving nor > restoring caller-saved registers. > * gcc.target/i386/no-callee-saved-9.c: Likewise. > * gcc.target/i386/preserve-none-14.c: Don't check frame register. > * gcc.target/i386/preserve-none-23.c: Likewise. > * gcc.target/i386/preserve-none-7.c: Check frame register isn't > saved nor restored in 64-bit mode > * gcc.target/i386/no-caller-saved-1-ms.c: New test. > * gcc.target/i386/no-caller-saved-1-sysv.c: Likewise. > * gcc.target/i386/no-caller-saved-1.c: Likewise. > * gcc.target/i386/no-caller-saved-2.c: Likewise. > * gcc.target/i386/no-caller-saved-3.c: Likewise. > * gcc.target/i386/no-caller-saved-4.c: Likewise. > * gcc.target/i386/no-caller-saved-5.c: Likewise. > * gcc.target/i386/no-caller-saved-6.c: Likewise. > * gcc.target/i386/no-caller-saved-7.c: Likewise. > * gcc.target/i386/stack-check-17.c: Also expect 1 pop in 64-bit > mode. > > Signed-off-by: H.J. Lu <[email protected]> > --- > gcc/config/i386/i386-expand.cc | 31 +- > gcc/config/i386/i386-options.cc | 4 + > gcc/config/i386/i386-protos.h | 2 +- > gcc/config/i386/i386.cc | 393 +++++++++++++++++- > gcc/config/i386/i386.md | 30 +- > .../gcc.target/i386/no-callee-saved-18.c | 2 - > .../gcc.target/i386/no-callee-saved-19b.c | 8 +- > .../gcc.target/i386/no-callee-saved-19d.c | 6 +- > .../gcc.target/i386/no-callee-saved-19e.c | 8 +- > .../gcc.target/i386/no-callee-saved-2.c | 10 +- > .../gcc.target/i386/no-callee-saved-8.c | 8 +- > .../gcc.target/i386/no-callee-saved-9.c | 10 +- > .../gcc.target/i386/no-caller-saved-1-ms.c | 50 +++ > .../gcc.target/i386/no-caller-saved-1-sysv.c | 46 ++ > .../gcc.target/i386/no-caller-saved-1.c | 50 +++ > .../gcc.target/i386/no-caller-saved-2.c | 49 +++ > .../gcc.target/i386/no-caller-saved-3.c | 49 +++ > .../gcc.target/i386/no-caller-saved-4.c | 44 ++ > .../gcc.target/i386/no-caller-saved-5.c | 34 ++ > .../gcc.target/i386/no-caller-saved-6.c | 34 ++ > .../gcc.target/i386/no-caller-saved-7.c | 49 +++ > .../gcc.target/i386/preserve-none-14.c | 2 - > .../gcc.target/i386/preserve-none-23.c | 2 - > .../gcc.target/i386/preserve-none-7.c | 10 +- > .../gcc.target/i386/stack-check-17.c | 3 +- > 25 files changed, 860 insertions(+), 74 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-2.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-3.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-4.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-5.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-6.c > create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-7.c > > diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc > index df44a4eb99d..443eacbfe62 100644 > --- a/gcc/config/i386/i386-expand.cc > +++ b/gcc/config/i386/i386-expand.cc > @@ -94,6 +94,7 @@ along with GCC; see the file COPYING3. If not see > #include "i386-builtins.h" > #include "i386-expand.h" > #include "asan.h" > +#include "function-abi.h" > > /* Split one or more double-mode RTL references into pairs of half-mode > references. The RTL can be REG, offsettable MEM, integer constant, or > @@ -11081,7 +11082,8 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx > callarg1, > rtx use = NULL, call; > unsigned int vec_len = 0; > tree fndecl; > - bool call_no_callee_saved_registers = false; > + function_abi caller_abi = fndecl_abi (current_function_decl); > + function_abi callee_abi = caller_abi; > > if (SYMBOL_REF_P (XEXP (fnaddr, 0))) > { > @@ -11091,8 +11093,8 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx > callarg1, > if (lookup_attribute ("interrupt", > TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) > error ("interrupt service routine cannot be called directly"); > - else if (ix86_type_no_callee_saved_registers_p (TREE_TYPE (fndecl))) > - call_no_callee_saved_registers = true; > + else if (TREE_CODE (fndecl) == FUNCTION_DECL) > + callee_abi = fndecl_abi (fndecl); > if (fndecl == current_function_decl > && decl_binds_to_current_def_p (fndecl)) > cfun->machine->recursive_function = true; > @@ -11103,10 +11105,8 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx > callarg1, > if (MEM_P (fnaddr)) > { > tree mem_expr = MEM_EXPR (fnaddr); > - if (mem_expr != nullptr > - && TREE_CODE (mem_expr) == MEM_REF > - && ix86_type_no_callee_saved_registers_p (TREE_TYPE (mem_expr))) > - call_no_callee_saved_registers = true; > + if (mem_expr != nullptr && TREE_CODE (mem_expr) == MEM_REF) > + callee_abi = fntype_abi (TREE_TYPE (mem_expr)); > } > > fndecl = NULL_TREE; > @@ -11320,21 +11320,14 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx > callarg1, > clobber_reg (&use, gen_rtx_REG (DImode, R10_REG)); > } > > - if (call_no_callee_saved_registers) > + if (callee_abi.id () == ABI_NO_CALLEE_SAVED > + && caller_abi.id () != ABI_NO_CALLEE_SAVED) > { > - /* After calling a no_callee_saved_registers function, all > - registers may be clobbered. Clobber all registers that are > - not used by the callee. */ > - bool is_64bit_ms_abi = (TARGET_64BIT > - && ix86_function_abi (fndecl) == MS_ABI); > - char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi); > for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > - if (!fixed_regs[i] > + if (GENERAL_REGNO_P (i) > + && TEST_HARD_REG_BIT (accessible_reg_set, i) > && i != HARD_FRAME_POINTER_REGNUM > - && !(ix86_call_used_regs[i] == 1 > - || (ix86_call_used_regs[i] & c_mask)) > - && !STACK_REGNO_P (i) > - && !MMX_REGNO_P (i)) > + && callee_abi.clobbers_at_least_part_of_reg_p (i)) > clobber_reg (&use, > gen_rtx_REG (GET_MODE (regno_reg_rtx[i]), i)); > } > diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc > index 7ffe9cd2a38..890b36835dd 100644 > --- a/gcc/config/i386/i386-options.cc > +++ b/gcc/config/i386/i386-options.cc > @@ -2004,6 +2004,10 @@ ix86_init_machine_status (void) > f->stack_frame_required = true; > f->silent_p = true; > > + /* NB: Call ix86_init_original_abi to make a copy of the function ABI > + without attributes on the current function. */ > + ix86_init_original_abi (); > + > return f; > } > > diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h > index 4ba4fb08556..1664a1a06a3 100644 > --- a/gcc/config/i386/i386-protos.h > +++ b/gcc/config/i386/i386-protos.h > @@ -283,10 +283,10 @@ extern tree ix86_valid_target_attribute_tree (tree, > tree, > struct gcc_options *, > struct gcc_options *, bool); > extern unsigned int ix86_get_callcvt (const_tree); > -extern bool ix86_type_no_callee_saved_registers_p (const_tree); > > #endif > > +extern void ix86_init_original_abi (void); > extern rtx ix86_tls_module_base (void); > extern bool ix86_gpr_tls_address_pattern_p (rtx); > extern bool ix86_tls_address_pattern_p (rtx); > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc > index 2744c749578..ab30d03e998 100644 > --- a/gcc/config/i386/i386.cc > +++ b/gcc/config/i386/i386.cc > @@ -503,16 +503,33 @@ ix86_conditional_register_usage (void) > { > int i, c_mask; > > - /* If there are no caller-saved registers, preserve all registers. > - except fixed_regs and registers used for function return value > - since aggregate_value_p checks call_used_regs[regno] on return > - value. */ > - if (cfun > - && (cfun->machine->call_saved_registers > - == TYPE_NO_CALLER_SAVED_REGISTERS)) > - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) > - if (!fixed_regs[i] && !ix86_function_value_regno_p (i)) > - call_used_regs[i] = 0; > + if (cfun) > + switch (cfun->machine->call_saved_registers) > + { > + case TYPE_DEFAULT_CALL_SAVED_REGISTERS: > + break; > + > + case TYPE_NO_CALLER_SAVED_REGISTERS: > + /* If there are no caller-saved registers, preserve all > + registers. except fixed_regs and registers used for > + function return value since aggregate_value_p checks > + call_used_regs[regno] on return value. */ > + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (!fixed_regs[i] && !ix86_function_value_regno_p (i)) > + call_used_regs[i] = 0; > + break; > + > + case TYPE_NO_CALLEE_SAVED_REGISTERS: > + case TYPE_PRESERVE_NONE: > + /* All, but frame pointer, are caller-saved. */ > + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (GENERAL_REGNO_P (i) > + || SSE_REGNO_P (i) > + || MASK_REGNO_P (i)) > + call_used_regs[i] = 1; > + call_used_regs[BP_REG] = 0; > + break; > + } > > /* For 32-bit targets, disable the REX registers. */ > if (! TARGET_64BIT) > @@ -571,6 +588,13 @@ ix86_conditional_register_usage (void) > for (i = FIRST_REX2_INT_REG; i <= LAST_REX2_INT_REG; i++) > CLEAR_HARD_REG_BIT (accessible_reg_set, i); > } > + > + /* If a register is disabled, it can't be used for call. This avoids > + reg_to_stack crashes when x87 registers are still accessed even > + with -mno-mmx -mno-80387. */ > + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (!TEST_HARD_REG_BIT (accessible_reg_set, i)) > + call_used_regs[i] = 0; > } > > /* Canonicalize a comparison from one we don't have to one we do have. */ > @@ -932,7 +956,7 @@ x86_64_elf_unique_section (tree decl, int reloc) > /* Return true if TYPE has no_callee_saved_registers or preserve_none > attribute. */ > > -bool > +static bool > ix86_type_no_callee_saved_registers_p (const_tree type) > { > return (lookup_attribute ("no_callee_saved_registers", > @@ -21854,6 +21878,307 @@ ix86_hard_regno_mode_ok (unsigned int regno, > machine_mode mode) > return false; > } > > +/* Return the descriptor of no_callee_saved_registers function type. > + None of registers are preserved, except for frame register to > + mitigate PR target/114116. MMX and x87 registers are preserved > + if MMX and x87 aren't enabled. */ > + > +static const predefined_function_abi & > +ix86_no_callee_saved_abi (void) > +{ > + auto &no_callee_saved_abi = function_abis[ABI_NO_CALLEE_SAVED]; > + if (!no_callee_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = reg_class_contents[ALL_REGS]; > + CLEAR_HARD_REG_BIT (full_reg_clobbers, HARD_FRAME_POINTER_REGNUM); > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if ((!TARGET_80387 && STACK_REGNO_P (i)) > + || (!TARGET_MMX && MMX_REGNO_P (i))) > + CLEAR_HARD_REG_BIT (full_reg_clobbers, i); > + no_callee_saved_abi.initialize (ABI_NO_CALLEE_SAVED, > + full_reg_clobbers); > + } > + return no_callee_saved_abi; > +} > + > +/* Return the descriptor of no_caller_saved_registers function type. > + All registers are preserved, except for MMX and x87 registers > + which aren't supported when saving and restoring registers. */ > + > +static const predefined_function_abi & > +ix86_no_caller_saved_abi_void (void) > +{ > + auto &no_caller_saved_abi > + = function_abis[ABI_NO_CALLER_SAVED_RETURN_VOID]; > + if (!no_caller_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if ((TARGET_80387 && STACK_REGNO_P (i)) > + || (TARGET_MMX && MMX_REGNO_P (i))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + no_caller_saved_abi.initialize > + (ABI_NO_CALLER_SAVED_RETURN_VOID, full_reg_clobbers); > + } > + return no_caller_saved_abi; > +} > + > +/* Return the descriptor of no_caller_saved_registers function type. > + All registers are preserved, except for AX used for return value, > + MMX and x87 registers which aren't supported when saving and > + restoring registers. */ > + > +static const predefined_function_abi & > +ix86_no_caller_saved_abi_ax (void) > +{ > + auto &no_caller_saved_abi > + = function_abis[ABI_NO_CALLER_SAVED_RETURN_AX]; > + if (!no_caller_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (i == AX_REG > + || (TARGET_80387 && STACK_REGNO_P (i)) > + || (TARGET_MMX && MMX_REGNO_P (i))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + no_caller_saved_abi.initialize > + (ABI_NO_CALLER_SAVED_RETURN_AX, full_reg_clobbers); > + } > + return no_caller_saved_abi; > +} > + > +/* Return the descriptor of no_caller_saved_registers function type. > + All registers are preserved, except for AX/DX used for return value, > + MMX and x87 registers which aren't supported when saving and > + restoring registers. */ > + > +static const predefined_function_abi & > +ix86_no_caller_saved_abi_ax_dx (void) > +{ > + auto &no_caller_saved_abi > + = function_abis[ABI_NO_CALLER_SAVED_RETURN_AX_DX]; > + if (!no_caller_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (i == AX_REG > + || i == DX_REG > + || (TARGET_80387 && STACK_REGNO_P (i)) > + || (TARGET_MMX && MMX_REGNO_P (i))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + no_caller_saved_abi.initialize > + (ABI_NO_CALLER_SAVED_RETURN_AX_DX, full_reg_clobbers); > + } > + return no_caller_saved_abi; > +} > + > +/* Return the descriptor of no_caller_saved_registers function type. > + All registers are preserved, except for XMM0 used for return value, > + MMX and x87 registers which aren't supported when saving and > + restoring registers. */ > + > +static const predefined_function_abi & > +ix86_no_caller_saved_abi_xmm0 (void) > +{ > + auto &no_caller_saved_abi > + = function_abis[ABI_NO_CALLER_SAVED_RETURN_XMM0]; > + if (!no_caller_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (i == XMM0_REG > + || (TARGET_80387 && STACK_REGNO_P (i)) > + || (TARGET_MMX && MMX_REGNO_P (i))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + no_caller_saved_abi.initialize > + (ABI_NO_CALLER_SAVED_RETURN_XMM0, full_reg_clobbers); > + } > + return no_caller_saved_abi; > +} > + > +/* Return the descriptor of no_caller_saved_registers function type. > + All registers are preserved, except for XMM0/XMM1 used for return > + value, MMX and x87 registers which aren't supported when saving and > + restoring registers. */ > + > +static const predefined_function_abi & > +ix86_no_caller_saved_abi_xmm0_xmm1 (void) > +{ > + auto &no_caller_saved_abi > + = function_abis[ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1]; > + if (!no_caller_saved_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (i == XMM0_REG > + || i == XMM1_REG > + || (TARGET_80387 && STACK_REGNO_P (i)) > + || (TARGET_MMX && MMX_REGNO_P (i))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + no_caller_saved_abi.initialize > + (ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1, full_reg_clobbers); > + } > + return no_caller_saved_abi; > +} > + > +/* Return the descriptor of the function ABI type without attributes > + on the current function. */ > + > +static const predefined_function_abi & > +ix86_original_abi (void) > +{ > + auto &original_abi = function_abis[ABI_ORIGINAL]; > + if (!original_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers > + = default_function_abi.full_reg_clobbers (); > + original_abi.initialize (ABI_ORIGINAL, full_reg_clobbers); > + } > + return original_abi; > +} > + > +/* Return the descriptor of the function alternate ABI type. */ > + > +static const predefined_function_abi & > +ix86_alternate_abi (void) > +{ > + static const char ix86_call_used_regs[] = CALL_USED_REGISTERS; > + auto &alternate_abi = function_abis[ABI_ALTERNATE]; > + if (!alternate_abi.initialized_p ()) > + { > + HARD_REG_SET full_reg_clobbers = {}; > + > + /* Add all registers that are clobbered by the call. NB: If the > + current ABI is SYSV_ABI, the alternate ABI is MS_ABI. */ > + bool is_64bit_ms_abi = TARGET_64BIT && ix86_abi == SYSV_ABI; > + char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi); > + for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++) > + if (!fixed_regs[i] > + && (ix86_call_used_regs[i] == 1 > + || (ix86_call_used_regs[i] & c_mask))) > + SET_HARD_REG_BIT (full_reg_clobbers, i); > + alternate_abi.initialize (ABI_ORIGINAL, full_reg_clobbers); > + } > + return alternate_abi; > +} > + > +/* Make ABI_ORIGINAL a copy of the function ABI without attributes on > + the current function. */ > + > +void > +ix86_init_original_abi (void) > +{ > + gcc_assert (default_function_abi.initialized_p ()); > + ix86_original_abi (); > +} > + > +/* Return the function ABI ID based on FNTYPE. */ > + > +static int > +ix86_function_abi_id (const_tree fntype) > +{ > + if (ix86_type_no_callee_saved_registers_p (fntype)) > + return ABI_NO_CALLEE_SAVED; > + > + if (lookup_attribute ("no_caller_saved_registers", > + TYPE_ATTRIBUTES (fntype))) > + { > + tree type = TREE_TYPE (fntype); > + if (VOID_TYPE_P (type)) > + return ABI_NO_CALLER_SAVED_RETURN_VOID; > + /* AX register contains the address of the return value location > + passed in by the caller. */ > + else if (ix86_return_in_memory (type, fntype)) > + return ABI_NO_CALLER_SAVED_RETURN_AX; > + rtx ret = ix86_function_value (type, fntype, false); > + unsigned int nregs; > + if (REG_P (ret)) > + { > + unsigned int regno = REGNO (ret); > + if (STACK_REGNO_P (regno) || MMX_REGNO_P (regno)) > + return ABI_NO_CALLER_SAVED_RETURN_VOID; > + else > + switch (regno) > + { > + case AX_REG: > + nregs = REG_NREGS (ret); > + if (nregs == 1) > + return ABI_NO_CALLER_SAVED_RETURN_AX; > + else if (nregs == 2) > + return ABI_NO_CALLER_SAVED_RETURN_AX_DX; > + break; > + case XMM0_REG: > + return ABI_NO_CALLER_SAVED_RETURN_XMM0; > + default: > + gcc_unreachable (); > + } > + } > + else if (GET_CODE (ret) == PARALLEL && XVECLEN (ret, 0) == 2) > + { > + rtx x0 = XVECEXP (ret, 0, 0); > + rtx x1 = XVECEXP (ret, 0, 1); > + if (GET_CODE (x0) == EXPR_LIST > + && GET_CODE (x1) == EXPR_LIST) > + { > + x0 = XEXP (x0, 0); > + x1 = XEXP (x1, 0); > + if (REG_P (x0) > + && REGNO (x0) == XMM0_REG > + && REG_P (x1) > + && REGNO (x1) == XMM1_REG) > + return ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1; > + } > + > + gcc_unreachable (); > + } > + } > + > + /* NB: This must be the last since other attributes change the > + function ABI. */ > + if (ix86_function_type_abi (fntype) != ix86_abi) > + return ABI_ALTERNATE; > + > + return ABI_ORIGINAL; > +} > + > +/* Implement TARGET_FNTYPE_ABI. */ > + > +static const predefined_function_abi & > +ix86_fntype_abi (const_tree fntype) > +{ > + switch (ix86_function_abi_id (fntype)) > + { > + case ABI_ORIGINAL: > + return ix86_original_abi (); > + > + case ABI_ALTERNATE: > + return ix86_alternate_abi (); > + > + case ABI_NO_CALLEE_SAVED: > + return ix86_no_callee_saved_abi (); > + > + case ABI_NO_CALLER_SAVED_RETURN_VOID: > + return ix86_no_caller_saved_abi_void (); > + > + case ABI_NO_CALLER_SAVED_RETURN_AX: > + return ix86_no_caller_saved_abi_ax (); > + > + case ABI_NO_CALLER_SAVED_RETURN_AX_DX: > + return ix86_no_caller_saved_abi_ax_dx (); > + > + case ABI_NO_CALLER_SAVED_RETURN_XMM0: > + return ix86_no_caller_saved_abi_xmm0 (); > + > + case ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1: > + return ix86_no_caller_saved_abi_xmm0_xmm1 (); > + > + default: > + gcc_unreachable (); > + } > + > + return default_function_abi; > +} > + > /* Implement TARGET_INSN_CALLEE_ABI. */ > > const predefined_function_abi & > @@ -21904,12 +22229,51 @@ static bool > ix86_hard_regno_call_part_clobbered (unsigned int abi_id, unsigned int regno, > machine_mode mode) > { > - /* Special ABI for vzeroupper which only clobber higher part of sse regs. > */ > - if (abi_id == ABI_VZEROUPPER) > + if (abi_id == ABI_DEFAULT) > + { > + /* Get the ABI ID from the current function. */ > + if (cfun) > + abi_id = ix86_function_abi_id (TREE_TYPE (cfun->decl)); > + else > + abi_id = ABI_ORIGINAL; > + } > + > + switch (abi_id) > + { > + case ABI_VZEROUPPER: > + /* Special ABI for vzeroupper which only clobbers higher part of > + SSE registers. */ > return (GET_MODE_SIZE (mode) > 16 > && ((TARGET_64BIT && REX_SSE_REGNO_P (regno)) > || LEGACY_SSE_REGNO_P (regno))); > > + case ABI_ORIGINAL: > + case ABI_ALTERNATE: > + case ABI_NO_CALLEE_SAVED: > + break; > + > + case ABI_NO_CALLER_SAVED_RETURN_VOID: > + case ABI_NO_CALLER_SAVED_RETURN_AX: > + case ABI_NO_CALLER_SAVED_RETURN_AX_DX: > + /* These ABIs don't clobber SSE registers. */ > + return false; > + > + case ABI_NO_CALLER_SAVED_RETURN_XMM0: > + /* This ABI only clobbers XMM0. */ > + if (regno != XMM0_REG) > + return false; > + break; > + > + case ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1: > + /* This ABI only clobbers XMM0 and XMM1. */ > + if (regno != XMM0_REG && regno != XMM1_REG) > + return false; > + break; > + > + default: > + gcc_unreachable (); > + } > + > return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16; > } > > @@ -28786,6 +29150,9 @@ ix86_libgcc_floating_mode_supported_p > #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \ > ix86_hard_regno_call_part_clobbered > > +#undef TARGET_FNTYPE_ABI > +#define TARGET_FNTYPE_ABI ix86_fntype_abi > + > #undef TARGET_INSN_CALLEE_ABI > #define TARGET_INSN_CALLEE_ABI ix86_insn_callee_abi > > diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md > index b4e397bc925..3ac7aca9461 100644 > --- a/gcc/config/i386/i386.md > +++ b/gcc/config/i386/i386.md > @@ -511,11 +511,33 @@ (define_constants > (FIRST_PSEUDO_REG 92) > ]) > > -;; Insn callee abi index. > +;; Insn callee abi index. ABI_DEFAULT is the funtion ABI for the > +;; current function. ABI_ORIGINAL is the function ABI without > +;; attributes on the current function. ABI_ALTERNATE is the Windows > +;; function ABI if ix86_abi == SYSV_ABI and is the SYSV function ABI > +;; if ix86_abi == MS_ABI. > (define_constants > - [(ABI_DEFAULT 0) > - (ABI_VZEROUPPER 1) > - (ABI_UNKNOWN 2)]) > + [(ABI_DEFAULT 0) > + (ABI_VZEROUPPER 1) > + (ABI_ORIGINAL 2) > + (ABI_ALTERNATE 3) > + (ABI_NO_CALLEE_SAVED 4) > + ;; Return void. > + (ABI_NO_CALLER_SAVED_RETURN_VOID 5) > + ;; Return char, short, int in 32-bit/64-bit. > + ;; Return int64 and _Complex int in 64-bit. > + ;; Return _Complex float in MS 32-bit/64-bit. > + (ABI_NO_CALLER_SAVED_RETURN_AX 6) > + ;; Return int64 and _Complex int in 32-bit. > + ;; Return _Complex int64 in 64-bit. > + (ABI_NO_CALLER_SAVED_RETURN_AX_DX 7) > + ;; Return float and double in 64-bit. > + ;; Return _Complex float in SYSV 64-bit. > + ;; Return int28, _Complex double in MS 64-bit. > + (ABI_NO_CALLER_SAVED_RETURN_XMM0 8) > + ;; Return _Complex double in SYSV 64-bit. > + (ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1 9) > + (ABI_UNKNOWN 10)]) > > ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls > ;; from i386.cc. > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-18.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-18.c > index 128b9c46e8e..5e228753d8a 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-18.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-18.c > @@ -19,7 +19,6 @@ foo (uintptr_t p) > /* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } > */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%esi" 1 { target ia32 } > } } */ > /* { dg-final { scan-assembler-not "pushq\[\\t \]*%rsi" { target { ! ia32 } > } } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 { target ia32 } > } } */ > @@ -36,7 +35,6 @@ foo (uintptr_t p) > /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%esi" 1 { target ia32 } } > } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%rsi" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 { target ia32 } } > } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c > index dc38936a61a..d784065b456 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c > @@ -52,15 +52,15 @@ > ** .cfi_startproc > ** subl \$376, %esp > **... > +** movq %rdi, 296\(%rsp\) > +**... > +** movl \$code\+4, %edi > +** movq %rbp, 304\(%rsp\) > ** movq %rax, 256\(%rsp\) > ** movq %rdx, 264\(%rsp\) > ** movq %rcx, 272\(%rsp\) > ** movq %rbx, 280\(%rsp\) > ** movq %rsi, 288\(%rsp\) > -** movq %rdi, 296\(%rsp\) > -**... > -** movl \$code\+4, %edi > -** movq %rbp, 304\(%rsp\) > ** movq %r8, 312\(%rsp\) > ** movq %r9, 320\(%rsp\) > ** movq %r10, 328\(%rsp\) > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c > index 4657e170350..bb9dce13350 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c > @@ -50,14 +50,14 @@ > ** .cfi_startproc > ** subq \$504, %rsp > **... > +** movq %rdi, 304\(%rsp\) > +**... > +** movl \$code\+8, %edi > ** movq %rax, 264\(%rsp\) > ** movq %rdx, 272\(%rsp\) > ** movq %rcx, 280\(%rsp\) > ** movq %rbx, 288\(%rsp\) > ** movq %rsi, 296\(%rsp\) > -** movq %rdi, 304\(%rsp\) > -**... > -** movl \$code\+8, %edi > ** movq %r8, 312\(%rsp\) > ** movq %r9, 320\(%rsp\) > ** movq %r10, 328\(%rsp\) > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c > index 8e0bbe82eae..617bb755f85 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c > @@ -52,15 +52,15 @@ > ** .cfi_startproc > ** subl \$504, %esp > **... > +** movq %rdi, 296\(%rsp\) > +**... > +** movl \$code\+4, %edi > +** movq %rbp, 304\(%rsp\) > ** movq %rax, 256\(%rsp\) > ** movq %rdx, 264\(%rsp\) > ** movq %rcx, 272\(%rsp\) > ** movq %rbx, 280\(%rsp\) > ** movq %rsi, 288\(%rsp\) > -** movq %rdi, 296\(%rsp\) > -**... > -** movl \$code\+4, %edi > -** movq %rbp, 304\(%rsp\) > ** movq %r8, 312\(%rsp\) > ** movq %r9, 320\(%rsp\) > ** movq %r10, 328\(%rsp\) > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c > index e074ca51df4..86864ea9bff 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-2.c > @@ -26,7 +26,9 @@ foo (void *frame) > } > } > > -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } > */ > -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ > -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 } } */ > -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 } } */ > +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { > target ia32 } } } */ > +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { > target ia32 } } } */ > +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 { target ia32 > } } } */ > +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 { target ia32 } > } } */ > +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*" { target { ! ia32 > } } } } */ > +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*" { target { ! ia32 } > } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-8.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-8.c > index ed3d96bdca0..692166c98e9 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-8.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-8.c > @@ -44,7 +44,7 @@ foo (void) > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r9" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r10" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r11" { target { ! ia32 } } > } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r12" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r13" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r14" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r15" 1 { target { ! ia32 > } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r12" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r13" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r14" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r15" 1 { target { ! > ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-9.c > b/gcc/testsuite/gcc.target/i386/no-callee-saved-9.c > index 7730c5903d4..7acaff2ad35 100644 > --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-9.c > +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-9.c > @@ -17,7 +17,6 @@ foo (fn_t bar) > /* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } > */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%esi" 1 { target ia32 } > } } */ > /* { dg-final { scan-assembler-not "pushq\[\\t \]*%rsi" { target { ! ia32 } > } } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 { target ia32 } > } } */ > @@ -34,7 +33,6 @@ foo (fn_t bar) > /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%esi" 1 { target ia32 } } > } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%rsi" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 { target ia32 } } > } */ > @@ -43,7 +41,7 @@ foo (fn_t bar) > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r9" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r10" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%r11" { target { ! ia32 } } > } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r12" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r13" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r14" 1 { target { ! ia32 > } } } } */ > -/* { dg-final { scan-assembler-times "popq\[\\t \]*%r15" 1 { target { ! ia32 > } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r12" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r13" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r14" 1 { target { ! > ia32 } } } } */ > +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r15" 1 { target { ! > ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c > new file mode 100644 > index 00000000000..9a834d49870 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c > @@ -0,0 +1,50 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-mabi=sysv -O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +extern void foo (void) __attribute__ ((no_caller_saved_registers, ms_abi)); > + > +void > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n), "=r" (o), "=r" (p)); > +#endif > + foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n), "r" (o), "r" (p)); > +#endif > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r12d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r13d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r14d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r15d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r12d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r13d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r14d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r15d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c > new file mode 100644 > index 00000000000..4bd3eecfcc6 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c > @@ -0,0 +1,46 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-mabi=ms -O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +extern void foo (void) __attribute__ ((no_caller_saved_registers, sysv_abi)); > + > +void > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n), "=r" (o), "=r" (p)); > +#endif > + foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n), "r" (o), "r" (p)); > +#endif > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r12d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r13d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r14d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r15d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r12d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r13d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r14d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r15d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-1.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-1.c > new file mode 100644 > index 00000000000..fc8ab95c7e8 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-1.c > @@ -0,0 +1,50 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern void foo (void); > + > +void > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n), "=r" (o), "=r" (p)); > +#endif > + foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n), "r" (o), "r" (p)); > +#endif > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r12d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r13d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r14d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r15d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r12d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r13d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r14d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r15d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-2.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-2.c > new file mode 100644 > index 00000000000..47b671dfa40 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-2.c > @@ -0,0 +1,49 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern int foo (void); > + > +int > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n), "=r" (o), "=r" (p)); > +#endif > + int ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n), "r" (o), "r" (p)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r12d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r13d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r14d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r15d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r12d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r13d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r15d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-3.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-3.c > new file mode 100644 > index 00000000000..990b870c323 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-3.c > @@ -0,0 +1,49 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern long long foo (void); > + > +long long > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n), "=r" (o), "=r" (p)); > +#endif > + long long ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7 %8 %9" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n), "r" (o), "r" (p)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r12d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r13d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r14d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r15d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r12d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r13d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r15d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-4.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-4.c > new file mode 100644 > index 00000000000..9f6b494bdb7 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-4.c > @@ -0,0 +1,44 @@ > +/* PR target/124798 */ > +/* { dg-do compile { target int128 } } */ > +/* { dg-options "-O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern __int128 foo (void); > + > +__int128 > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j, k, l, m, n; > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j), "=r" (k), "=r" (l), > "=r" (m), "=r" (n)); > +#endif > + __int128 ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : : "r" (g), "r" (h), "r" (i), "r" (j), "r" (k), "r" (l), "r" > (m), "r" (n)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-5.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-5.c > new file mode 100644 > index 00000000000..98f58fe92f5 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-5.c > @@ -0,0 +1,34 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 -msse2 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern float foo (void); > + > +float > +qux (void) > +{ > + float a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=v" (a), "=v" (b), "=v" (c), "=v" (d), "=v" (e), "=v" (f)); > +#ifdef __x86_64__ > + float g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1" > + : "=v" (g), "=v" (h)); > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : "=v" (i), "=v" (j), "=v" (k), "=v" (l), "=v" (m), "=v" (n), > "=v" (o), "=v" (p)); > +#endif > + float ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "v" (a), "v" (b), "v" (c), "v" (d), "v" (e), "v" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1" > + :: "v" (g), "v" (h)); > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : : "v" (i), "v" (j), "v" (k), "v" (l), "v" (m), "v" (n), "v" > (o), "v" (p)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "movss\[ \\t\]+%xmm\[0-9\]+, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %xmm\[0-9\]+" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-6.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-6.c > new file mode 100644 > index 00000000000..5eb5b102843 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-6.c > @@ -0,0 +1,34 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 -msse2 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +[[gnu::no_caller_saved_registers]] extern _Complex double foo (void); > + > +_Complex double > +qux (void) > +{ > + double a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=v" (a), "=v" (b), "=v" (c), "=v" (d), "=v" (e), "=v" (f)); > +#ifdef __x86_64__ > + double g, h, i, j, k, l, m, n, o, p; > + asm volatile ("# %0 %1" > + : "=v" (g), "=v" (h)); > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : "=v" (i), "=v" (j), "=v" (k), "=v" (l), "=v" (m), "=v" (n), > "=v" (o), "=v" (p)); > +#endif > + _Complex double ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "v" (a), "v" (b), "v" (c), "v" (d), "v" (e), "v" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1" > + :: "v" (g), "v" (h)); > + asm volatile ("# %0 %1 %2 %3 %4 %5 %6 %7" > + : : "v" (i), "v" (j), "v" (k), "v" (l), "v" (m), "v" (n), "v" > (o), "v" (p)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "movss\[ \\t\]+%xmm\[0-9\]+, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %xmm\[0-9\]+" } } */ > diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-7.c > b/gcc/testsuite/gcc.target/i386/no-caller-saved-7.c > new file mode 100644 > index 00000000000..c8a99e950da > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-7.c > @@ -0,0 +1,49 @@ > +/* PR target/124798 */ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -mtune=corei7 > -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } > */ > + > +typedef struct > +{ > + double d[16]; > +} record; > + > +[[gnu::no_caller_saved_registers]] extern record foo (void); > + > +record > +qux (void) > +{ > + int a, b, c, d, e, f; > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + : "=r" (a), "=r" (b), "=r" (c), "=r" (d), "=r" (e), "=r" (f)); > +#ifdef __x86_64__ > + int g, h, i, j; > + asm volatile ("# %0 %1 %2 %3" > + : "=r" (g), "=r" (h), "=r" (i), "=r" (j)); > +#endif > + record ret = foo (); > + asm volatile ("# %0 %1 %2 %3 %4 %5" > + :: "r" (a), "r" (b), "r" (c), "r" (d), "r" (e), "r" (f)); > +#ifdef __x86_64__ > + asm volatile ("# %0 %1 %2 %3" > + :: "r" (g), "r" (h), "r" (i), "r" (j)); > +#endif > + > + return ret; > +} > + > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%ecx, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%esi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%edi, > \[0-9\]*\\(%\[re\]?sp\\)" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %ecx" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %esi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %edi" } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r8d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r9d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r10d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ \\t\]+%r11d, > \[0-9\]*\\(%\[re\]?sp\\)" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r8d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r9d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r10d" { target { ! ia32 } } } } */ > +/* { dg-final { scan-assembler-not "mov(l|q)\[ > \\t\]+\[0-9\]*\\(%\[re\]?sp\\), %r11d" { target { ! ia32 } } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-14.c > b/gcc/testsuite/gcc.target/i386/preserve-none-14.c > index ca23b586fa1..175eb25acd6 100644 > --- a/gcc/testsuite/gcc.target/i386/preserve-none-14.c > +++ b/gcc/testsuite/gcc.target/i386/preserve-none-14.c > @@ -17,7 +17,6 @@ foo (fn_t bar) > /* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } > */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%esi" 1 { target ia32 } > } } */ > /* { dg-final { scan-assembler-not "pushq\[\\t \]*%rsi" { target { ! ia32 } > } } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 { target ia32 } > } } */ > @@ -34,7 +33,6 @@ foo (fn_t bar) > /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%esi" 1 { target ia32 } } > } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%rsi" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 { target ia32 } } > } */ > diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-23.c > b/gcc/testsuite/gcc.target/i386/preserve-none-23.c > index 8e83879443f..629bd695374 100644 > --- a/gcc/testsuite/gcc.target/i386/preserve-none-23.c > +++ b/gcc/testsuite/gcc.target/i386/preserve-none-23.c > @@ -19,7 +19,6 @@ foo (uintptr_t p) > /* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } > */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%esi" 1 { target ia32 } > } } */ > /* { dg-final { scan-assembler-not "pushq\[\\t \]*%rsi" { target { ! ia32 } > } } } */ > /* { dg-final { scan-assembler-times "pushl\[\\t \]*%edi" 1 { target ia32 } > } } */ > @@ -36,7 +35,6 @@ foo (uintptr_t p) > /* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)cx" } } */ > /* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)dx" } } */ > -/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)bp" } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%esi" 1 { target ia32 } } > } */ > /* { dg-final { scan-assembler-not "popq\[\\t \]*%rsi" { target { ! ia32 } } > } } */ > /* { dg-final { scan-assembler-times "popl\[\\t \]*%edi" 1 { target ia32 } } > } */ > diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-7.c > b/gcc/testsuite/gcc.target/i386/preserve-none-7.c > index 2c80560887c..6f252ee50a4 100644 > --- a/gcc/testsuite/gcc.target/i386/preserve-none-7.c > +++ b/gcc/testsuite/gcc.target/i386/preserve-none-7.c > @@ -26,7 +26,9 @@ foo (void *frame) > } > } > > -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } > */ > -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ > -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 } } */ > -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 } } */ > +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { > target ia32 } } } */ > +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { > target ia32 } } } */ > +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 { target ia32 > } } } */ > +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 { target ia32 } > } } */ > +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*" { target { ! ia32 > } } } } */ > +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*" { target { ! ia32 } > } } } */ > diff --git a/gcc/testsuite/gcc.target/i386/stack-check-17.c > b/gcc/testsuite/gcc.target/i386/stack-check-17.c > index 924a459c4e2..ed2f341b106 100644 > --- a/gcc/testsuite/gcc.target/i386/stack-check-17.c > +++ b/gcc/testsuite/gcc.target/i386/stack-check-17.c > @@ -32,5 +32,4 @@ f3 (void) > register on ia32 for a noreturn function. */ > /* { dg-final { scan-assembler-times "push\[ql\]" 1 { target { ! ia32 } } } > } */ > /* { dg-final { scan-assembler-times "push\[ql\]" 3 { target ia32 } } } */ > -/* { dg-final { scan-assembler-not "pop" { target { ! ia32 } } } } */ > -/* { dg-final { scan-assembler-times "pop" 1 { target ia32 } } } */ > +/* { dg-final { scan-assembler-times "pop\[ql\]" 1 } } */
