On Thu, Jun 25, 2026 at 7:54 AM H.J. Lu <[email protected]> wrote:
>
> Implement TARGET_FNTYPE_ABI to avoid spills of callee-saved registers
> when calling functions with no_caller_saved_registers attribute.
>
> After
>
> commit 754c6600fe058f1026098fde57860bbc38cc28fe
> Author: Richard Sandiford <[email protected]>
> Date:   Wed Jun 3 13:11:17 2026 +0100
>
>     Add CALL_INSN_ABI_ID
>
> there is no need for ix86_expand_call to add clobbers for when one ABI
> calls another ABI.
>
> ABI_ALTERNATE is the alternate function ABI from the system ABI.  If
> ix86_abi is SYSV_ABI, ABI_ALTERNATE is the function ABI for MS_ABI.
> Otherwise, ABI_ALTERNATE is the function ABI for SYSV_ABI.
>
> This target hook also properly marks the implicit __tls_get_addr call:
>
> (call_insn/u 9 8 10 (parallel [
>             (set (reg:DI 0 ax)
>                 (call:DI (mem:QI (symbol_ref:DI ("__tls_get_addr")) [0  S1 
> A8])
>                     (const_int 0 [0])))
>             (unspec:DI [
>                     (reg/f:DI 7 sp)
>                 ] UNSPEC_TLS_LD_BASE)
>             (clobber (reg:DI 5 di))
>         ]) "x.c":7:16 -1
>      (expr_list:REG_EH_REGION (const_int -2147483648 [0xffffffff80000000])
>         (nil))
>     (nil) 0)
>
> with ABI_DEFAULT function ABI.
>
> Tested on Linux/x86-64 and with CPython 3.14.4.
>
> gcc/
>
>         PR target/124798
>         PR target/125436
>         * config/i386/i386-expand.cc: Include "function-abi.h".
>         (x86_64_ms_sysv_extra_clobbered_registers): Removed.
>         (ix86_expand_call): Don't add explicit call and ABI-switch
>         clobbers.
>         * config/i386/i386-features.cc (ix86_place_single_tls_call):
>         Set CALL_INSN_ABI_ID on TLS calls.
>         * config/i386/i386-options.cc (ix86_set_current_function): Don't
>         call reinit_regs.
>         * config/i386/i386-protos.h
>         (ix86_type_no_callee_saved_registers_p): Removed.
>         (ix86_tls_get_addr_abi): New.
>         * config/i386/i386.cc (ix86_alternate_abi): New prototype.
>         (ix86_conditional_register_usage): Changed to describe the
>         system ABI.
>         (ix86_type_no_callee_saved_registers_p): Make it static.
>         (ix86_function_value_regno_p): Replace ix86_cfun_abi () with
>         ix86_abi.
>         (ix86_save_reg): Only check TYPE_NO_CALLEE_SAVED_REGISTERS as
>         a special case.
>         (ix86_tls_get_addr_abi): New.
>         (legitimize_tls_address): Set CALL_INSN_ABI_ID on TLS calls.
>         Call ix86_alternate_abi to initialize the alternate function ABI.
>         (ix86_initialize_abi): New function.
>         (ix86_no_callee_saved_abi): Likewise.
>         (ix86_no_caller_saved_abi): Likewise.
>         (ix86_standard_abi): Likewise.
>         (ix86_alternate_abi): Likewise.
>         (ix86_function_abi_id): Likewise.
>         (ix86_fntype_abi): Likewise.
>         (ix86_hard_regno_call_part_clobbered): Handle newly added ABIs.
>         (TARGET_FNTYPE_ABI): New.
>         * config/i386/i386.md: Add ABI_ALTERNATE, ABI_NO_CALLEE_SAVED,
>         ABI_NO_CALLER_SAVED_RETURN_VOID, ABI_NO_CALLER_SAVED_RETURN_AX,
>         ABI_NO_CALLER_SAVED_RETURN_AX_DX, ABI_NO_CALLER_SAVED_RETURN_XMM0
>         and ABI_NO_CALLER_SAVED_RETURN_XMM0_XMM1.
>
> gcc/testsuite/
>
>         PR target/124798
>         PR target/125436
>         * gcc.target/i386/abi-mix-1.c: New test.
>         * gcc.target/i386/abi-mix-2.c: Likewise.
>         * gcc.target/i386/no-callee-saved-20.c: Likewise.
>         * gcc.target/i386/no-caller-saved-1-ms.c: Likewise.
>         * gcc.target/i386/no-caller-saved-1-sysv.c: Likewise.
>         * gcc.target/i386/no-caller-saved-1.c: Likewise.
>         * gcc.target/i386/no-caller-saved-2.c: Likewise.
>         * gcc.target/i386/no-caller-saved-3.c: Likewise.
>         * gcc.target/i386/no-caller-saved-4.c: Likewise.
>         * gcc.target/i386/no-caller-saved-5.c: Likewise.
>         * gcc.target/i386/no-caller-saved-6.c: Likewise.
>         * gcc.target/i386/no-caller-saved-7.c: Likewise.
>         * gcc.target/i386/pr125436-1a.c: Likewise.
>         * gcc.target/i386/pr125436-1b.c: Likewise.
>         * gcc.target/i386/pr125436-2a.c: Likewise.
>         * gcc.target/i386/pr125436-2b.c: Likewise.
>         * gcc.target/i386/pr125436-3.c: Likewise.
>         * gcc.target/i386/pr125436-4.c: Likewise.
>         * gcc.target/i386/no-callee-saved-18.c: Don't check frame
>         register.
>         * gcc.target/i386/no-callee-saved-19b.c: Update the expected
>         instruction order.
>         * gcc.target/i386/no-callee-saved-19d.c: Likewise.
>         * gcc.target/i386/no-callee-saved-19e.c: Likewise.
>         * gcc.target/i386/no-callee-saved-2.c: Check frame register isn't
>         saved nor restored in 64-bit mode.
>         * gcc.target/i386/no-callee-saved-8.c: Expect no saving nor
>         restoring caller-saved registers.
>         * gcc.target/i386/no-callee-saved-9.c: Likewise.
>         * gcc.target/i386/preserve-none-14.c: Don't check frame register.
>         * gcc.target/i386/preserve-none-23.c: Likewise.
>         * gcc.target/i386/preserve-none-7.c: Check frame register isn't
>         saved nor restored in 64-bit mode.
>
> Signed-off-by: H.J. Lu <[email protected]>
> Co-Authored by: Richard Sandiford <[email protected]>
> ---
>  gcc/config/i386/i386-expand.cc                | 113 +-----
>  gcc/config/i386/i386-features.cc              |   2 +
>  gcc/config/i386/i386-options.cc               |  17 -
>  gcc/config/i386/i386-protos.h                 |   3 +-
>  gcc/config/i386/i386.cc                       | 336 +++++++++++++++---
>  gcc/config/i386/i386.md                       |  30 +-
>  gcc/testsuite/gcc.target/i386/abi-mix-1.c     |  20 ++
>  gcc/testsuite/gcc.target/i386/abi-mix-2.c     |   6 +
>  .../gcc.target/i386/no-callee-saved-18.c      |   2 -
>  .../gcc.target/i386/no-callee-saved-19b.c     |  32 +-
>  .../gcc.target/i386/no-callee-saved-19d.c     |   6 +-
>  .../gcc.target/i386/no-callee-saved-19e.c     |  33 +-
>  .../gcc.target/i386/no-callee-saved-2.c       |  10 +-
>  .../gcc.target/i386/no-callee-saved-20.c      |  92 +++++
>  .../gcc.target/i386/no-callee-saved-8.c       |   8 +-
>  .../gcc.target/i386/no-callee-saved-9.c       |  10 +-
>  .../gcc.target/i386/no-caller-saved-1-ms.c    |  50 +++
>  .../gcc.target/i386/no-caller-saved-1-sysv.c  |  46 +++
>  .../gcc.target/i386/no-caller-saved-1.c       |  50 +++
>  .../gcc.target/i386/no-caller-saved-2.c       |  49 +++
>  .../gcc.target/i386/no-caller-saved-3.c       |  49 +++
>  .../gcc.target/i386/no-caller-saved-4.c       |  44 +++
>  .../gcc.target/i386/no-caller-saved-5.c       |  34 ++
>  .../gcc.target/i386/no-caller-saved-6.c       |  34 ++
>  .../gcc.target/i386/no-caller-saved-7.c       |  49 +++
>  gcc/testsuite/gcc.target/i386/pr125436-1a.c   | 130 +++++++
>  gcc/testsuite/gcc.target/i386/pr125436-1b.c   |  81 +++++
>  gcc/testsuite/gcc.target/i386/pr125436-2a.c   | 132 +++++++
>  gcc/testsuite/gcc.target/i386/pr125436-2b.c   |  83 +++++
>  gcc/testsuite/gcc.target/i386/pr125436-3.c    |  88 +++++
>  gcc/testsuite/gcc.target/i386/pr125436-4.c    |  88 +++++
>  .../gcc.target/i386/preserve-none-14.c        |   2 -
>  .../gcc.target/i386/preserve-none-23.c        |   2 -
>  .../gcc.target/i386/preserve-none-7.c         |  10 +-
>  34 files changed, 1503 insertions(+), 238 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/abi-mix-1.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/abi-mix-2.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-20.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1-ms.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1-sysv.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-1.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-2.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-3.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-4.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-5.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-6.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/no-caller-saved-7.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-1a.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-1b.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-2a.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-2b.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-3.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr125436-4.c
>
> diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> index 07756897fad..18b259a660d 100644
> --- a/gcc/config/i386/i386-expand.cc
> +++ b/gcc/config/i386/i386-expand.cc
> @@ -94,6 +94,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "i386-builtins.h"
>  #include "i386-expand.h"
>  #include "asan.h"
> +#include "function-abi.h"
>
>  /* Split one or more double-mode RTL references into pairs of half-mode
>     references.  The RTL can be REG, offsettable MEM, integer constant, or
> @@ -11094,17 +11095,6 @@ construct_plt_address (rtx symbol)
>    return tmp;
>  }
>
> -/* Additional registers that are clobbered by SYSV calls.  */
> -
> -static int const x86_64_ms_sysv_extra_clobbered_registers
> -                [NUM_X86_64_MS_CLOBBERED_REGS] =
> -{
> -  SI_REG, DI_REG,
> -  XMM6_REG, XMM7_REG,
> -  XMM8_REG, XMM9_REG, XMM10_REG, XMM11_REG,
> -  XMM12_REG, XMM13_REG, XMM14_REG, XMM15_REG
> -};
> -
>  rtx_insn *
>  ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
>                   rtx callarg2,
> @@ -11114,7 +11104,6 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx 
> callarg1,
>    rtx use = NULL, call;
>    unsigned int vec_len = 0;
>    tree fndecl;
> -  bool call_no_callee_saved_registers = false;
>
>    if (SYMBOL_REF_P (XEXP (fnaddr, 0)))
>      {
> @@ -11124,26 +11113,13 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx 
> callarg1,
>           if (lookup_attribute ("interrupt",
>                                 TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))
>             error ("interrupt service routine cannot be called directly");
> -         else if (ix86_type_no_callee_saved_registers_p (TREE_TYPE (fndecl)))
> -           call_no_callee_saved_registers = true;
>           if (fndecl == current_function_decl
>               && decl_binds_to_current_def_p (fndecl))
>             cfun->machine->recursive_function = true;
>         }
>      }
>    else
> -    {
> -      if (MEM_P (fnaddr))
> -       {
> -         tree mem_expr = MEM_EXPR (fnaddr);
> -         if (mem_expr != nullptr
> -             && TREE_CODE (mem_expr) == MEM_REF
> -             && ix86_type_no_callee_saved_registers_p (TREE_TYPE (mem_expr)))
> -           call_no_callee_saved_registers = true;
> -       }
> -
> -      fndecl = NULL_TREE;
> -    }
> +    fndecl = NULL_TREE;
>
>    if (pop == const0_rtx)
>      pop = NULL;
> @@ -11280,62 +11256,26 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx 
> callarg1,
>        vec[vec_len++] = pop;
>      }
>
> -  static const char ix86_call_used_regs[] = CALL_USED_REGISTERS;
> -
> -  if ((cfun->machine->call_saved_registers
> -       == TYPE_NO_CALLER_SAVED_REGISTERS)
> -      && (!fndecl
> -         || (!TREE_THIS_VOLATILE (fndecl)
> -             && !lookup_attribute ("no_caller_saved_registers",
> -                                   TYPE_ATTRIBUTES (TREE_TYPE (fndecl))))))
> +  /* Set here, but it may get cleared later.  */
> +  if (TARGET_64BIT_MS_ABI
> +      && (!callarg2 || INTVAL (callarg2) != -2)
> +      && TARGET_CALL_MS2SYSV_XLOGUES)
>      {
> -      bool is_64bit_ms_abi = (TARGET_64BIT
> -                             && ix86_function_abi (fndecl) == MS_ABI);
> -      char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi);
> -
> -      /* If there are no caller-saved registers, add all registers
> -        that are clobbered by the call which returns.  */
> -      for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> -       if (!fixed_regs[i]
> -           && (ix86_call_used_regs[i] == 1
> -               || (ix86_call_used_regs[i] & c_mask))
> -           && !STACK_REGNO_P (i)
> -           && !MMX_REGNO_P (i))
> -         clobber_reg (&use,
> -                      gen_rtx_REG (GET_MODE (regno_reg_rtx[i]), i));
> -    }
> -  else if (TARGET_64BIT_MS_ABI
> -          && (!callarg2 || INTVAL (callarg2) != -2))
> -    {
> -      unsigned i;
> +      if (!TARGET_SSE)
> +       ;
>
> -      for (i = 0; i < NUM_X86_64_MS_CLOBBERED_REGS; i++)
> -       {
> -         int regno = x86_64_ms_sysv_extra_clobbered_registers[i];
> -         machine_mode mode = SSE_REGNO_P (regno) ? TImode : DImode;
> +      /* Don't break hot-patched functions.  */
> +      else if (ix86_function_ms_hook_prologue (current_function_decl))
> +       ;
>
> -         clobber_reg (&use, gen_rtx_REG (mode, regno));
> -       }
> +      /* TODO: Cases not yet examined.  */
> +      else if (flag_split_stack)
> +       warn_once_call_ms2sysv_xlogues ("-fsplit-stack");
>
> -      /* Set here, but it may get cleared later.  */
> -      if (TARGET_CALL_MS2SYSV_XLOGUES)
> +      else
>         {
> -         if (!TARGET_SSE)
> -           ;
> -
> -         /* Don't break hot-patched functions.  */
> -         else if (ix86_function_ms_hook_prologue (current_function_decl))
> -           ;
> -
> -         /* TODO: Cases not yet examined.  */
> -         else if (flag_split_stack)
> -           warn_once_call_ms2sysv_xlogues ("-fsplit-stack");
> -
> -         else
> -           {
> -             gcc_assert (!reload_completed);
> -             cfun->machine->call_ms2sysv = true;
> -           }
> +         gcc_assert (!reload_completed);
> +         cfun->machine->call_ms2sysv = true;
>         }
>      }
>
> @@ -11353,25 +11293,6 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx 
> callarg1,
>        clobber_reg (&use, gen_rtx_REG (DImode, R10_REG));
>      }
>
> -  if (call_no_callee_saved_registers)
> -    {
> -      /* After calling a no_callee_saved_registers function, all
> -        registers may be clobbered.  Clobber all registers that are
> -        not used by the callee.  */
> -      bool is_64bit_ms_abi = (TARGET_64BIT
> -                             && ix86_function_abi (fndecl) == MS_ABI);
> -      char c_mask = CALL_USED_REGISTERS_MASK (is_64bit_ms_abi);
> -      for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> -       if (!fixed_regs[i]
> -           && i != HARD_FRAME_POINTER_REGNUM
> -           && !(ix86_call_used_regs[i] == 1
> -                || (ix86_call_used_regs[i] & c_mask))
> -           && !STACK_REGNO_P (i)
> -           && !MMX_REGNO_P (i))
> -         clobber_reg (&use,
> -                      gen_rtx_REG (GET_MODE (regno_reg_rtx[i]), i));
> -    }
> -
>    if (vec_len > 1)
>      call = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (vec_len, vec));
>    rtx_insn *call_insn = emit_call_insn (call);
> diff --git a/gcc/config/i386/i386-features.cc 
> b/gcc/config/i386/i386-features.cc
> index f5caef29c6e..aef364ba8b7 100644
> --- a/gcc/config/i386/i386-features.cc
> +++ b/gcc/config/i386/i386-features.cc
> @@ -4505,6 +4505,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
> x86_cse_kind kind,
>
>        symbol = XVECEXP (val, 0, 0);
>        tls = gen_tls_global_dynamic_64 (Pmode, rax, symbol, caddr, rdi);
> +      CALL_INSN_ABI_ID (tls) = ix86_tls_get_addr_abi ().id ();
>
>        if (GET_MODE (symbol) != Pmode)
>         symbol = gen_rtx_ZERO_EXTEND (Pmode, symbol);
> @@ -4517,6 +4518,7 @@ ix86_place_single_tls_call (rtx dest, rtx val, 
> x86_cse_kind kind,
>        caddr = ix86_tls_get_addr ();
>
>        tls = gen_tls_local_dynamic_base_64 (Pmode, rax, caddr, rdi);
> +      CALL_INSN_ABI_ID (tls) = ix86_tls_get_addr_abi ().id ();
>
>        /* Attach a unique REG_EQUAL to DEST, to allow the RTL optimizers
>          to share the LD_BASE result with other LD model accesses.  */
> diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
> index 626e1eab929..7aa9daf9ae1 100644
> --- a/gcc/config/i386/i386-options.cc
> +++ b/gcc/config/i386/i386-options.cc
> @@ -3527,21 +3527,6 @@ ix86_set_current_function (tree fndecl)
>      }
>    ix86_previous_fndecl = fndecl;
>
> -  static call_saved_registers_type prev_call_saved_registers;
> -
> -  /* 64-bit MS and SYSV ABI have different set of call used registers.
> -     Avoid expensive re-initialization of init_regs each time we switch
> -     function context.  */
> -  if (TARGET_64BIT
> -      && (call_used_or_fixed_reg_p (SI_REG)
> -         == (cfun->machine->call_abi == MS_ABI)))
> -    reinit_regs ();
> -  /* Need to re-initialize init_regs if caller-saved registers are
> -     changed.  */
> -  else if (prev_call_saved_registers
> -          != cfun->machine->call_saved_registers)
> -    reinit_regs ();
> -
>    if (cfun->machine->func_type != TYPE_NORMAL
>        || (cfun->machine->call_saved_registers
>           == TYPE_NO_CALLER_SAVED_REGISTERS))
> @@ -3589,8 +3574,6 @@ ix86_set_current_function (tree fndecl)
>             = TYPE_DEFAULT_CALL_SAVED_REGISTERS;
>         }
>      }
> -
> -  prev_call_saved_registers = cfun->machine->call_saved_registers;
>  }
>
>  /* Implement the TARGET_OFFLOAD_OPTIONS hook.  */
> diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
> index 7dac3ed8e6c..ea23f75804a 100644
> --- a/gcc/config/i386/i386-protos.h
> +++ b/gcc/config/i386/i386-protos.h
> @@ -286,7 +286,6 @@ extern tree ix86_valid_target_attribute_tree (tree, tree,
>                                               struct gcc_options *,
>                                               struct gcc_options *, bool);
>  extern unsigned int ix86_get_callcvt (const_tree);
> -extern bool ix86_type_no_callee_saved_registers_p (const_tree);
>
>  #endif
>
> @@ -295,6 +294,8 @@ extern bool ix86_gpr_tls_address_pattern_p (rtx);
>  extern bool ix86_tls_address_pattern_p (rtx);
>  extern rtx ix86_rewrite_tls_address (rtx);
>  extern rtx ix86_tls_get_addr (void);
> +class predefined_function_abi;
> +extern const predefined_function_abi & ix86_tls_get_addr_abi (void);
>
>  extern void ix86_expand_vector_init (bool, rtx, rtx);
>  extern void ix86_expand_vector_set (bool, rtx, rtx, int);
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 5bcf7254ab2..86bd6caf59f 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -107,6 +107,7 @@ along with GCC; see the file COPYING3.  If not see
>
>  static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool);
>  static void ix86_emit_restore_reg_using_pop (rtx, bool = false);
> +static const predefined_function_abi & ix86_alternate_abi (void);
>
>
>  #ifndef CHECK_STACK_LIMIT
> @@ -503,17 +504,6 @@ ix86_conditional_register_usage (void)
>  {
>    int i, c_mask;
>
> -  /* If there are no caller-saved registers, preserve all registers.
> -     except fixed_regs and registers used for function return value
> -     since aggregate_value_p checks call_used_regs[regno] on return
> -     value.  */
> -  if (cfun
> -      && (cfun->machine->call_saved_registers
> -         == TYPE_NO_CALLER_SAVED_REGISTERS))
> -    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> -      if (!fixed_regs[i] && !ix86_function_value_regno_p (i))
> -       call_used_regs[i] = 0;
> -
>    /* For 32-bit targets, disable the REX registers.  */
>    if (! TARGET_64BIT)
>      {
> @@ -525,8 +515,10 @@ ix86_conditional_register_usage (void)
>         CLEAR_HARD_REG_BIT (accessible_reg_set, i);
>      }
>
> -  /*  See the definition of CALL_USED_REGISTERS in i386.h.  */
> -  c_mask = CALL_USED_REGISTERS_MASK (TARGET_64BIT_MS_ABI);
> +  /* Set up the call-used registers based on the system ABI (ix86_abi).
> +
> +     See the definition of CALL_USED_REGISTERS in i386.h.  */
> +  c_mask = CALL_USED_REGISTERS_MASK (TARGET_64BIT && ix86_abi == MS_ABI);
>
>    CLEAR_HARD_REG_SET (reg_class_contents[(int)CLOBBERED_REGS]);
>
> @@ -932,7 +924,7 @@ x86_64_elf_unique_section (tree decl, int reloc)
>  /* Return true if TYPE has no_callee_saved_registers or preserve_none
>     attribute.  */
>
> -bool
> +static bool
>  ix86_type_no_callee_saved_registers_p (const_tree fntype)
>  {
>    auto type = ix86_fntype_call_saved_registers (fntype);
> @@ -3871,10 +3863,10 @@ ix86_function_value_regno_p (const unsigned int regno)
>        /* Complex values are returned in %st(0)/%st(1) pair.  */
>      case ST0_REG:
>      case ST1_REG:
> -      /* TODO: The function should depend on current function ABI but
> -       builtins.cc would need updating then. Therefore we use the
> -       default ABI.  */
> -      if (TARGET_64BIT && ix86_cfun_abi () == MS_ABI)
> +      /* TODO: An ABI identifier should be passed as a parameter.
> +        For now, most callers, including those in builtins.cc,
> +        expect us to use the default ABI.  */
> +      if (TARGET_64BIT && ix86_abi == MS_ABI)
>         return false;
>        return TARGET_FLOAT_RETURNS_IN_80387;
>
> @@ -6796,8 +6788,6 @@ ix86_hard_regno_scratch_ok (unsigned int regno)
>  bool
>  ix86_save_reg (unsigned int regno, bool maybe_eh_return, bool 
> ignore_outlined)
>  {
> -  rtx reg;
> -
>    /* Save and restore DRAP register between prologue and epilogue so
>       that stack pointer can be restored.  */
>    if (crtl->drap_reg
> @@ -6805,41 +6795,12 @@ ix86_save_reg (unsigned int regno, bool 
> maybe_eh_return, bool ignore_outlined)
>        && !cfun->machine->no_drap_save_restore)
>      return true;
>
> -  switch (cfun->machine->call_saved_registers)
> -    {
> -    case TYPE_DEFAULT_CALL_SAVED_REGISTERS:
> -      break;
> -
> -    case TYPE_NO_CALLER_SAVED_REGISTERS:
> -      /* If there are no caller-saved registers, we preserve all
> -        registers, except for MMX and x87 registers which aren't
> -        supported when saving and restoring registers.  Don't
> -        explicitly save SP register since it is always preserved.
> -
> -        Don't preserve registers used for function return value.  */
> -      reg = crtl->return_rtx;
> -      if (reg)
> -       {
> -         unsigned int i = REGNO (reg);
> -         unsigned int nregs = REG_NREGS (reg);
> -         while (nregs-- > 0)
> -           if ((i + nregs) == regno)
> -             return false;
> -       }
> -
> -      return (df_regs_ever_live_p (regno)
> -             && !fixed_regs[regno]
> -             && !STACK_REGNO_P (regno)
> -             && !MMX_REGNO_P (regno)
> -             && (regno != HARD_FRAME_POINTER_REGNUM
> -                 || !frame_pointer_needed));

1) Original no_caller_saved_register won't preserve mmx/x86 register,
and it's documented in gcc/doc/extend.texi:8909
But the patch changes that,  mmx/x86 registers are preserved for
no_caller_saved_register, so either we need to change the document or
the patch should be fixed.

--------------------------The testcase to reproduce the
issue.------------------------------

/* 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
-mmmx -mno-sse -mno-iamcu -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;
}

void
bar_mmx (void)
{
  v2si x;
  __asm__ volatile ("# %0" : "=y" (x));
  foo ();
  __asm__ volatile ("# %0" :: "y" (x));
}

/* { dg-final { scan-assembler-times "fstpt\[ \t\]+" 1 } } */
/* { 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 } } */
----------------------------testcase ends
-----------------------------------------------------


2) Also it ICE for the mixed aggregate return

 struct pair { long i; double d; };
 extern struct pair foo (void)
   __attribute__ ((no_caller_saved_registers, sysv_abi));

 struct pair bar (void) { return foo (); }

 with dg-do compile { target lp64 } and -O2 -msse2 -mno-avx.

> @@ -26,7 +26,9 @@ foo (void *frame)
>    }
>  }
>
> -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } 
> */
> -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */
> -/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 } } */
> -/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 } } */
> +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { 
> target ia32 } } } */
> +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 { 
> target ia32 } } } */
> +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*" 1 { target ia32 
> } } } */
> +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*" 1 { target ia32 } 
> } } */
> +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*" { target { ! ia32 
> } } } } */
> +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*" { target { ! ia32 } 
> } } } */
> --
> 2.54.0
>


--
BR,
Hongtao

Reply via email to