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