On Wed, May 13, 2026 at 7:11 PM Richard Sandiford
<[email protected]> wrote:
>
> "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.  I appreciate it.

> 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 } }  */



-- 
H.J.

Reply via email to