[gcc r17-2209] x86: Implement TARGET_FNTYPE_ABI

"H.J. Lu via Gcc-cvs" <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:94082ac189cf318ea4ad52ffdf9fa5f941ebcf9e

commit r17-2209-g94082ac189cf318ea4ad52ffdf9fa5f941ebcf9e
Author: H.J. Lu <[email protected]>
Date:   Tue Apr 14 18:37:20 2026 +0800

    x86: Implement TARGET_FNTYPE_ABI
    
    Implement TARGET_FNTYPE_ABI to avoid spills of callee-saved registers
    when calling functions with no_caller_saved_registers attribute.
    
    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_emit_tls_call): Call
            ix86_tls_get_addr_abi to get GNU TLS ABI and use it, instead of
            default_function_abi, for registers clobbered by GNU TLS call.
            (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_AX_XMM0,
            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/no-caller-saved-8.c: Likewise.
            * gcc.target/i386/no-caller-saved-9.c: Likewise.
            * gcc.target/i386/no-caller-saved-10.c: Likewise.
            * gcc.target/i386/no-caller-saved-11.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/pr119784b.c: Adjusted for unused RBP.
            * 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]>
    
    Signed-off-by: H.J. Lu <[email protected]>

Diff:
---
 gcc/config/i386/i386-expand.cc                     | 113 +------
 gcc/config/i386/i386-features.cc                   |  16 +-
 gcc/config/i386/i386-options.cc                    |  17 -
 gcc/config/i386/i386-protos.h                      |   3 +-
 gcc/config/i386/i386.cc                            | 361 +++++++++++++++++----
 gcc/config/i386/i386.md                            |  32 +-
 gcc/testsuite/gcc.target/i386/abi-mix-1.c          |  21 ++
 gcc/testsuite/gcc.target/i386/abi-mix-2.c          |   7 +
 gcc/testsuite/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/testsuite/gcc.target/i386/no-callee-saved-2.c  |  10 +-
 gcc/testsuite/gcc.target/i386/no-callee-saved-20.c |  92 ++++++
 gcc/testsuite/gcc.target/i386/no-callee-saved-8.c  |   8 +-
 gcc/testsuite/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/testsuite/gcc.target/i386/no-caller-saved-1.c  |  50 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-10.c |  17 +
 gcc/testsuite/gcc.target/i386/no-caller-saved-11.c |  19 ++
 gcc/testsuite/gcc.target/i386/no-caller-saved-2.c  |  49 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-3.c  |  49 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-4.c  |  44 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-5.c  |  34 ++
 gcc/testsuite/gcc.target/i386/no-caller-saved-6.c  |  34 ++
 gcc/testsuite/gcc.target/i386/no-caller-saved-7.c  |  49 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-8.c  |  51 +++
 gcc/testsuite/gcc.target/i386/no-caller-saved-9.c  |  51 +++
 gcc/testsuite/gcc.target/i386/pr119784b.c          |  33 +-
 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/testsuite/gcc.target/i386/preserve-none-14.c   |   2 -
 gcc/testsuite/gcc.target/i386/preserve-none-23.c   |   2 -
 gcc/testsuite/gcc.target/i386/preserve-none-7.c    |  10 +-
 39 files changed, 1694 insertions(+), 261 deletions(-)

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 69265c4e2287..fd25b93a566b 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
@@ -11329,17 +11330,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,
@@ -11349,7 +11339,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)))
     {
@@ -11359,26 +11348,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;
@@ -11515,62 +11491,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;
 	}
     }
 
@@ -11588,25 +11528,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 c6c3c906c8db..d65b6ce76721 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -4349,11 +4349,15 @@ ix86_emit_tls_call (rtx tls_set, x86_cse_kind kind, basic_block bb,
       /* Get all live caller-saved registers for TLS_GD and TLS_LD_BASE
 	 instructions.  */
       if (kind != X86_CSE_TLSDESC)
-	for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-	  if (default_function_abi.clobbers_full_reg_p (i)
-	      && !fixed_regs[i]
-	      && bitmap_bit_p (in, i))
-	    bitmap_set_bit (live_caller_saved_regs, i);
+	{
+	  const predefined_function_abi &tls_abi
+	    = ix86_tls_get_addr_abi ();
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+	    if (tls_abi.clobbers_full_reg_p (i)
+		&& !fixed_regs[i]
+		&& bitmap_bit_p (in, i))
+	      bitmap_set_bit (live_caller_saved_regs, i);
+	}
 
       if (bitmap_empty_p (live_caller_saved_regs))
 	{
@@ -4526,6 +4530,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);
@@ -4538,6 +4543,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 da6e45f3f29b..a9d31714f13f 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -3525,21 +3525,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))
@@ -3587,8 +3572,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 870dcb68d2f2..9708810ea765 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 d62e75352688..23f65ab401d1 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;
 
@@ -6783,8 +6775,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
@@ -6792,41 +6782,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)
@@ -12561,6 +12522,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;
@@ -12671,8 +12644,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)
@@ -12726,8 +12701,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
@@ -21713,6 +21690,243 @@ 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);
+
+  /* MMX registers aren't preserved.  */
+  if (TARGET_MMX)
+    full_reg_clobbers |= reg_class_contents[MMX_REGS];
+
+  /* X87 registers aren't preserved.  */
+  if (TARGET_80387 || TARGET_FLOAT_RETURNS_IN_80387)
+    full_reg_clobbers |= reg_class_contents[FLOAT_REGS];
+
+  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_AX_XMM0:
+	  SET_HARD_REG_BIT (full_reg_clobbers, AX_REG);
+	  SET_HARD_REG_BIT (full_reg_clobbers, XMM0_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;
+
+	default:
+	  gcc_unreachable ();
+	}
+
+      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) == AX_REG)
+		{
+		  if (REG_P (x1) && REGNO (x1) == XMM0_REG)
+		    return ABI_NO_CALLER_SAVED_RETURN_AX_XMM0;
+		}
+	      if (REG_P (x0) && REGNO (x0) == XMM0_REG && REG_P (x1))
+		{
+		  if (REGNO (x1) == AX_REG)
+		    return ABI_NO_CALLER_SAVED_RETURN_AX_XMM0;
+		  else if (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_AX_XMM0:
+    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
@@ -21751,12 +21965,38 @@ 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_AX_XMM0:
+    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;
 }
 
@@ -28680,6 +28920,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 f173423b3342..d4107739250a 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -513,9 +513,35 @@
 
 ;; 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 struct pair with int64 and double in 64-bit.
+   (ABI_NO_CALLER_SAVED_RETURN_AX_XMM0      7)
+   ;; Return float and double in 64-bit.
+   ;; Return _Complex float in SYSV 64-bit.
+   ;; Return int28, _Complex double in MS 64-bit.
+   (ABI_NO_CALLER_SAVED_RETURN_XMM0         8)
+   ;; Return _Complex double in SYSV 64-bit.
+   (ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1    9)
+   (ABI_UNKNOWN                            10)])
 
 ;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
 ;; from i386.cc.
diff --git a/gcc/testsuite/gcc.target/i386/abi-mix-1.c b/gcc/testsuite/gcc.target/i386/abi-mix-1.c
new file mode 100644
index 000000000000..ae00e2ba3a16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/abi-mix-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile { target { ! x32 } } } */
+/* { 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 000000000000..8c95d8cb7d57
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/abi-mix-2.c
@@ -0,0 +1,7 @@
+/* { dg-do compile { target { ! x32 } } } */
+/* { 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 128b9c46e8ec..5e228753d8a1 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 dc38936a61a9..f64172c737fb 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 4657e170350b..bb9dce13350c 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 8e0bbe82eae0..b715d9aff8e1 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 e074ca51df40..86864ea9bffb 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 000000000000..56bf4569d025
--- /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 ed3d96bdca05..692166c98e9e 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 7730c5903d4b..7acaff2ad355 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 000000000000..6b95a646fc5f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c
@@ -0,0 +1,50 @@
+/* PR target/124798  */
+/* { dg-do compile { target { ! x32 } } } */
+/* { 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 000000000000..5e2f792665fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c
@@ -0,0 +1,46 @@
+/* PR target/124798  */
+/* { dg-do compile { target { ! x32 } } } */
+/* { 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 000000000000..fc8ab95c7e85
--- /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-10.c b/gcc/testsuite/gcc.target/i386/no-caller-saved-10.c
new file mode 100644
index 000000000000..0dc9f5a2ad2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-10.c
@@ -0,0 +1,17 @@
+/* Verify that no_caller_saved_registers calls still clobber x87 and MMX
+   registers.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att -mfpmath=387 -m80387 -mlong-double-80 -mno-sse -fomit-frame-pointer" } */
+
+typedef int v2si __attribute__ ((vector_size (8)));
+extern void foo (void) __attribute__ ((no_caller_saved_registers));
+
+long double
+bar_x87 (long double x, long double y)
+{
+  long double z = x + y;
+  foo ();
+  return z + 1.0L;
+}
+
+/* { dg-final { scan-assembler-times "fstpt\[ \t\]+" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/no-caller-saved-11.c b/gcc/testsuite/gcc.target/i386/no-caller-saved-11.c
new file mode 100644
index 000000000000..11967ea06a2c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-11.c
@@ -0,0 +1,19 @@
+/* Verify that no_caller_saved_registers calls still clobber x87 and MMX
+   registers.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -masm=att -mmmx -mno-sse -fomit-frame-pointer" } */
+
+typedef int v2si __attribute__ ((vector_size (8)));
+extern void foo (void) __attribute__ ((no_caller_saved_registers));
+
+void
+bar_mmx (void)
+{
+  v2si x;
+  __asm__ volatile ("# %0" : "=y" (x));
+  foo ();
+  __asm__ volatile ("# %0" :: "y" (x));
+}
+
+/* { dg-final { scan-assembler-times "movq\[ \t\]+%mm\[0-7\], \[0-9\]*\\(%\[re\]?sp\\)" 1 } } */
+/* { dg-final { scan-assembler-times "movq\[ \t\]+\[0-9\]*\\(%\[re\]?sp\\), %mm\[0-7\]" 1 } } */
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 000000000000..47b671dfa401
--- /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 000000000000..990b870c3238
--- /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 000000000000..9f6b494bdb71
--- /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 000000000000..98f58fe92f53
--- /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 000000000000..5eb5b102843b
--- /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 000000000000..c8a99e950da2
--- /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/no-caller-saved-8.c b/gcc/testsuite/gcc.target/i386/no-caller-saved-8.c
new file mode 100644
index 000000000000..40809ec71214
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-8.c
@@ -0,0 +1,51 @@
+/* PR target/124798  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=corei7 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */
+
+typedef struct
+{
+  long long i;
+  double d;
+} record;
+
+extern record foo (void)
+  __attribute__ ((no_caller_saved_registers, sysv_abi));
+
+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/no-caller-saved-9.c b/gcc/testsuite/gcc.target/i386/no-caller-saved-9.c
new file mode 100644
index 000000000000..f254b4deff36
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/no-caller-saved-9.c
@@ -0,0 +1,51 @@
+/* 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;
+  long long i;
+} record;
+
+extern record foo (void)
+  __attribute__ ((no_caller_saved_registers, sysv_abi));
+
+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/pr119784b.c b/gcc/testsuite/gcc.target/i386/pr119784b.c
index c6761976ed62..fbb907cdde73 100644
--- a/gcc/testsuite/gcc.target/i386/pr119784b.c
+++ b/gcc/testsuite/gcc.target/i386/pr119784b.c
@@ -11,14 +11,12 @@
 **	.cfi_startproc
 **	subl	\$248, %esp
 **...
-**	movq	%rax, \(%rsp\)
-**	movq	%rdx, 8\(%rsp\)
-**	movq	%rcx, 16\(%rsp\)
-**	movq	%rbx, 24\(%rsp\)
-**	movq	%rsi, 32\(%rsp\)
-**	movq	%rdi, 40\(%rsp\)
-**...
-**	movq	%rbp, 48\(%rsp\)
+**	movq	%rax, 8\(%rsp\)
+**	movq	%rdx, 16\(%rsp\)
+**	movq	%rcx, 24\(%rsp\)
+**	movq	%rbx, 32\(%rsp\)
+**	movq	%rsi, 40\(%rsp\)
+**	movq	%rdi, 48\(%rsp\)
 **	movq	%r8, 56\(%rsp\)
 **	movq	%r9, 64\(%rsp\)
 **	movq	%r10, 72\(%rsp\)
@@ -44,15 +42,14 @@
 **	movq	%r30, 232\(%rsp\)
 **	movq	%r31, 240\(%rsp\)
 **...
-**	movl	code\(%rip\), %ebp
-**	call	\*%rbp
-**	movq	\(%rsp\), %rax
-**	movq	8\(%rsp\), %rdx
-**	movq	16\(%rsp\), %rcx
-**	movq	24\(%rsp\), %rbx
-**	movq	32\(%rsp\), %rsi
-**	movq	40\(%rsp\), %rdi
-**	movq	48\(%rsp\), %rbp
+**	movl	code\(%rip\), %eax
+**	call	\*%rax
+**	movq	8\(%rsp\), %rax
+**	movq	16\(%rsp\), %rdx
+**	movq	24\(%rsp\), %rcx
+**	movq	32\(%rsp\), %rbx
+**	movq	40\(%rsp\), %rsi
+**	movq	48\(%rsp\), %rdi
 **	movq	56\(%rsp\), %r8
 **	movq	64\(%rsp\), %r9
 **	movq	72\(%rsp\), %r10
@@ -61,8 +58,8 @@
 **	movq	96\(%rsp\), %r13
 **	movq	104\(%rsp\), %r14
 **	movq	112\(%rsp\), %r15
-**	movq	120\(%rsp\), %r16
 **	movq	128\(%rsp\), %r17
+**	movq	120\(%rsp\), %r16
 **	movq	136\(%rsp\), %r18
 **	movq	144\(%rsp\), %r19
 **	movq	152\(%rsp\), %r20
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 000000000000..be3c2509fc60
--- /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 000000000000..9b6e4a508c97
--- /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 000000000000..9126d3ca2ab2
--- /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 000000000000..4c634c9d8b02
--- /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 000000000000..939f85a586bc
--- /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 000000000000..205595810aad
--- /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 ca23b586fa16..175eb25acd69 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 8e83879443fa..629bd6953747 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 2c80560887c2..6f252ee50a4c 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 } } } } */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.