Implement TARGET_FNTYPE_ABI to avoid spills of callee-saved registers
when calling functions with no_caller_saved_registers attribute.

After

commit 754c6600fe058f1026098fde57860bbc38cc28fe
Author: Richard Sandiford <[email protected]>
Date:   Wed Jun 3 13:11:17 2026 +0100

    Add CALL_INSN_ABI_ID

there is no need for ix86_expand_call to add clobbers for when one ABI
calls another ABI.

ABI_ALTERNATE is the alternate function ABI from the system ABI.  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.

This target hook also properly marks the implicit __tls_get_addr call:

(call_insn/u 9 8 10 (parallel [
            (set (reg:DI 0 ax)
                (call:DI (mem:QI (symbol_ref:DI ("__tls_get_addr")) [0  S1 A8])
                    (const_int 0 [0])))
            (unspec:DI [
                    (reg/f:DI 7 sp)
                ] UNSPEC_TLS_LD_BASE)
            (clobber (reg:DI 5 di))
        ]) "x.c":7:16 -1
     (expr_list:REG_EH_REGION (const_int -2147483648 [0xffffffff80000000])
        (nil))
    (nil) 0)

with ABI_DEFAULT function ABI.

Tested on Linux/x86-64 and with CPython 3.14.4.

gcc/

        PR target/124798
        PR target/125436
        * config/i386/i386-expand.cc: Include "function-abi.h".
        (x86_64_ms_sysv_extra_clobbered_registers): Removed.
        (ix86_expand_call): Don't add explicit call and ABI-switch
        clobbers.
        * config/i386/i386-features.cc (ix86_place_single_tls_call):
        Set CALL_INSN_ABI_ID on TLS calls.
        * config/i386/i386-options.cc (ix86_set_current_function): Don't
        call reinit_regs.
        * config/i386/i386-protos.h
        (ix86_type_no_callee_saved_registers_p): Removed.
        (ix86_tls_get_addr_abi): New.
        * config/i386/i386.cc (ix86_alternate_abi): New prototype.
        (ix86_conditional_register_usage): Changed to describe the
        system ABI.
        (ix86_type_no_callee_saved_registers_p): Make it static.
        (ix86_function_value_regno_p): Replace ix86_cfun_abi () with
        ix86_abi.
        (ix86_save_reg): Only check TYPE_NO_CALLEE_SAVED_REGISTERS as
        a special case.
        (ix86_tls_get_addr_abi): New.
        (legitimize_tls_address): Set CALL_INSN_ABI_ID on TLS calls.
        Call ix86_alternate_abi to initialize the alternate function ABI.
        (ix86_initialize_abi): New function.
        (ix86_no_callee_saved_abi): Likewise.
        (ix86_no_caller_saved_abi): Likewise.
        (ix86_standard_abi): Likewise.
        (ix86_alternate_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_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
        PR target/125436
        * gcc.target/i386/abi-mix-1.c: New test.
        * gcc.target/i386/abi-mix-2.c: Likewise.
        * gcc.target/i386/no-callee-saved-20.c: Likewise.
        * gcc.target/i386/no-caller-saved-1-ms.c: Likewise.
        * 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/pr125436-1a.c: Likewise.
        * gcc.target/i386/pr125436-1b.c: Likewise.
        * gcc.target/i386/pr125436-2a.c: Likewise.
        * gcc.target/i386/pr125436-2b.c: Likewise.
        * gcc.target/i386/pr125436-3.c: Likewise.
        * gcc.target/i386/pr125436-4.c: Likewise.
        * 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.

Signed-off-by: H.J. Lu <[email protected]>
Co-Authored by: Richard Sandiford <[email protected]>
---
 gcc/config/i386/i386-expand.cc                | 113 +-----
 gcc/config/i386/i386-features.cc              |   2 +
 gcc/config/i386/i386-options.cc               |  17 -
 gcc/config/i386/i386-protos.h                 |   3 +-
 gcc/config/i386/i386.cc                       | 336 +++++++++++++++---
 gcc/config/i386/i386.md                       |  30 +-
 gcc/testsuite/gcc.target/i386/abi-mix-1.c     |  20 ++
 gcc/testsuite/gcc.target/i386/abi-mix-2.c     |   6 +
 .../gcc.target/i386/no-callee-saved-18.c      |   2 -
 .../gcc.target/i386/no-callee-saved-19b.c     |  32 +-
 .../gcc.target/i386/no-callee-saved-19d.c     |   6 +-
 .../gcc.target/i386/no-callee-saved-19e.c     |  33 +-
 .../gcc.target/i386/no-callee-saved-2.c       |  10 +-
 .../gcc.target/i386/no-callee-saved-20.c      |  92 +++++
 .../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/testsuite/gcc.target/i386/pr125436-1a.c   | 130 +++++++
 gcc/testsuite/gcc.target/i386/pr125436-1b.c   |  81 +++++
 gcc/testsuite/gcc.target/i386/pr125436-2a.c   | 132 +++++++
 gcc/testsuite/gcc.target/i386/pr125436-2b.c   |  83 +++++
 gcc/testsuite/gcc.target/i386/pr125436-3.c    |  88 +++++
 gcc/testsuite/gcc.target/i386/pr125436-4.c    |  88 +++++
 .../gcc.target/i386/preserve-none-14.c        |   2 -
 .../gcc.target/i386/preserve-none-23.c        |   2 -
 .../gcc.target/i386/preserve-none-7.c         |  10 +-
 34 files changed, 1503 insertions(+), 238 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/abi-mix-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/abi-mix-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-20.c
 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
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-1a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-1b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-2a.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-2b.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-4.c

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 07756897fad..18b259a660d 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
@@ -11094,17 +11095,6 @@ construct_plt_address (rtx symbol)
   return tmp;
 }
 
-/* Additional registers that are clobbered by SYSV calls.  */
-
-static int const x86_64_ms_sysv_extra_clobbered_registers
-                [NUM_X86_64_MS_CLOBBERED_REGS] =
-{
-  SI_REG, DI_REG,
-  XMM6_REG, XMM7_REG,
-  XMM8_REG, XMM9_REG, XMM10_REG, XMM11_REG,
-  XMM12_REG, XMM13_REG, XMM14_REG, XMM15_REG
-};
-
 rtx_insn *
 ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
                  rtx callarg2,
@@ -11114,7 +11104,6 @@ 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;
 
   if (SYMBOL_REF_P (XEXP (fnaddr, 0)))
     {
@@ -11124,26 +11113,13 @@ 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;
          if (fndecl == current_function_decl
              && decl_binds_to_current_def_p (fndecl))
            cfun->machine->recursive_function = true;
        }
     }
   else
-    {
-      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;
-       }
-
-      fndecl = NULL_TREE;
-    }
+    fndecl = NULL_TREE;
 
   if (pop == const0_rtx)
     pop = NULL;
@@ -11280,62 +11256,26 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx 
callarg1,
       vec[vec_len++] = pop;
     }
 
-  static const char ix86_call_used_regs[] = CALL_USED_REGISTERS;
-
-  if ((cfun->machine->call_saved_registers
-       == TYPE_NO_CALLER_SAVED_REGISTERS)
-      && (!fndecl
-         || (!TREE_THIS_VOLATILE (fndecl)
-             && !lookup_attribute ("no_caller_saved_registers",
-                                   TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))))
+  /* Set here, but it may get cleared later.  */
+  if (TARGET_64BIT_MS_ABI
+      && (!callarg2 || INTVAL (callarg2) != -2)
+      && TARGET_CALL_MS2SYSV_XLOGUES)
     {
-      bool is_64bit_ms_abi = (TARGET_64BIT
-                             && ix86_function_abi (fndecl) == MS_ABI);
-      char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi);
-
-      /* If there are no caller-saved registers, add all registers
-        that are clobbered by the call which returns.  */
-      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))
-           && !STACK_REGNO_P (i)
-           && !MMX_REGNO_P (i))
-         clobber_reg (&use,
-                      gen_rtx_REG (GET_MODE (regno_reg_rtx[i]), i));
-    }
-  else if (TARGET_64BIT_MS_ABI
-          && (!callarg2 || INTVAL (callarg2) != -2))
-    {
-      unsigned i;
+      if (!TARGET_SSE)
+       ;
 
-      for (i = 0; i < NUM_X86_64_MS_CLOBBERED_REGS; i++)
-       {
-         int regno = x86_64_ms_sysv_extra_clobbered_registers[i];
-         machine_mode mode = SSE_REGNO_P (regno) ? TImode : DImode;
+      /* Don't break hot-patched functions.  */
+      else if (ix86_function_ms_hook_prologue (current_function_decl))
+       ;
 
-         clobber_reg (&use, gen_rtx_REG (mode, regno));
-       }
+      /* TODO: Cases not yet examined.  */
+      else if (flag_split_stack)
+       warn_once_call_ms2sysv_xlogues ("-fsplit-stack");
 
-      /* Set here, but it may get cleared later.  */
-      if (TARGET_CALL_MS2SYSV_XLOGUES)
+      else
        {
-         if (!TARGET_SSE)
-           ;
-
-         /* Don't break hot-patched functions.  */
-         else if (ix86_function_ms_hook_prologue (current_function_decl))
-           ;
-
-         /* TODO: Cases not yet examined.  */
-         else if (flag_split_stack)
-           warn_once_call_ms2sysv_xlogues ("-fsplit-stack");
-
-         else
-           {
-             gcc_assert (!reload_completed);
-             cfun->machine->call_ms2sysv = true;
-           }
+         gcc_assert (!reload_completed);
+         cfun->machine->call_ms2sysv = true;
        }
     }
 
@@ -11353,25 +11293,6 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
       clobber_reg (&use, gen_rtx_REG (DImode, R10_REG));
     }
 
-  if (call_no_callee_saved_registers)
-    {
-      /* 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]
-           && 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))
-         clobber_reg (&use,
-                      gen_rtx_REG (GET_MODE (regno_reg_rtx[i]), i));
-    }
-
   if (vec_len > 1)
     call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (vec_len, vec));
   rtx_insn *call_insn = emit_call_insn (call);
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index f5caef29c6e..aef364ba8b7 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -4505,6 +4505,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
x86_cse_kind kind,
 
       symbol = XVECEXP (val, 0, 0);
       tls = gen_tls_global_dynamic_64 (Pmode, rax, symbol, caddr, rdi);
+      CALL_INSN_ABI_ID (tls) = ix86_tls_get_addr_abi ().id ();
 
       if (GET_MODE (symbol) != Pmode)
        symbol = gen_rtx_ZERO_EXTEND (Pmode, symbol);
@@ -4517,6 +4518,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
x86_cse_kind kind,
       caddr = ix86_tls_get_addr ();
 
       tls = gen_tls_local_dynamic_base_64 (Pmode, rax, caddr, rdi);
+      CALL_INSN_ABI_ID (tls) = ix86_tls_get_addr_abi ().id ();
 
       /* Attach a unique REG_EQUAL to DEST, to allow the RTL optimizers
         to share the LD_BASE result with other LD model accesses.  */
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index 626e1eab929..7aa9daf9ae1 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3527,21 +3527,6 @@ ix86_set_current_function (tree fndecl)
     }
   ix86_previous_fndecl = fndecl;
 
-  static call_saved_registers_type prev_call_saved_registers;
-
-  /* 64-bit MS and SYSV ABI have different set of call used registers.
-     Avoid expensive re-initialization of init_regs each time we switch
-     function context.  */
-  if (TARGET_64BIT
-      && (call_used_or_fixed_reg_p (SI_REG)
-         == (cfun->machine->call_abi == MS_ABI)))
-    reinit_regs ();
-  /* Need to re-initialize init_regs if caller-saved registers are
-     changed.  */
-  else if (prev_call_saved_registers
-          != cfun->machine->call_saved_registers)
-    reinit_regs ();
-
   if (cfun->machine->func_type != TYPE_NORMAL
       || (cfun->machine->call_saved_registers
          == TYPE_NO_CALLER_SAVED_REGISTERS))
@@ -3589,8 +3574,6 @@ ix86_set_current_function (tree fndecl)
            = TYPE_DEFAULT_CALL_SAVED_REGISTERS;
        }
     }
-
-  prev_call_saved_registers = cfun->machine->call_saved_registers;
 }
 
 /* Implement the TARGET_OFFLOAD_OPTIONS hook.  */
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 7dac3ed8e6c..ea23f75804a 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -286,7 +286,6 @@ 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
 
@@ -295,6 +294,8 @@ extern bool ix86_gpr_tls_address_pattern_p (rtx);
 extern bool ix86_tls_address_pattern_p (rtx);
 extern rtx ix86_rewrite_tls_address (rtx);
 extern rtx ix86_tls_get_addr (void);
+class predefined_function_abi;
+extern const predefined_function_abi & ix86_tls_get_addr_abi (void);
 
 extern void ix86_expand_vector_init (bool, rtx, rtx);
 extern void ix86_expand_vector_set (bool, rtx, rtx, int);
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 5bcf7254ab2..86bd6caf59f 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -107,6 +107,7 @@ along with GCC; see the file COPYING3.  If not see
 
 static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool);
 static void ix86_emit_restore_reg_using_pop (rtx, bool = false);
+static const predefined_function_abi & ix86_alternate_abi (void);
 
 
 #ifndef CHECK_STACK_LIMIT
@@ -503,17 +504,6 @@ 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;
-
   /* For 32-bit targets, disable the REX registers.  */
   if (! TARGET_64BIT)
     {
@@ -525,8 +515,10 @@ ix86_conditional_register_usage (void)
        CLEAR_HARD_REG_BIT (accessible_reg_set, i);
     }
 
-  /*  See the definition of CALL_USED_REGISTERS in i386.h.  */
-  c_mask = CALL_USED_REGISTERS_MASK (TARGET_64BIT_MS_ABI);
+  /* Set up the call-used registers based on the system ABI (ix86_abi).
+
+     See the definition of CALL_USED_REGISTERS in i386.h.  */
+  c_mask = CALL_USED_REGISTERS_MASK (TARGET_64BIT && ix86_abi == MS_ABI);
 
   CLEAR_HARD_REG_SET (reg_class_contents[(int)CLOBBERED_REGS]);
 
@@ -932,7 +924,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 fntype)
 {
   auto type = ix86_fntype_call_saved_registers (fntype);
@@ -3871,10 +3863,10 @@ ix86_function_value_regno_p (const unsigned int regno)
       /* Complex values are returned in %st(0)/%st(1) pair.  */
     case ST0_REG:
     case ST1_REG:
-      /* TODO: The function should depend on current function ABI but
-       builtins.cc would need updating then. Therefore we use the
-       default ABI.  */
-      if (TARGET_64BIT && ix86_cfun_abi () == MS_ABI)
+      /* TODO: An ABI identifier should be passed as a parameter.
+        For now, most callers, including those in builtins.cc,
+        expect us to use the default ABI.  */
+      if (TARGET_64BIT && ix86_abi == MS_ABI)
        return false;
       return TARGET_FLOAT_RETURNS_IN_80387;
 
@@ -6796,8 +6788,6 @@ ix86_hard_regno_scratch_ok (unsigned int regno)
 bool
 ix86_save_reg (unsigned int regno, bool maybe_eh_return, bool ignore_outlined)
 {
-  rtx reg;
-
   /* Save and restore DRAP register between prologue and epilogue so
      that stack pointer can be restored.  */
   if (crtl->drap_reg
@@ -6805,41 +6795,12 @@ ix86_save_reg (unsigned int regno, bool 
maybe_eh_return, bool ignore_outlined)
       && !cfun->machine->no_drap_save_restore)
     return true;
 
-  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, we preserve all
-        registers, except for MMX and x87 registers which aren't
-        supported when saving and restoring registers.  Don't
-        explicitly save SP register since it is always preserved.
-
-        Don't preserve registers used for function return value.  */
-      reg = crtl->return_rtx;
-      if (reg)
-       {
-         unsigned int i = REGNO (reg);
-         unsigned int nregs = REG_NREGS (reg);
-         while (nregs-- > 0)
-           if ((i + nregs) == regno)
-             return false;
-       }
-
-      return (df_regs_ever_live_p (regno)
-             && !fixed_regs[regno]
-             && !STACK_REGNO_P (regno)
-             && !MMX_REGNO_P (regno)
-             && (regno != HARD_FRAME_POINTER_REGNUM
-                 || !frame_pointer_needed));
-
-    case TYPE_NO_CALLEE_SAVED_REGISTERS:
-    case TYPE_PRESERVE_NONE:
-      if (regno != HARD_FRAME_POINTER_REGNUM)
-       return false;
-      break;
-    }
+  /* ??? Treat no_callee_saved_registers as a special case in order
+     to cope with -mnoreturn-no-callee-saved-registers, which is not
+     reflected in crtl->abi.  */
+  if (cfun->machine->call_saved_registers == TYPE_NO_CALLEE_SAVED_REGISTERS
+      && regno != HARD_FRAME_POINTER_REGNUM)
+    return false;
 
   if (regno == REAL_PIC_OFFSET_TABLE_REGNUM
       && pic_offset_table_rtx)
@@ -12574,6 +12535,18 @@ ix86_tls_get_addr (void)
   return ix86_tls_symbol;
 }
 
+/* Return the descriptor of the function ABI type for the tls_get_addr
+   function.  */
+
+const predefined_function_abi &
+ix86_tls_get_addr_abi (void)
+{
+  if (ix86_abi == SYSV_ABI)
+    return default_function_abi;
+  else
+    return ix86_alternate_abi ();
+}
+
 /* Construct the SYMBOL_REF for the _TLS_MODULE_BASE_ symbol.  */
 
 static GTY(()) rtx ix86_tls_module_base_symbol;
@@ -12684,8 +12657,10 @@ legitimize_tls_address (rtx x, enum tls_model model, 
bool for_mov)
              rtx_insn *insns;
 
              start_sequence ();
-             emit_call_insn
+             rtx_insn *call_insn = emit_call_insn
                (gen_tls_global_dynamic_64 (Pmode, rax, x, caddr, rdi));
+             CALL_INSN_ABI_ID (call_insn)
+               = ix86_tls_get_addr_abi ().id ();
              insns = end_sequence ();
 
              if (GET_MODE (x) != Pmode)
@@ -12739,8 +12714,10 @@ legitimize_tls_address (rtx x, enum tls_model model, 
bool for_mov)
              rtx eqv;
 
              start_sequence ();
-             emit_call_insn
+             rtx_insn *call_insn = emit_call_insn
                (gen_tls_local_dynamic_base_64 (Pmode, rax, caddr, rdi));
+             CALL_INSN_ABI_ID (call_insn)
+               = ix86_tls_get_addr_abi ().id ();
              insns = end_sequence ();
 
              /* Attach a unique REG_EQUAL, to allow the RTL optimizers to
@@ -21738,6 +21715,219 @@ ix86_hard_regno_mode_ok (unsigned int regno, 
machine_mode mode)
   return false;
 }
 
+/* Initialize function_abis[ABI_ID] with the set of register clobbers
+   in FULL_REG_CLOBBERS, adjusting for rules that apply to all ABIs.  */
+
+static void
+ix86_initialize_abi (unsigned int abi_id, HARD_REG_SET full_reg_clobbers)
+{
+  /* The general rule is that fixed registers should be marked as
+     call-clobbered.  This includes global registers, inaccessible
+     registers, the flags register, and the FPSR.
+
+     Handle the exceptions below.  */
+  full_reg_clobbers |= fixed_reg_set;
+
+  /* Every ABI (even preserve_none) preserves EBP/RBP.  */
+  CLEAR_HARD_REG_BIT (full_reg_clobbers, HARD_FRAME_POINTER_REGNUM);
+
+  /* Treat GCC's internal frame-related registers as call-preserved.  */
+  CLEAR_HARD_REG_BIT (full_reg_clobbers, FRAME_POINTER_REGNUM);
+  CLEAR_HARD_REG_BIT (full_reg_clobbers, ARG_POINTER_REGNUM);
+
+  function_abis[abi_id].initialize (abi_id, full_reg_clobbers);
+}
+
+/* Return the descriptor of no_callee_saved_registers function type.
+   None of the enabled registers are preserved, except for the common
+   rules applied by ix86_initialize_abi.  */
+
+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 ())
+    ix86_initialize_abi (ABI_NO_CALLEE_SAVED, accessible_reg_set);
+  return no_callee_saved_abi;
+}
+
+/* Return the descriptor of the no_caller_saved_registers function type
+   with ABI identifier ABI_ID.  All registers are preserved, except for:
+
+   - the return registers, which are enumerated in ABI_ID.
+
+   - the common rules applied by ix86_initialize_abi.  */
+
+static const predefined_function_abi &
+ix86_no_caller_saved_abi (unsigned int abi_id)
+{
+  auto &abi = function_abis[abi_id];
+  if (!abi.initialized_p ())
+    {
+      HARD_REG_SET full_reg_clobbers = {};
+
+      switch (abi_id)
+       {
+       case ABI_NO_CALLER_SAVED_RETURN_VOID:
+         break;
+
+       case ABI_NO_CALLER_SAVED_RETURN_AX_DX:
+         SET_HARD_REG_BIT (full_reg_clobbers, DX_REG);
+         /* Fall through.  */
+       case ABI_NO_CALLER_SAVED_RETURN_AX:
+         SET_HARD_REG_BIT (full_reg_clobbers, AX_REG);
+         break;
+
+       case ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1:
+         SET_HARD_REG_BIT (full_reg_clobbers, XMM1_REG);
+         /* Fall through.  */
+       case ABI_NO_CALLER_SAVED_RETURN_XMM0:
+         SET_HARD_REG_BIT (full_reg_clobbers, XMM0_REG);
+         break;
+       }
+
+      ix86_initialize_abi (abi_id, full_reg_clobbers);
+    }
+  return abi;
+}
+
+/* Return the descriptor of the standard function ABI type.  If
+   ABI_TYPE == ABI_ALTERNATE, return the function alternate ABI type.  */
+
+static const predefined_function_abi &
+ix86_standard_abi (int abi_type)
+{
+  static const char ix86_call_used_regs[] = CALL_USED_REGISTERS;
+  auto &standard_abi = function_abis[abi_type];
+  if (!standard_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 == (abi_type == ABI_ALTERNATE
+                                             ? SYSV_ABI : MS_ABI));
+      char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi);
+      for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (ix86_call_used_regs[i] == 1
+           || (ix86_call_used_regs[i] & c_mask))
+         SET_HARD_REG_BIT (full_reg_clobbers, i);
+
+      ix86_initialize_abi (abi_type, full_reg_clobbers);
+    }
+  return standard_abi;
+}
+
+/* Return the descriptor of the function alternate ABI type.  */
+
+static const predefined_function_abi &
+ix86_alternate_abi (void)
+{
+  return ix86_standard_abi (ABI_ALTERNATE);
+}
+
+/* Return the function ABI ID based on FNTYPE.  */
+
+static int
+ix86_function_abi_id (const_tree fntype)
+{
+  auto call_saved_registers = ix86_fntype_call_saved_registers (fntype);
+  if (call_saved_registers == TYPE_PRESERVE_NONE
+      || call_saved_registers == TYPE_NO_CALLEE_SAVED_REGISTERS)
+    return ABI_NO_CALLEE_SAVED;
+
+  if (call_saved_registers == TYPE_NO_CALLER_SAVED_REGISTERS)
+    {
+      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;
+               gcc_unreachable ();
+             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_DEFAULT;
+}
+
+/* Implement TARGET_FNTYPE_ABI.  */
+
+static const predefined_function_abi &
+ix86_fntype_abi (const_tree fntype)
+{
+  unsigned int abi_id = ix86_function_abi_id (fntype);
+  switch (abi_id)
+    {
+    case ABI_DEFAULT:
+      return default_function_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:
+    case ABI_NO_CALLER_SAVED_RETURN_AX:
+    case ABI_NO_CALLER_SAVED_RETURN_AX_DX:
+    case ABI_NO_CALLER_SAVED_RETURN_XMM0:
+    case ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1:
+      return ix86_no_caller_saved_abi (abi_id);
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return default_function_abi;
+}
+
 /* Initialize function_abis with corresponding abi_id,
    currently only handle vzeroupper.  */
 void
@@ -21776,12 +21966,37 @@ 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)
+  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_DEFAULT:
+    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:
+    case ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1:
+      /* These ABIs return some values in SSE registers and preserve
+        the rest.  The return value registers (XMM0 and possibly XMM1)
+        are fully rather than partially call-clobbered.  */
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+
   return SSE_REGNO_P (regno) && GET_MODE_SIZE (mode) > 16;
 }
 
@@ -28708,6 +28923,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_CAN_CHANGE_MODE_CLASS
 #define TARGET_CAN_CHANGE_MODE_CLASS ix86_can_change_mode_class
 
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index be4b615c542..05d6f6d62f0 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -513,9 +513,33 @@ (define_constants
 
 ;; Insn callee abi index.
 (define_constants
-  [(ABI_DEFAULT                0)
-   (ABI_VZEROUPPER     1)
-   (ABI_UNKNOWN                2)])
+  [;; The system ABI; that is, the ABI associated with ix86_abi, and the
+   ;; ABI that an undecorated "void foo()" would have.
+   (ABI_DEFAULT                             0)
+   ;; An ABI that describes the effect of vzeroupper.  vzeroupper is
+   ;; represented as a call because calls are the main mechanism for
+   ;; expression partial register clobbers.
+   (ABI_VZEROUPPER                          1)
+   ;; ABI_ALTERNATE is the Windows function ABI if ix86_abi == SYSV_ABI
+   ;; and is the SYSV function ABI if ix86_abi == MS_ABI.
+   (ABI_ALTERNATE                           2)
+   (ABI_NO_CALLEE_SAVED                     3)
+   ;; Return void.
+   (ABI_NO_CALLER_SAVED_RETURN_VOID         4)
+   ;; 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           5)
+   ;; Return int64 and _Complex int in 32-bit.
+   ;; Return _Complex int64 in 64-bit.
+   (ABI_NO_CALLER_SAVED_RETURN_AX_DX        6)
+   ;; 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         7)
+   ;; Return _Complex double in SYSV 64-bit.
+   (ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1    8)
+   (ABI_UNKNOWN                             9)])
 
 ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
 ;; from i386.cc.
diff --git a/gcc/testsuite/gcc.target/i386/abi-mix-1.c 
b/gcc/testsuite/gcc.target/i386/abi-mix-1.c
new file mode 100644
index 00000000000..342da642bf2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/abi-mix-1.c
@@ -0,0 +1,20 @@
+/* { dg-options "-O2 -masm=att -mno-mmx -mno-80387 -msse" } */
+
+extern void callee_clobbered () [[gnu::preserve_none]];
+extern void callee_preserved () [[gnu::no_caller_saved_registers]];
+extern void callee_sysv () [[gnu::sysv_abi]];
+extern void callee_ms () [[gnu::ms_abi]];
+
+#define TEST(PREFIX, ATTR) \
+  void PREFIX##_clobbered () [[ATTR]] { callee_clobbered (); } \
+  void PREFIX##_preserved () [[ATTR]] { callee_preserved (); } \
+  void PREFIX##_sysv () [[ATTR]] { callee_sysv (); } \
+  void PREFIX##_ms () [[ATTR]] { callee_ms (); }
+
+TEST (clobbered, gnu::preserve_none)
+TEST (preserved, gnu::no_caller_saved_registers)
+TEST (sysv, gnu::sysv_abi)
+TEST (ms, gnu::ms_abi)
+
+/* { dg-final { scan-assembler-not "%st" } } */
+/* { dg-final { scan-assembler "%xmm" } } */
diff --git a/gcc/testsuite/gcc.target/i386/abi-mix-2.c 
b/gcc/testsuite/gcc.target/i386/abi-mix-2.c
new file mode 100644
index 00000000000..14428a6d3a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/abi-mix-2.c
@@ -0,0 +1,6 @@
+/* { dg-options "-O2 -masm=att -mno-mmx -mno-80387 -mno-sse" } */
+
+#include "abi-mix-1.c"
+
+/* { dg-final { scan-assembler-not "%st" } } */
+/* { dg-final { scan-assembler-not "%xmm" } } */
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..f64172c737f 100644
--- a/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c
+++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */
+/* { dg-do compile { target { *-*-linux* && { lp64 && maybe_x32 } } } } */
 /* { dg-options "-O2 -mx32 -fno-pic -mtune=generic -msse2 -mno-avx -mno-mmx 
-mno-80387 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */
 /* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
 /* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
@@ -52,15 +52,14 @@
 **     .cfi_startproc
 **     subl    \$376, %esp
 **...
-**     movq    %rax, 256\(%rsp\)
-**     movq    %rdx, 264\(%rsp\)
-**     movq    %rcx, 272\(%rsp\)
-**     movq    %rbx, 280\(%rsp\)
-**     movq    %rsi, 288\(%rsp\)
-**     movq    %rdi, 296\(%rsp\)
+**     movq    %rdi, 304\(%rsp\)
 **...
 **     movl    \$code\+4, %edi
-**     movq    %rbp, 304\(%rsp\)
+**     movq    %rax, 264\(%rsp\)
+**     movq    %rdx, 272\(%rsp\)
+**     movq    %rcx, 280\(%rsp\)
+**     movq    %rbx, 288\(%rsp\)
+**     movq    %rsi, 296\(%rsp\)
 **     movq    %r8, 312\(%rsp\)
 **     movq    %r9, 320\(%rsp\)
 **     movq    %r10, 328\(%rsp\)
@@ -86,8 +85,8 @@
 **     movaps  %xmm14, 224\(%rsp\)
 **     movaps  %xmm15, 240\(%rsp\)
 **...
-**     movl    code\(%rip\), %ebp
-**     call    \*%rbp
+**     movl    code\(%rip\), %eax
+**     call    \*%rax
 **     movaps  \(%rsp\), %xmm0
 **     movaps  16\(%rsp\), %xmm1
 **     movaps  32\(%rsp\), %xmm2
@@ -104,13 +103,12 @@
 **     movaps  208\(%rsp\), %xmm13
 **     movaps  224\(%rsp\), %xmm14
 **     movaps  240\(%rsp\), %xmm15
-**     movq    256\(%rsp\), %rax
-**     movq    264\(%rsp\), %rdx
-**     movq    272\(%rsp\), %rcx
-**     movq    280\(%rsp\), %rbx
-**     movq    288\(%rsp\), %rsi
-**     movq    296\(%rsp\), %rdi
-**     movq    304\(%rsp\), %rbp
+**     movq    264\(%rsp\), %rax
+**     movq    272\(%rsp\), %rdx
+**     movq    280\(%rsp\), %rcx
+**     movq    288\(%rsp\), %rbx
+**     movq    296\(%rsp\), %rsi
+**     movq    304\(%rsp\), %rdi
 **     movq    312\(%rsp\), %r8
 **     movq    320\(%rsp\), %r9
 **     movq    328\(%rsp\), %r10
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..b715d9aff8e 100644
--- a/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c
+++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c
@@ -1,4 +1,4 @@
-/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */
+/* { dg-do compile { target { *-*-linux* && { lp64 && maybe_x32 } } } } */
 /* { dg-options "-O2 -mx32 -fno-pic -mtune=generic -msse2 -mno-avx -mno-mmx 
-mno-80387 -mapxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */
 /* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
 /* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
@@ -52,15 +52,14 @@
 **     .cfi_startproc
 **     subl    \$504, %esp
 **...
-**     movq    %rax, 256\(%rsp\)
-**     movq    %rdx, 264\(%rsp\)
-**     movq    %rcx, 272\(%rsp\)
-**     movq    %rbx, 280\(%rsp\)
-**     movq    %rsi, 288\(%rsp\)
-**     movq    %rdi, 296\(%rsp\)
+**     movq    %rax, 264\(%rsp\)
+**     movq    %rdi, 304\(%rsp\)
 **...
 **     movl    \$code\+4, %edi
-**     movq    %rbp, 304\(%rsp\)
+**     movq    %rdx, 272\(%rsp\)
+**     movq    %rcx, 280\(%rsp\)
+**     movq    %rbx, 288\(%rsp\)
+**     movq    %rsi, 296\(%rsp\)
 **     movq    %r8, 312\(%rsp\)
 **     movq    %r9, 320\(%rsp\)
 **     movq    %r10, 328\(%rsp\)
@@ -85,9 +84,8 @@
 **     movq    %r29, 480\(%rsp\)
 **     movq    %r30, 488\(%rsp\)
 **     movq    %r31, 496\(%rsp\)
-**...
-**     movl    code\(%rip\), %ebp
 **     movaps  %xmm0, \(%rsp\)
+**     movl    code\(%rip\), %eax
 **     movaps  %xmm1, 16\(%rsp\)
 **     movaps  %xmm2, 32\(%rsp\)
 **     movaps  %xmm3, 48\(%rsp\)
@@ -104,7 +102,7 @@
 **     movaps  %xmm14, 224\(%rsp\)
 **     movaps  %xmm15, 240\(%rsp\)
 **...
-**     call    \*%rbp
+**     call    \*%rax
 **     movaps  \(%rsp\), %xmm0
 **     movaps  16\(%rsp\), %xmm1
 **     movaps  32\(%rsp\), %xmm2
@@ -121,13 +119,12 @@
 **     movaps  208\(%rsp\), %xmm13
 **     movaps  224\(%rsp\), %xmm14
 **     movaps  240\(%rsp\), %xmm15
-**     movq    256\(%rsp\), %rax
-**     movq    264\(%rsp\), %rdx
-**     movq    272\(%rsp\), %rcx
-**     movq    280\(%rsp\), %rbx
-**     movq    288\(%rsp\), %rsi
-**     movq    296\(%rsp\), %rdi
-**     movq    304\(%rsp\), %rbp
+**     movq    264\(%rsp\), %rax
+**     movq    272\(%rsp\), %rdx
+**     movq    280\(%rsp\), %rcx
+**     movq    288\(%rsp\), %rbx
+**     movq    296\(%rsp\), %rsi
+**     movq    304\(%rsp\), %rdi
 **     movq    312\(%rsp\), %r8
 **     movq    320\(%rsp\), %r9
 **     movq    328\(%rsp\), %r10
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-20.c 
b/gcc/testsuite/gcc.target/i386/no-callee-saved-20.c
new file mode 100644
index 00000000000..56bf4569d02
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-20.c
@@ -0,0 +1,92 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O2 -fno-pic -mgeneral-regs-only -mtune=generic 
-mtune-ctrl=prologue_using_move,epilogue_using_move" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+__attribute__((no_callee_saved_registers, noipa))
+void
+foo (void)
+{
+}
+
+/*
+**bar:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     subq    \$376, %rsp
+**...
+**     movq    %rax, 264\(%rsp\)
+**     movq    %rdx, 272\(%rsp\)
+**     movq    %rcx, 280\(%rsp\)
+**     movq    %rbx, 288\(%rsp\)
+**     movq    %rsi, 296\(%rsp\)
+**     movq    %rdi, 304\(%rsp\)
+**     movq    %r8, 312\(%rsp\)
+**     movq    %r9, 320\(%rsp\)
+**     movq    %r10, 328\(%rsp\)
+**     movq    %r11, 336\(%rsp\)
+**     movq    %r12, 344\(%rsp\)
+**     movq    %r13, 352\(%rsp\)
+**     movq    %r14, 360\(%rsp\)
+**     movq    %r15, 368\(%rsp\)
+**     movaps  %xmm0, \(%rsp\)
+**     movaps  %xmm1, 16\(%rsp\)
+**     movaps  %xmm2, 32\(%rsp\)
+**     movaps  %xmm3, 48\(%rsp\)
+**     movaps  %xmm4, 64\(%rsp\)
+**     movaps  %xmm5, 80\(%rsp\)
+**     movaps  %xmm6, 96\(%rsp\)
+**     movaps  %xmm7, 112\(%rsp\)
+**     movaps  %xmm8, 128\(%rsp\)
+**     movaps  %xmm9, 144\(%rsp\)
+**     movaps  %xmm10, 160\(%rsp\)
+**     movaps  %xmm11, 176\(%rsp\)
+**     movaps  %xmm12, 192\(%rsp\)
+**     movaps  %xmm13, 208\(%rsp\)
+**     movaps  %xmm14, 224\(%rsp\)
+**     movaps  %xmm15, 240\(%rsp\)
+**...
+**     call    foo
+**     movaps  \(%rsp\), %xmm0
+**     movaps  16\(%rsp\), %xmm1
+**     movaps  32\(%rsp\), %xmm2
+**     movaps  48\(%rsp\), %xmm3
+**     movaps  64\(%rsp\), %xmm4
+**     movaps  80\(%rsp\), %xmm5
+**     movaps  96\(%rsp\), %xmm6
+**     movaps  112\(%rsp\), %xmm7
+**     movaps  128\(%rsp\), %xmm8
+**     movaps  144\(%rsp\), %xmm9
+**     movaps  160\(%rsp\), %xmm10
+**     movaps  176\(%rsp\), %xmm11
+**     movaps  192\(%rsp\), %xmm12
+**     movaps  208\(%rsp\), %xmm13
+**     movq    264\(%rsp\), %rax
+**     movq    272\(%rsp\), %rdx
+**     movq    280\(%rsp\), %rcx
+**     movq    288\(%rsp\), %rbx
+**     movq    296\(%rsp\), %rsi
+**     movq    304\(%rsp\), %rdi
+**     movq    312\(%rsp\), %r8
+**     movq    320\(%rsp\), %r9
+**     movq    328\(%rsp\), %r10
+**     movq    336\(%rsp\), %r11
+**     movq    344\(%rsp\), %r12
+**     movq    352\(%rsp\), %r13
+**     movq    360\(%rsp\), %r14
+**     movq    368\(%rsp\), %r15
+**     movaps  224\(%rsp\), %xmm14
+**     movaps  240\(%rsp\), %xmm15
+**     addq    \$376, %rsp
+**...
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+__attribute__((no_caller_saved_registers, target("sse2")))
+void
+bar (void)
+{
+  foo ();
+}
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/pr125436-1a.c 
b/gcc/testsuite/gcc.target/i386/pr125436-1a.c
new file mode 100644
index 00000000000..be3c2509fc6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-1a.c
@@ -0,0 +1,130 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     leaq    tls_instance@tlsld\(%rip\), %rdi
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, tls_instance@dtpoff\(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+static volatile int magic_number = 0x12345678;
+
+static __thread int tls_instance = 0;
+
+__attribute__ ((ms_abi))
+void
+ms_tls_access (int i)
+{
+  tls_instance += i;
+}
+
+__attribute__ ((sysv_abi))
+int
+sysv_foo (int i)
+{
+  double A = magic_number;
+  double B = magic_number;
+  int a = magic_number;
+  int b = magic_number;
+  int c = magic_number;
+  int d = magic_number;
+  int e = magic_number;
+  int f = magic_number;
+  int g = magic_number;
+  int h = magic_number;
+
+  ms_tls_access (i);
+
+  return (a ^ b) ^ (c ^ d) ^ (e ^ f) ^ (g ^ h) + (int)(A - B);
+}
+
+__attribute__ ((ms_abi))
+int
+ms_foo (int i)
+{
+  double A = magic_number;
+  double B = magic_number;
+  int a = magic_number;
+  int b = magic_number;
+  int c = magic_number;
+  int d = magic_number;
+  int e = magic_number;
+  int f = magic_number;
+  int g = magic_number;
+  int h = magic_number;
+
+  ms_tls_access (i);
+
+  return a ^ b ^ c ^ d ^ e ^ f ^ g ^ h + (int)(A - B);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125436-1b.c 
b/gcc/testsuite/gcc.target/i386/pr125436-1b.c
new file mode 100644
index 00000000000..9b6e4a508c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-1b.c
@@ -0,0 +1,81 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mabi=ms -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     leaq    tls_instance@tlsld\(%rip\), %rdi
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, tls_instance@dtpoff\(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+#include "pr125436-1a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr125436-2a.c 
b/gcc/testsuite/gcc.target/i386/pr125436-2a.c
new file mode 100644
index 00000000000..9126d3ca2ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-2a.c
@@ -0,0 +1,132 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     data16  leaq    tls_instance@tlsgd\(%rip\), %rdi
+**     .value  0x6666
+**     rex64
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, \(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+static volatile int magic_number = 0x12345678;
+
+__thread int tls_instance = 0;
+
+__attribute__ ((ms_abi))
+void
+ms_tls_access (int i)
+{
+  tls_instance += i;
+}
+
+__attribute__ ((sysv_abi))
+int
+sysv_foo (int i)
+{
+  double A = magic_number;
+  double B = magic_number;
+  int a = magic_number;
+  int b = magic_number;
+  int c = magic_number;
+  int d = magic_number;
+  int e = magic_number;
+  int f = magic_number;
+  int g = magic_number;
+  int h = magic_number;
+
+  ms_tls_access (i);
+
+  return (a ^ b) ^ (c ^ d) ^ (e ^ f) ^ (g ^ h) + (int)(A - B);
+}
+
+__attribute__ ((ms_abi))
+int
+ms_foo (int i)
+{
+  double A = magic_number;
+  double B = magic_number;
+  int a = magic_number;
+  int b = magic_number;
+  int c = magic_number;
+  int d = magic_number;
+  int e = magic_number;
+  int f = magic_number;
+  int g = magic_number;
+  int h = magic_number;
+
+  ms_tls_access (i);
+
+  return a ^ b ^ c ^ d ^ e ^ f ^ g ^ h + (int)(A - B);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125436-2b.c 
b/gcc/testsuite/gcc.target/i386/pr125436-2b.c
new file mode 100644
index 00000000000..4c634c9d8b0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-2b.c
@@ -0,0 +1,83 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mabi=ms -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     data16  leaq    tls_instance@tlsgd\(%rip\), %rdi
+**     .value  0x6666
+**     rex64
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, \(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+#include "pr125436-2a.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr125436-3.c 
b/gcc/testsuite/gcc.target/i386/pr125436-3.c
new file mode 100644
index 00000000000..939f85a586b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-3.c
@@ -0,0 +1,88 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     leaq    tls_instance@tlsld\(%rip\), %rdi
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, tls_instance@dtpoff\(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+static __thread int tls_instance = 0;
+
+__attribute__ ((ms_abi))
+void
+ms_tls_access (int i)
+{
+  tls_instance += i;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr125436-4.c 
b/gcc/testsuite/gcc.target/i386/pr125436-4.c
new file mode 100644
index 00000000000..205595810aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr125436-4.c
@@ -0,0 +1,88 @@
+/* { dg-do compile { target { *-*-linux* && lp64 } } } */
+/* { dg-options "-O1 -fPIC -mabi=ms -mtls-dialect=gnu 
-mtune-ctrl=^prologue_using_move,^epilogue_using_move -mno-push-args 
-fomit-frame-pointer -mtune=generic" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.}  
} } */
+
+/*
+**ms_tls_access:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     pushq   %rdi
+**     .cfi_def_cfa_offset 16
+**     .cfi_offset 5, -16
+**     pushq   %rsi
+**     .cfi_def_cfa_offset 24
+**     .cfi_offset 4, -24
+**     pushq   %rbx
+**     .cfi_def_cfa_offset 32
+**     .cfi_offset 3, -32
+**     subq    \$160, %rsp
+**     .cfi_def_cfa_offset 192
+**     movaps  %xmm6, \(%rsp\)
+**     movaps  %xmm7, 16\(%rsp\)
+**     movaps  %xmm8, 32\(%rsp\)
+**     movaps  %xmm9, 48\(%rsp\)
+**     movaps  %xmm10, 64\(%rsp\)
+**     movaps  %xmm11, 80\(%rsp\)
+**     movaps  %xmm12, 96\(%rsp\)
+**     movaps  %xmm13, 112\(%rsp\)
+**     movaps  %xmm14, 128\(%rsp\)
+**     movaps  %xmm15, 144\(%rsp\)
+**     .cfi_offset 23, -192
+**     .cfi_offset 24, -176
+**     .cfi_offset 25, -160
+**     .cfi_offset 26, -144
+**     .cfi_offset 27, -128
+**     .cfi_offset 28, -112
+**     .cfi_offset 29, -96
+**     .cfi_offset 30, -80
+**     .cfi_offset 31, -64
+**     .cfi_offset 32, -48
+**     movl    %ecx, %ebx
+**     leaq    tls_instance@tlsld\(%rip\), %rdi
+**     call    __tls_get_addr@PLT
+**     addl    %ebx, tls_instance@dtpoff\(%rax\)
+**     movaps  \(%rsp\), %xmm6
+**     movaps  16\(%rsp\), %xmm7
+**     movaps  32\(%rsp\), %xmm8
+**     movaps  48\(%rsp\), %xmm9
+**     movaps  64\(%rsp\), %xmm10
+**     movaps  80\(%rsp\), %xmm11
+**     movaps  96\(%rsp\), %xmm12
+**     movaps  112\(%rsp\), %xmm13
+**     movaps  128\(%rsp\), %xmm14
+**     movaps  144\(%rsp\), %xmm15
+**     addq    \$160, %rsp
+**     .cfi_restore 32
+**     .cfi_restore 31
+**     .cfi_restore 30
+**     .cfi_restore 29
+**     .cfi_restore 28
+**     .cfi_restore 27
+**     .cfi_restore 26
+**     .cfi_restore 25
+**     .cfi_restore 24
+**     .cfi_restore 23
+**     .cfi_def_cfa_offset 32
+**     popq    %rbx
+**     .cfi_restore 3
+**     .cfi_def_cfa_offset 24
+**     popq    %rsi
+**     .cfi_restore 4
+**     .cfi_def_cfa_offset 16
+**     popq    %rdi
+**     .cfi_restore 5
+**     .cfi_def_cfa_offset 8
+**     ret
+**     .cfi_endproc
+**...
+*/
+
+static __thread int tls_instance = 0;
+
+__attribute__ ((ms_abi))
+void
+ms_tls_access (int i)
+{
+  tls_instance += i;
+}
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 } } 
} } */
-- 
2.54.0

Reply via email to