Add preserve_none attribute which is similar to no_callee_saved_registers attribute, except on x86-64, r12, r13, r14, r15, rdi and rsi registers are used for integer parameter passing. This can be used in an interpreter to avoid saving/restoring the registers in functions which processing byte codes. It improved the pystones benchmark by 6-7%:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119628#c15 Remove -mgeneral-regs-only restriction on no_caller_saved_registers attribute. Only SSE is allowed since SSE XMM register load preserves the upper bits in YMM/ZMM register while YMM register load zeros the upper 256 bits of ZMM register, and preserving 32 ZMM registers can be quite expensive. gcc/ PR target/119628 * config/i386/i386-expand.cc (ix86_expand_call): Call ix86_type_preserve_none_attribute_p instead of looking up no_callee_saved_registers attribute. * config/i386/i386-options.cc (ix86_set_func_type): Call ix86_type_preserve_none_attribute_p instead of looking up no_callee_saved_registers attribute. Check preserve_none attribute for interrupt attribute. Don't check no_caller_saved_registers and no_callee_saved_registers conflicts here. (ix86_set_current_function): Allow SSE with no_caller_saved_registers attribute. (ix86_handle_call_saved_registers_attribute): Check preserve_none, no_callee_saved_registers and no_caller_saved_registers conflicts. (ix86_gnu_attributes): Add preserve_none attribute. * config/i386/i386-protos.h (ix86_type_preserve_none_attribute_p): New. * config/i386/i386.cc (x86_64_preserve_none_int_parameter_registers): New. (ix86_using_red_zone): Don't use red-zone when there are no caller-saved registers with SSE. (ix86_type_preserve_none_attribute_p): New. (ix86_function_ok_for_sibcall): Call ix86_type_preserve_none_attribute_p instead of looking up no_callee_saved_registers attribute. (ix86_comp_type_attributes): Call ix86_type_preserve_none_attribute_p instead of looking up no_callee_saved_registers attribute. Return 0 if preserve_none attribute doesn't match in 64-bit mode. (ix86_function_arg_regno_p): If preserve_none calling convention is used, use x86_64_preserve_none_int_parameter_registers. (ix86_call_abi_override): Also set the preserve_none_abi field. (init_cumulative_args): Likewise. (function_arg_64): Use x86_64_preserve_none_int_parameter_registers with preserve_none attribute. (setup_incoming_varargs_64): Use x86_64_preserve_none_int_parameter_registers with preserve_none attribute. (ix86_nsaved_sseregs): Allow saving XMM registers for no_caller_saved_registers attribute. (ix86_compute_frame_layout): Likewise. (x86_this_parameter): Use x86_64_preserve_none_int_parameter_registers with preserve_none attribute. * config/i386/i386.h (ix86_args): Add preserve_none_abi. (call_saved_registers_type): Update comments for TYPE_NO_CALLEE_SAVED_REGISTERS. (machine_function): Add preserve_none_abi. * doc/extend.texi: Add preserve_none attribute. Update no_caller_saved_registers attribute to remove -mgeneral-regs-only restriction. gcc/testsuite/ PR target/119628 * gcc.target/i386/no-callee-saved-19a.c: New test. * gcc.target/i386/no-callee-saved-19b.c: Likewise. * gcc.target/i386/no-callee-saved-19c.c: Likewise. * gcc.target/i386/no-callee-saved-19d.c: Likewise. * gcc.target/i386/no-callee-saved-19e.c: Likewise. * gcc.target/i386/preserve-none-1.c: Likewise. * gcc.target/i386/preserve-none-2.c: Likewise. * gcc.target/i386/preserve-none-3.c: Likewise. * gcc.target/i386/preserve-none-4.c: Likewise. * gcc.target/i386/preserve-none-5.c: Likewise. * gcc.target/i386/preserve-none-6.c: Likewise. * gcc.target/i386/preserve-none-7.c: Likewise. * gcc.target/i386/preserve-none-8.c: Likewise. * gcc.target/i386/preserve-none-9.c: Likewise. * gcc.target/i386/preserve-none-10.c: Likewise. * gcc.target/i386/preserve-none-11.c: Likewise. * gcc.target/i386/preserve-none-12.c: Likewise. * gcc.target/i386/preserve-none-13.c: Likewise. * gcc.target/i386/preserve-none-14.c: Likewise. * gcc.target/i386/preserve-none-15.c: Likewise. * gcc.target/i386/preserve-none-16.c: Likewise. * gcc.target/i386/preserve-none-17.c: Likewise. * gcc.target/i386/preserve-none-19.c: Likewise. * gcc.target/i386/preserve-none-19.c: Likewise. * gcc.target/i386/preserve-none-20.c: Likewise. * gcc.target/i386/preserve-none-21.c: Likewise. * gcc.target/i386/preserve-none-22.c: Likewise. * gcc.target/i386/preserve-none-23.c: Likewise. * gcc.target/i386/preserve-none-24.c: Likewise. * gcc.target/i386/preserve-none-25.c: Likewise. * gcc.target/i386/preserve-none-26.c: Likewise. * gcc.target/i386/preserve-none-27.c: Likewise. * gcc.target/i386/preserve-none-28.c: Likewise. * gcc.target/i386/preserve-none-29.c: Likewise. * gcc.target/i386/preserve-none-30a.c: Likewise. * gcc.target/i386/preserve-none-30b.c: Likewise. Signed-off-by: H.J. Lu <hjl.to...@gmail.com> --- gcc/config/i386/i386-expand.cc | 6 +- gcc/config/i386/i386-options.cc | 90 ++++++++-- gcc/config/i386/i386-protos.h | 1 + gcc/config/i386/i386.cc | 105 +++++++++-- gcc/config/i386/i386.h | 7 +- gcc/doc/extend.texi | 14 +- .../gcc.target/i386/no-callee-saved-19a.c | 166 ++++++++++++++++++ .../gcc.target/i386/no-callee-saved-19b.c | 129 ++++++++++++++ .../gcc.target/i386/no-callee-saved-19c.c | 94 ++++++++++ .../gcc.target/i386/no-callee-saved-19d.c | 159 +++++++++++++++++ .../gcc.target/i386/no-callee-saved-19e.c | 162 +++++++++++++++++ .../gcc.target/i386/no-callee-saved-3.c | 4 +- .../gcc.target/i386/preserve-none-1.c | 17 ++ .../gcc.target/i386/preserve-none-10.c | 11 ++ .../gcc.target/i386/preserve-none-11.c | 12 ++ .../gcc.target/i386/preserve-none-12.c | 49 ++++++ .../gcc.target/i386/preserve-none-13.c | 50 ++++++ .../gcc.target/i386/preserve-none-14.c | 49 ++++++ .../gcc.target/i386/preserve-none-15.c | 46 +++++ .../gcc.target/i386/preserve-none-16.c | 11 ++ .../gcc.target/i386/preserve-none-17.c | 10 ++ .../gcc.target/i386/preserve-none-18.c | 17 ++ .../gcc.target/i386/preserve-none-19.c | 17 ++ .../gcc.target/i386/preserve-none-2.c | 12 ++ .../gcc.target/i386/preserve-none-20.c | 18 ++ .../gcc.target/i386/preserve-none-21.c | 16 ++ .../gcc.target/i386/preserve-none-22.c | 17 ++ .../gcc.target/i386/preserve-none-23.c | 51 ++++++ .../gcc.target/i386/preserve-none-24.c | 8 + .../gcc.target/i386/preserve-none-25.c | 27 +++ .../gcc.target/i386/preserve-none-26.c | 27 +++ .../gcc.target/i386/preserve-none-27.c | 33 ++++ .../gcc.target/i386/preserve-none-28.c | 48 +++++ .../gcc.target/i386/preserve-none-29.c | 57 ++++++ .../gcc.target/i386/preserve-none-3.c | 18 ++ .../gcc.target/i386/preserve-none-30a.c | 31 ++++ .../gcc.target/i386/preserve-none-30b.c | 21 +++ .../gcc.target/i386/preserve-none-4.c | 19 ++ .../gcc.target/i386/preserve-none-5.c | 18 ++ .../gcc.target/i386/preserve-none-6.c | 30 ++++ .../gcc.target/i386/preserve-none-7.c | 30 ++++ .../gcc.target/i386/preserve-none-8.c | 8 + .../gcc.target/i386/preserve-none-9.c | 8 + 43 files changed, 1675 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-19a.c create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-19c.c create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c create mode 100644 gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-1.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-10.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-11.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-12.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-13.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-14.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-15.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-16.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-17.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-18.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-19.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-2.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-20.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-21.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-22.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-23.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-24.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-25.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-26.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-27.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-28.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-29.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-3.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-30a.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-30b.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-4.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-5.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-6.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-7.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-8.c create mode 100644 gcc/testsuite/gcc.target/i386/preserve-none-9.c diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index cdfd94d3c73..0f12b34db6c 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -10108,8 +10108,7 @@ 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 (lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + else if (ix86_type_preserve_none_attribute_p (TREE_TYPE (fndecl))) call_no_callee_saved_registers = true; } } @@ -10120,8 +10119,7 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1, tree mem_expr = MEM_EXPR (fnaddr); if (mem_expr != nullptr && TREE_CODE (mem_expr) == MEM_REF - && lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (TREE_TYPE (mem_expr)))) + && ix86_type_preserve_none_attribute_p (TREE_TYPE (mem_expr))) call_no_callee_saved_registers = true; } diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc index 964449fa8cd..2238fb904f8 100644 --- a/gcc/config/i386/i386-options.cc +++ b/gcc/config/i386/i386-options.cc @@ -3420,8 +3420,7 @@ ix86_set_func_type (tree fndecl) interrupt function in this case. */ enum call_saved_registers_type no_callee_saved_registers = TYPE_DEFAULT_CALL_SAVED_REGISTERS; - if (lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + if (ix86_type_preserve_none_attribute_p (TREE_TYPE (fndecl))) no_callee_saved_registers = TYPE_NO_CALLEE_SAVED_REGISTERS; else if (ix86_noreturn_no_callee_saved_registers && TREE_THIS_VOLATILE (fndecl) @@ -3444,9 +3443,17 @@ ix86_set_func_type (tree fndecl) "interrupt and naked attributes are not compatible"); if (no_callee_saved_registers) - error_at (DECL_SOURCE_LOCATION (fndecl), - "%qs and %qs attributes are not compatible", - "interrupt", "no_callee_saved_registers"); + { + const char *attr; + if (lookup_attribute ("preserve_none", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))) + attr = "preserve_none"; + else + attr = "no_callee_saved_registers"; + error_at (DECL_SOURCE_LOCATION (fndecl), + "%qs and %qs attributes are not compatible", + "interrupt", attr); + } int nargs = 0; for (tree arg = DECL_ARGUMENTS (fndecl); @@ -3473,16 +3480,8 @@ ix86_set_func_type (tree fndecl) cfun->machine->call_saved_registers = TYPE_NO_CALLER_SAVED_REGISTERS; if (no_callee_saved_registers) - { - if (cfun->machine->call_saved_registers - == TYPE_NO_CALLER_SAVED_REGISTERS) - error_at (DECL_SOURCE_LOCATION (fndecl), - "%qs and %qs attributes are not compatible", - "no_caller_saved_registers", - "no_callee_saved_registers"); - cfun->machine->call_saved_registers - = no_callee_saved_registers; - } + cfun->machine->call_saved_registers + = no_callee_saved_registers; } } } @@ -3671,11 +3670,21 @@ ix86_set_current_function (tree fndecl) || (cfun->machine->call_saved_registers == TYPE_NO_CALLER_SAVED_REGISTERS)) { - /* Don't allow SSE, MMX nor x87 instructions since they - may change processor state. */ + /* Don't allow AVX, AVX512, MMX nor x87 instructions since they + may change processor state. Don't allow SSE instructions in + exception/interrupt service routines. */ const char *isa; if (TARGET_SSE) - isa = "SSE"; + { + if (TARGET_AVX512F) + isa = "AVX512"; + else if (TARGET_AVX) + isa = "AVX"; + else if (cfun->machine->func_type != TYPE_NORMAL) + isa = "SSE"; + else + isa = NULL; + } else if (TARGET_MMX) isa = "MMX/3Dnow"; else if (TARGET_80387) @@ -4100,9 +4109,50 @@ ix86_handle_fndecl_attribute (tree *node, tree name, tree args, int, } static tree -ix86_handle_call_saved_registers_attribute (tree *, tree, tree, +ix86_handle_call_saved_registers_attribute (tree *node, tree name, tree, int, bool *) { + const char *attr1 = nullptr; + const char *attr2 = nullptr; + + if (is_attribute_p ("no_callee_saved_registers", name)) + { + /* Disallow preserve_none and no_caller_saved_registers + attributes. */ + attr1 = "no_callee_saved_registers"; + if (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (*node))) + attr2 = "preserve_none"; + else if (lookup_attribute ("no_caller_saved_registers", + TYPE_ATTRIBUTES (*node))) + attr2 = "no_caller_saved_registers"; + } + else if (is_attribute_p ("no_caller_saved_registers", name)) + { + /* Disallow preserve_none and no_callee_saved_registers + attributes. */ + attr1 = "no_caller_saved_registers"; + if (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (*node))) + attr2 = "preserve_none"; + else if (lookup_attribute ("no_callee_saved_registers", + TYPE_ATTRIBUTES (*node))) + attr2 = "no_callee_saved_registers"; + } + else if (is_attribute_p ("preserve_none", name)) + { + /* Disallow no_callee_saved_registers and no_caller_saved_registers + attributes. */ + attr1 = "preserve_none"; + if (lookup_attribute ("no_callee_saved_registers", + TYPE_ATTRIBUTES (*node))) + attr2 = "no_caller_saved_registers"; + else if (lookup_attribute ("no_callee_saved_registers", + TYPE_ATTRIBUTES (*node))) + attr2 = "no_callee_saved_registers"; + } + + if (attr2) + error ("%qs and %qs attributes are not compatible", attr1, attr2); + return NULL_TREE; } @@ -4264,6 +4314,8 @@ static const attribute_spec ix86_gnu_attributes[] = ix86_handle_interrupt_attribute, NULL }, { "no_caller_saved_registers", 0, 0, false, true, true, false, ix86_handle_call_saved_registers_attribute, NULL }, + { "preserve_none", 0, 0, false, true, true, true, + ix86_handle_call_saved_registers_attribute, NULL }, { "no_callee_saved_registers", 0, 0, false, true, true, true, ix86_handle_call_saved_registers_attribute, NULL }, { "naked", 0, 0, true, false, false, false, diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index bea3fd4b2e2..f4190945e69 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -280,6 +280,7 @@ 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_preserve_none_attribute_p (const_tree); #endif diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 38df84f7db2..5ccb52188c7 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -334,6 +334,14 @@ static int const x86_64_ms_abi_int_parameter_registers[4] = CX_REG, DX_REG, R8_REG, R9_REG }; +/* The same as Clang's preserve_none function parameter passing. + NB: Use DI_REG and SI_REG, see ix86_function_value_regno_p. */ + +static int const x86_64_preserve_none_int_parameter_registers[6] = +{ + R12_REG, R13_REG, R14_REG, R15_REG, DI_REG, SI_REG +}; + static int const x86_64_int_return_registers[4] = { AX_REG, DX_REG, DI_REG, SI_REG @@ -459,7 +467,8 @@ int ix86_arch_specified; red-zone. NB: Don't use red-zone for functions with no_caller_saved_registers - and 32 GPRs since 128-byte red-zone is too small for 31 GPRs. + and 32 GPRs or 16 XMM registers since 128-byte red-zone is too small + for 31 GPRs or 15 GPRs + 16 XMM registers. TODO: If we can reserve the first 2 WORDs, for PUSH and, another for CALL, in red-zone, we can allow local indirect jumps with @@ -470,7 +479,7 @@ ix86_using_red_zone (void) { return (TARGET_RED_ZONE && !TARGET_64BIT_MS_ABI - && (!TARGET_APX_EGPR + && ((!TARGET_APX_EGPR && !TARGET_SSE) || (cfun->machine->call_saved_registers != TYPE_NO_CALLER_SAVED_REGISTERS)) && (!cfun->machine->has_local_indirect_jump @@ -897,6 +906,18 @@ x86_64_elf_unique_section (tree decl, int reloc) default_unique_section (decl, reloc); } +/* Return true if TYPE has no_callee_saved_registers or preserve_none + attribute. */ + +bool +ix86_type_preserve_none_attribute_p (const_tree type) +{ + return (lookup_attribute ("no_callee_saved_registers", + TYPE_ATTRIBUTES (type)) != NULL + || lookup_attribute ("preserve_none", + TYPE_ATTRIBUTES (type)) != NULL); +} + #ifdef COMMON_ASM_OP #ifndef LARGECOMM_SECTION_ASM_OP @@ -1021,8 +1042,7 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) if (cfun->machine->call_saved_registers != TYPE_NO_CALLEE_SAVED_REGISTERS && (cfun->machine->call_saved_registers != TYPE_NO_CALLEE_SAVED_REGISTERS_EXCEPT_BP) - && lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (type))) + && ix86_type_preserve_none_attribute_p (type)) return false; /* If outgoing reg parm stack space changes, we cannot do sibcall. */ @@ -1187,10 +1207,16 @@ ix86_comp_type_attributes (const_tree type1, const_tree type2) != ix86_function_regparm (type2, NULL)) return 0; - if (lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (type1)) - != lookup_attribute ("no_callee_saved_registers", - TYPE_ATTRIBUTES (type2))) + if (ix86_type_preserve_none_attribute_p (type1) + != ix86_type_preserve_none_attribute_p (type2)) + return 0; + + /* preserve_none attribute uses a different calling convention is + only for 64-bit. */ + if (TARGET_64BIT + && (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (type1)) + != lookup_attribute ("preserve_none", + TYPE_ATTRIBUTES (type2)))) return 0; return 1; @@ -1552,7 +1578,9 @@ ix86_function_arg_regno_p (int regno) if (call_abi == SYSV_ABI && regno == AX_REG) return true; - if (call_abi == MS_ABI) + if (cfun && cfun->machine->preserve_none_abi) + parm_regs = x86_64_preserve_none_int_parameter_registers; + else if (call_abi == MS_ABI) parm_regs = x86_64_ms_abi_int_parameter_registers; else parm_regs = x86_64_int_parameter_registers; @@ -1722,6 +1750,11 @@ void ix86_call_abi_override (const_tree fndecl) { cfun->machine->call_abi = ix86_function_abi (fndecl); + cfun->machine->preserve_none_abi + = (fndecl + && (lookup_attribute ("preserve_none", + TYPE_ATTRIBUTES (TREE_TYPE (fndecl))) + != nullptr)); } /* Return 1 if pseudo register should be created and used to hold @@ -1822,6 +1855,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ memset (cum, 0, sizeof (*cum)); + tree preserve_none_type; if (fndecl) { target = cgraph_node::get (fndecl); @@ -1830,12 +1864,24 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ target = target->function_symbol (); local_info_node = cgraph_node::local_info_node (target->decl); cum->call_abi = ix86_function_abi (target->decl); + preserve_none_type = TREE_TYPE (target->decl); } else - cum->call_abi = ix86_function_abi (fndecl); + { + cum->call_abi = ix86_function_abi (fndecl); + preserve_none_type = TREE_TYPE (fndecl); + } } else - cum->call_abi = ix86_function_type_abi (fntype); + { + cum->call_abi = ix86_function_type_abi (fntype); + preserve_none_type = fntype; + } + cum->preserve_none_abi + = (preserve_none_type + && (lookup_attribute ("preserve_none", + TYPE_ATTRIBUTES (preserve_none_type)) + != nullptr)); cum->caller = caller; @@ -3409,9 +3455,15 @@ function_arg_64 (const CUMULATIVE_ARGS *cum, machine_mode mode, break; } + const int *parm_regs; + if (cum->preserve_none_abi) + parm_regs = x86_64_preserve_none_int_parameter_registers; + else + parm_regs = x86_64_int_parameter_registers; + return construct_container (mode, orig_mode, type, 0, cum->nregs, cum->sse_nregs, - &x86_64_int_parameter_registers [cum->regno], + &parm_regs[cum->regno], cum->sse_regno); } @@ -4576,6 +4628,12 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) if (max > X86_64_REGPARM_MAX) max = X86_64_REGPARM_MAX; + const int *parm_regs; + if (cum->preserve_none_abi) + parm_regs = x86_64_preserve_none_int_parameter_registers; + else + parm_regs = x86_64_int_parameter_registers; + for (i = cum->regno; i < max; i++) { mem = gen_rtx_MEM (word_mode, @@ -4583,8 +4641,7 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) MEM_NOTRAP_P (mem) = 1; set_mem_alias_set (mem, set); emit_move_insn (mem, - gen_rtx_REG (word_mode, - x86_64_int_parameter_registers[i])); + gen_rtx_REG (word_mode, parm_regs[i])); } if (ix86_varargs_fpr_size) @@ -6779,7 +6836,9 @@ ix86_nsaved_sseregs (void) int nregs = 0; int regno; - if (!TARGET_64BIT_MS_ABI) + if (!TARGET_64BIT_MS_ABI + && (cfun->machine->call_saved_registers + != TYPE_NO_CALLER_SAVED_REGISTERS)) return 0; for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) if (SSE_REGNO_P (regno) && ix86_save_reg (regno, true, true)) @@ -6967,12 +7026,18 @@ ix86_compute_frame_layout (void) gcc_assert (preferred_alignment >= STACK_BOUNDARY / BITS_PER_UNIT); gcc_assert (preferred_alignment <= stack_alignment_needed); - /* The only ABI saving SSE regs should be 64-bit ms_abi. */ - gcc_assert (TARGET_64BIT || !frame->nsseregs); + /* The only ABI saving SSE regs should be 64-bit ms_abi or with + no_caller_saved_registers attribue. */ + gcc_assert (TARGET_64BIT + || (cfun->machine->call_saved_registers + == TYPE_NO_CALLER_SAVED_REGISTERS) + || !frame->nsseregs); if (TARGET_64BIT && m->call_ms2sysv) { gcc_assert (stack_alignment_needed >= 16); - gcc_assert (!frame->nsseregs); + gcc_assert ((cfun->machine->call_saved_registers + == TYPE_NO_CALLER_SAVED_REGISTERS) + || !frame->nsseregs); } /* For SEH we have to limit the amount of code movement into the prologue. @@ -22833,7 +22898,9 @@ x86_this_parameter (tree function) { const int *parm_regs; - if (ix86_function_type_abi (type) == MS_ABI) + if (lookup_attribute ("preserve_none", TYPE_ATTRIBUTES (type))) + parm_regs = x86_64_preserve_none_int_parameter_registers; + else if (ix86_function_type_abi (type) == MS_ABI) parm_regs = x86_64_ms_abi_int_parameter_registers; else parm_regs = x86_64_int_parameter_registers; diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 8507243d726..3b5c9520ddf 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1682,6 +1682,8 @@ typedef struct ix86_args { int stdarg; /* Set to 1 if function is stdarg. */ enum calling_abi call_abi; /* Set to SYSV_ABI for sysv abi. Otherwise MS_ABI for ms abi. */ + bool preserve_none_abi; /* Set to true if the preserve_none ABI is + used. */ tree decl; /* Callee decl. */ } CUMULATIVE_ARGS; @@ -2782,7 +2784,7 @@ enum call_saved_registers_type or "no_caller_saved_registers" attribute. */ TYPE_NO_CALLER_SAVED_REGISTERS, /* The current function is a function specified with the - "no_callee_saved_registers" attribute. */ + "no_callee_saved_registers"/"preserve_none" attribute. */ TYPE_NO_CALLEE_SAVED_REGISTERS, /* The current function is a function specified with the "noreturn" attribute. */ @@ -2816,6 +2818,9 @@ struct GTY(()) machine_function { to be used. MS_ABI means ms abi. Otherwise SYSV_ABI means sysv abi. */ ENUM_BITFIELD(calling_abi) call_abi : 8; + /* True if the preserve_none ABI is used. */ + BOOL_BITFIELD preserve_none_abi : 1; + /* Nonzero if the function accesses a previous frame. */ BOOL_BITFIELD accesses_prev_frame : 1; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 0978c4c41b2..4be531bb4fc 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -6117,6 +6117,13 @@ registers. For example, this attribute can be used for a function called from the interrupt handler assembly stub which will preserve all registers and return from interrupt. +@cindex @code{preserve_none} function attribute, x86 +@item preserve_none +This attribute is similar to @code{no_callee_saved_registers}, except +on x86-64, r12, r13, r14, r15, rdi and rsi registers are used for +integer parameter passing and this calling convention is subject to +change. + @cindex @code{no_caller_saved_registers} function attribute, x86 @item no_caller_saved_registers Use this attribute to indicate that the specified function has no @@ -6124,9 +6131,10 @@ caller-saved registers. That is, all registers are callee-saved. For example, this attribute can be used for a function called from an interrupt handler. The compiler generates proper function entry and exit sequences to save and restore any modified registers, except for -the EFLAGS register. Since GCC doesn't preserve SSE, MMX nor x87 -states, the GCC option @option{-mgeneral-regs-only} should be used to -compile functions with @code{no_caller_saved_registers} attribute. +the EFLAGS register. Since GCC doesn't preserve YMM nor ZMM registers, +@code{no_caller_saved_registers} attribute can't be used on functions +with AVX enabled. Note that MMX and x87 registers aren't preserved by +@code{no_caller_saved_registers} attribute. @cindex @code{interrupt} function attribute, x86 @item interrupt diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19a.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-19a.c new file mode 100644 index 00000000000..25ef8558a5d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19a.c @@ -0,0 +1,166 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* end must be empty. */ + +/* +**end: +**.LFB[0-9]+: +** .cfi_startproc +** ret +** .cfi_endproc +**... +*/ + +#define NEXT { op_t *op = next; [[gnu::musttail]] return (*op)(op + 1); } +#ifdef __x86_64__ +# define CLOBBER asm("" ::: "r12","r13","r14","r15","rbp","rbx") +#else +# define CLOBBER asm("" ::: "ebp","ebx") +#endif +#define DONT_SAVE_REGS __attribute__((no_callee_saved_registers)) +#define SAVE_REGS __attribute__((no_caller_saved_registers)) + +typedef DONT_SAVE_REGS void (*op_t)(void *next); + +extern int accumulator; + +static DONT_SAVE_REGS void end(void *next) +{ +} + +/* inc doesn't have any callee saved registers. */ + +/* +**inc: +**.LFB[0-9]+: +** .cfi_startproc +** addl \$1, accumulator\(%rip\) +** movq \(%rdi\), %rax +** addq \$8, %rdi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +static DONT_SAVE_REGS void inc(void *next) +{ + accumulator += 1; + CLOBBER; + NEXT; +} + +/* dec doesn't have any callee saved registers. */ + +/* +**dec: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$1, accumulator\(%rip\) +** movq \(%rdi\), %rax +** addq \$8, %rdi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +static DONT_SAVE_REGS void dec(void *next) +{ + accumulator -= 1; + CLOBBER; + NEXT; +} + +op_t code[] = { inc, inc, dec, end, }; + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subq \$376, %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\+8, %edi +** movq %rbp, 304\(%rsp\) +** movq %r8, 312\(%rsp\) +** movq %r9, 320\(%rsp\) +** movq %r10, 328\(%rsp\) +** movq %r11, 336\(%rsp\) +** movq %r12, 344\(%rsp\) +** movq %r13, 352\(%rsp\) +** movq %r14, 360\(%rsp\) +** movq %r15, 368\(%rsp\) +** movaps %xmm0, \(%rsp\) +** movaps %xmm1, 16\(%rsp\) +** movaps %xmm2, 32\(%rsp\) +** movaps %xmm3, 48\(%rsp\) +** movaps %xmm4, 64\(%rsp\) +** movaps %xmm5, 80\(%rsp\) +** movaps %xmm6, 96\(%rsp\) +** movaps %xmm7, 112\(%rsp\) +** movaps %xmm8, 128\(%rsp\) +** movaps %xmm9, 144\(%rsp\) +** movaps %xmm10, 160\(%rsp\) +** movaps %xmm11, 176\(%rsp\) +** movaps %xmm12, 192\(%rsp\) +** movaps %xmm13, 208\(%rsp\) +** movaps %xmm14, 224\(%rsp\) +** movaps %xmm15, 240\(%rsp\) +**... +** call \*code\(%rip\) +** movaps \(%rsp\), %xmm0 +** movaps 16\(%rsp\), %xmm1 +** movaps 32\(%rsp\), %xmm2 +** movaps 48\(%rsp\), %xmm3 +** movaps 64\(%rsp\), %xmm4 +** movaps 80\(%rsp\), %xmm5 +** movaps 96\(%rsp\), %xmm6 +** movaps 112\(%rsp\), %xmm7 +** movaps 128\(%rsp\), %xmm8 +** movaps 144\(%rsp\), %xmm9 +** movaps 160\(%rsp\), %xmm10 +** movaps 176\(%rsp\), %xmm11 +** movaps 192\(%rsp\), %xmm12 +** movaps 208\(%rsp\), %xmm13 +** movq 256\(%rsp\), %rax +** movq 264\(%rsp\), %rdx +** movq 272\(%rsp\), %rcx +** movq 280\(%rsp\), %rbx +** movq 288\(%rsp\), %rsi +** movq 296\(%rsp\), %rdi +** movq 304\(%rsp\), %rbp +** movq 312\(%rsp\), %r8 +** movq 320\(%rsp\), %r9 +** movq 328\(%rsp\), %r10 +** movq 336\(%rsp\), %r11 +** movq 344\(%rsp\), %r12 +** movq 352\(%rsp\), %r13 +** movq 360\(%rsp\), %r14 +** movaps 224\(%rsp\), %xmm14 +** movq 368\(%rsp\), %r15 +** movaps 240\(%rsp\), %xmm15 +** addq \$376, %rsp +**... +** ret +** .cfi_endproc +**... +*/ + +/* This function should have normal ABI to interoperate with others */ +SAVE_REGS void start() +{ + void *next = code; + + // musttail doesn't work here because the registers need to be restored + code[0](code + 1); +} diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c new file mode 100644 index 00000000000..c9343a65470 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19b.c @@ -0,0 +1,129 @@ +/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */ +/* { dg-options "-O2 -mx32 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* end must be empty. */ + +/* +**end: +**.LFB[0-9]+: +** .cfi_startproc +** ret +** .cfi_endproc +**... +*/ + +/* inc doesn't have any callee saved registers. */ + +/* +**inc: +**.LFB[0-9]+: +** .cfi_startproc +** addl \$1, accumulator\(%rip\) +** movq %rdi, %rax +** movl \(%eax\), %eax +** leal 4\(%rdi\), %edi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* dec doesn't have any callee saved registers. */ + +/* +**dec: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$1, accumulator\(%rip\) +** movq %rdi, %rax +** movl \(%eax\), %eax +** leal 4\(%rdi\), %edi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$376, %esp +**... +** movq %rax, 256\(%rsp\) +** movq %rdx, 264\(%rsp\) +** movq %rcx, 272\(%rsp\) +** movq %rbx, 280\(%rsp\) +** movq %rsi, 288\(%rsp\) +** movq %rdi, 296\(%rsp\) +**... +** movl \$code\+4, %edi +** movq %rbp, 304\(%rsp\) +** movq %r8, 312\(%rsp\) +** movq %r9, 320\(%rsp\) +** movq %r10, 328\(%rsp\) +** movq %r11, 336\(%rsp\) +** movq %r12, 344\(%rsp\) +** movq %r13, 352\(%rsp\) +** movq %r14, 360\(%rsp\) +** movq %r15, 368\(%rsp\) +** movaps %xmm0, \(%rsp\) +** movaps %xmm1, 16\(%rsp\) +** movaps %xmm2, 32\(%rsp\) +** movaps %xmm3, 48\(%rsp\) +** movaps %xmm4, 64\(%rsp\) +** movaps %xmm5, 80\(%rsp\) +** movaps %xmm6, 96\(%rsp\) +** movaps %xmm7, 112\(%rsp\) +** movaps %xmm8, 128\(%rsp\) +** movaps %xmm9, 144\(%rsp\) +** movaps %xmm10, 160\(%rsp\) +** movaps %xmm11, 176\(%rsp\) +** movaps %xmm12, 192\(%rsp\) +** movaps %xmm13, 208\(%rsp\) +** movaps %xmm14, 224\(%rsp\) +** movaps %xmm15, 240\(%rsp\) +**... +** movl code\(%rip\), %ebp +** call \*%rbp +** movaps \(%rsp\), %xmm0 +** movaps 16\(%rsp\), %xmm1 +** movaps 32\(%rsp\), %xmm2 +** movaps 48\(%rsp\), %xmm3 +** movaps 64\(%rsp\), %xmm4 +** movaps 80\(%rsp\), %xmm5 +** movaps 96\(%rsp\), %xmm6 +** movaps 112\(%rsp\), %xmm7 +** movaps 128\(%rsp\), %xmm8 +** movaps 144\(%rsp\), %xmm9 +** movaps 160\(%rsp\), %xmm10 +** movaps 176\(%rsp\), %xmm11 +** movaps 192\(%rsp\), %xmm12 +** movaps 208\(%rsp\), %xmm13 +** movaps 224\(%rsp\), %xmm14 +** movaps 240\(%rsp\), %xmm15 +** movq 256\(%rsp\), %rax +** movq 264\(%rsp\), %rdx +** movq 272\(%rsp\), %rcx +** movq 280\(%rsp\), %rbx +** movq 288\(%rsp\), %rsi +** movq 296\(%rsp\), %rdi +** movq 304\(%rsp\), %rbp +** movq 312\(%rsp\), %r8 +** movq 320\(%rsp\), %r9 +** movq 328\(%rsp\), %r10 +** movq 336\(%rsp\), %r11 +** movq 344\(%rsp\), %r12 +** movq 352\(%rsp\), %r13 +** movq 360\(%rsp\), %r14 +** movq 368\(%rsp\), %r15 +** addl \$376, %esp +**... +** ret +** .cfi_endproc +**... +*/ + +#include "no-callee-saved-19a.c" diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19c.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-19c.c new file mode 100644 index 00000000000..2ad388d1a56 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19c.c @@ -0,0 +1,94 @@ +/* { dg-do compile { target { *-*-linux* && ia32 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* end must be empty. */ + +/* +**end: +**.LFB[0-9]+: +** .cfi_startproc +** ret +** .cfi_endproc +**... +*/ + +/* inc doesn't have any callee saved registers. */ + +/* +**inc: +**.LFB[0-9]+: +** .cfi_startproc +** addl \$1, accumulator +** movl 4\(%esp\), %eax +** leal 4\(%eax\), %edx +** movl %edx, 4\(%esp\) +** jmp \*\(%eax\) +** .cfi_endproc +**... +*/ + +/* dec doesn't have any callee saved registers. */ + +/* +**dec: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$1, accumulator +** movl 4\(%esp\), %eax +** leal 4\(%eax\), %edx +** movl %edx, 4\(%esp\) +** jmp \*\(%eax\) +** .cfi_endproc +**... +*/ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +**... +** movl %eax, 140\(%esp\) +** movl %edx, 144\(%esp\) +** movl %ecx, 148\(%esp\) +** movl %ebx, 152\(%esp\) +** movl %esi, 156\(%esp\) +** movl %edi, 160\(%esp\) +** movl %ebp, 164\(%esp\) +** movaps %xmm0, 12\(%esp\) +** movaps %xmm1, 28\(%esp\) +** movaps %xmm2, 44\(%esp\) +** movaps %xmm3, 60\(%esp\) +** movaps %xmm4, 76\(%esp\) +** movaps %xmm5, 92\(%esp\) +** movaps %xmm6, 108\(%esp\) +** movaps %xmm7, 124\(%esp\) +**... +** pushl \$code\+4 +**... +** call \*code +** movaps 16\(%esp\), %xmm0 +** movaps 32\(%esp\), %xmm1 +** movaps 48\(%esp\), %xmm2 +** movaps 64\(%esp\), %xmm3 +** movaps 80\(%esp\), %xmm4 +** movaps 96\(%esp\), %xmm5 +** movaps 112\(%esp\), %xmm6 +** movaps 128\(%esp\), %xmm7 +** movl 144\(%esp\), %eax +** movl 148\(%esp\), %edx +** movl 152\(%esp\), %ecx +** movl 156\(%esp\), %ebx +** movl 160\(%esp\), %esi +** movl 164\(%esp\), %edi +** movl 168\(%esp\), %ebp +**... +** ret +** .cfi_endproc +**... +*/ + +#include "no-callee-saved-19a.c" diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c new file mode 100644 index 00000000000..a18d12e5899 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19d.c @@ -0,0 +1,159 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mapxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* end must be empty. */ + +/* +**end: +**.LFB[0-9]+: +** .cfi_startproc +** ret +** .cfi_endproc +**... +*/ + +/* inc doesn't have any callee saved registers. */ + +/* +**inc: +**.LFB[0-9]+: +** .cfi_startproc +** addl \$1, accumulator\(%rip\) +** movq \(%rdi\), %rax +** addq \$8, %rdi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* dec doesn't have any callee saved registers. */ + +/* +**dec: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$1, accumulator\(%rip\) +** movq \(%rdi\), %rax +** addq \$8, %rdi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subq \$504, %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\+8, %edi +** movq %rbp, 304\(%rsp\) +** movq %r8, 312\(%rsp\) +** movq %r9, 320\(%rsp\) +** movq %r10, 328\(%rsp\) +** movq %r11, 336\(%rsp\) +** movq %r12, 344\(%rsp\) +** movq %r13, 352\(%rsp\) +** movq %r14, 360\(%rsp\) +** movq %r15, 368\(%rsp\) +** movq %r16, 376\(%rsp\) +** movq %r17, 384\(%rsp\) +** movq %r18, 392\(%rsp\) +** movq %r19, 400\(%rsp\) +** movq %r20, 408\(%rsp\) +** movq %r21, 416\(%rsp\) +** movq %r22, 424\(%rsp\) +** movq %r23, 432\(%rsp\) +** movq %r24, 440\(%rsp\) +** movq %r25, 448\(%rsp\) +** movq %r26, 456\(%rsp\) +** movq %r27, 464\(%rsp\) +** movq %r28, 472\(%rsp\) +** movq %r29, 480\(%rsp\) +** movq %r30, 488\(%rsp\) +** movq %r31, 496\(%rsp\) +**... +** movaps %xmm0, \(%rsp\) +** movaps %xmm1, 16\(%rsp\) +** movaps %xmm2, 32\(%rsp\) +** movaps %xmm3, 48\(%rsp\) +** movaps %xmm4, 64\(%rsp\) +** movaps %xmm5, 80\(%rsp\) +** movaps %xmm6, 96\(%rsp\) +** movaps %xmm7, 112\(%rsp\) +** movaps %xmm8, 128\(%rsp\) +** movaps %xmm9, 144\(%rsp\) +** movaps %xmm10, 160\(%rsp\) +** movaps %xmm11, 176\(%rsp\) +** movaps %xmm12, 192\(%rsp\) +** movaps %xmm13, 208\(%rsp\) +** movaps %xmm14, 224\(%rsp\) +** movaps %xmm15, 240\(%rsp\) +**... +** call \*code\(%rip\) +** movaps \(%rsp\), %xmm0 +** movaps 16\(%rsp\), %xmm1 +** movaps 32\(%rsp\), %xmm2 +** movaps 48\(%rsp\), %xmm3 +** movaps 64\(%rsp\), %xmm4 +** movaps 80\(%rsp\), %xmm5 +** movaps 96\(%rsp\), %xmm6 +** movaps 112\(%rsp\), %xmm7 +** movaps 128\(%rsp\), %xmm8 +** movaps 144\(%rsp\), %xmm9 +** movaps 160\(%rsp\), %xmm10 +** movaps 176\(%rsp\), %xmm11 +** movaps 192\(%rsp\), %xmm12 +** movaps 208\(%rsp\), %xmm13 +** movq 256\(%rsp\), %rax +** movq 264\(%rsp\), %rdx +** movq 272\(%rsp\), %rcx +** movq 280\(%rsp\), %rbx +** movq 288\(%rsp\), %rsi +** movq 296\(%rsp\), %rdi +** movq 304\(%rsp\), %rbp +** movq 312\(%rsp\), %r8 +** movq 320\(%rsp\), %r9 +** movq 328\(%rsp\), %r10 +** movq 336\(%rsp\), %r11 +** movq 344\(%rsp\), %r12 +** movq 352\(%rsp\), %r13 +** movq 360\(%rsp\), %r14 +** movq 368\(%rsp\), %r15 +** movq 376\(%rsp\), %r16 +** movaps 224\(%rsp\), %xmm14 +** movaps 240\(%rsp\), %xmm15 +** movq 384\(%rsp\), %r17 +** movq 392\(%rsp\), %r18 +** movq 400\(%rsp\), %r19 +** movq 408\(%rsp\), %r20 +** movq 416\(%rsp\), %r21 +** movq 424\(%rsp\), %r22 +** movq 432\(%rsp\), %r23 +** movq 440\(%rsp\), %r24 +** movq 448\(%rsp\), %r25 +** movq 456\(%rsp\), %r26 +** movq 464\(%rsp\), %r27 +** movq 472\(%rsp\), %r28 +** movq 480\(%rsp\), %r29 +** movq 488\(%rsp\), %r30 +** movq 496\(%rsp\), %r31 +** addq \$504, %rsp +**... +** ret +** .cfi_endproc +**... +*/ + +#include "no-callee-saved-19a.c" diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c new file mode 100644 index 00000000000..3fcb41ff196 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-19e.c @@ -0,0 +1,162 @@ +/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */ +/* { dg-options "-O2 -mx32 -fno-pic -mtune=generic -msse2 -mapxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* end must be empty. */ + +/* +**end: +**.LFB[0-9]+: +** .cfi_startproc +** ret +** .cfi_endproc +**... +*/ + +/* inc doesn't have any callee saved registers. */ + +/* +**inc: +**.LFB[0-9]+: +** .cfi_startproc +** addl \$1, accumulator\(%rip\) +** movq %rdi, %rax +** movl \(%eax\), %eax +** leal 4\(%rdi\), %edi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* dec doesn't have any callee saved registers. */ + +/* +**dec: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$1, accumulator\(%rip\) +** movq %rdi, %rax +** movl \(%eax\), %eax +** leal 4\(%rdi\), %edi +** jmp \*%rax +** .cfi_endproc +**... +*/ + +/* start must save and restore all caller saved registers. */ + +/* +**start: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$504, %esp +**... +** movq %rax, 256\(%rsp\) +** movq %rdx, 264\(%rsp\) +** movq %rcx, 272\(%rsp\) +** movq %rbx, 280\(%rsp\) +** movq %rsi, 288\(%rsp\) +** movq %rdi, 296\(%rsp\) +**... +** movl \$code\+4, %edi +** movq %rbp, 304\(%rsp\) +** movq %r8, 312\(%rsp\) +** movq %r9, 320\(%rsp\) +** movq %r10, 328\(%rsp\) +** movq %r11, 336\(%rsp\) +** movq %r12, 344\(%rsp\) +** movq %r13, 352\(%rsp\) +** movq %r14, 360\(%rsp\) +** movq %r15, 368\(%rsp\) +** movq %r16, 376\(%rsp\) +** movq %r17, 384\(%rsp\) +** movq %r18, 392\(%rsp\) +** movq %r19, 400\(%rsp\) +** movq %r20, 408\(%rsp\) +** movq %r21, 416\(%rsp\) +** movq %r22, 424\(%rsp\) +** movq %r23, 432\(%rsp\) +** movq %r24, 440\(%rsp\) +** movq %r25, 448\(%rsp\) +** movq %r26, 456\(%rsp\) +** movq %r27, 464\(%rsp\) +** movq %r28, 472\(%rsp\) +** movq %r29, 480\(%rsp\) +** movq %r30, 488\(%rsp\) +** movq %r31, 496\(%rsp\) +**... +** movl code\(%rip\), %ebp +** movaps %xmm0, \(%rsp\) +** movaps %xmm1, 16\(%rsp\) +** movaps %xmm2, 32\(%rsp\) +** movaps %xmm3, 48\(%rsp\) +** movaps %xmm4, 64\(%rsp\) +** movaps %xmm5, 80\(%rsp\) +** movaps %xmm6, 96\(%rsp\) +** movaps %xmm7, 112\(%rsp\) +** movaps %xmm8, 128\(%rsp\) +** movaps %xmm9, 144\(%rsp\) +** movaps %xmm10, 160\(%rsp\) +** movaps %xmm11, 176\(%rsp\) +** movaps %xmm12, 192\(%rsp\) +** movaps %xmm13, 208\(%rsp\) +** movaps %xmm14, 224\(%rsp\) +** movaps %xmm15, 240\(%rsp\) +**... +** call \*%rbp +** movaps \(%rsp\), %xmm0 +** movaps 16\(%rsp\), %xmm1 +** movaps 32\(%rsp\), %xmm2 +** movaps 48\(%rsp\), %xmm3 +** movaps 64\(%rsp\), %xmm4 +** movaps 80\(%rsp\), %xmm5 +** movaps 96\(%rsp\), %xmm6 +** movaps 112\(%rsp\), %xmm7 +** movaps 128\(%rsp\), %xmm8 +** movaps 144\(%rsp\), %xmm9 +** movaps 160\(%rsp\), %xmm10 +** movaps 176\(%rsp\), %xmm11 +** movaps 192\(%rsp\), %xmm12 +** movaps 208\(%rsp\), %xmm13 +** movaps 224\(%rsp\), %xmm14 +** movaps 240\(%rsp\), %xmm15 +** movq 256\(%rsp\), %rax +** movq 264\(%rsp\), %rdx +** movq 272\(%rsp\), %rcx +** movq 280\(%rsp\), %rbx +** movq 288\(%rsp\), %rsi +** movq 296\(%rsp\), %rdi +** movq 304\(%rsp\), %rbp +** movq 312\(%rsp\), %r8 +** movq 320\(%rsp\), %r9 +** movq 328\(%rsp\), %r10 +** movq 336\(%rsp\), %r11 +** movq 344\(%rsp\), %r12 +** movq 352\(%rsp\), %r13 +** movq 360\(%rsp\), %r14 +** movq 368\(%rsp\), %r15 +** movq 376\(%rsp\), %r16 +** movq 384\(%rsp\), %r17 +** movq 392\(%rsp\), %r18 +** movq 400\(%rsp\), %r19 +** movq 408\(%rsp\), %r20 +** movq 416\(%rsp\), %r21 +** movq 424\(%rsp\), %r22 +** movq 432\(%rsp\), %r23 +** movq 440\(%rsp\), %r24 +** movq 448\(%rsp\), %r25 +** movq 456\(%rsp\), %r26 +** movq 464\(%rsp\), %r27 +** movq 472\(%rsp\), %r28 +** movq 480\(%rsp\), %r29 +** movq 488\(%rsp\), %r30 +** movq 496\(%rsp\), %r31 +** addl \$504, %esp +**... +** ret +** .cfi_endproc +**... +*/ + +#include "no-callee-saved-19a.c" diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-3.c b/gcc/testsuite/gcc.target/i386/no-callee-saved-3.c index 453272e11c0..44ad0b2114e 100644 --- a/gcc/testsuite/gcc.target/i386/no-callee-saved-3.c +++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-3.c @@ -3,6 +3,6 @@ __attribute__ ((no_callee_saved_registers, no_caller_saved_registers)) void -foo (void) /* { dg-error "attributes are not compatible" } */ -{ +foo (void) +{ /* { dg-error "attributes are not compatible" } */ } diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-1.c b/gcc/testsuite/gcc.target/i386/preserve-none-1.c new file mode 100644 index 00000000000..850791872a4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +extern void boring(void); + +extern void continuation(void *, void *, void *, void *) + __attribute__((preserve_none)); + +__attribute__((preserve_none)) +void entry(void *a, void *b, void *c, void *d) +{ + boring(); + continuation(a, b, c, d); +} + +/* { dg-final { scan-assembler-not "movq" } } */ +/* { dg-final { scan-assembler "jmp\[\\t \]+_?continuation" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-10.c b/gcc/testsuite/gcc.target/i386/preserve-none-10.c new file mode 100644 index 00000000000..f22200a9ff1 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-10.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef void (*fn_t) (void *) __attribute__ ((preserve_none)); + +void +foo (void *frame) +{ +} + +fn_t func = foo; /* { dg-error "incompatible pointer type" } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-11.c b/gcc/testsuite/gcc.target/i386/preserve-none-11.c new file mode 100644 index 00000000000..3bc82ba671a --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef void (*fn_t) (void *) __attribute__ ((preserve_none)); + +__attribute__ ((preserve_none)) +void +foo (void *frame) +{ +} + +fn_t func = foo; diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-12.c b/gcc/testsuite/gcc.target/i386/preserve-none-12.c new file mode 100644 index 00000000000..6960f660797 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-12.c @@ -0,0 +1,49 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +extern void bar (void) __attribute__ ((preserve_none)); + +void +foo (void) +{ + bar (); +} + +/* foo must save and restore all caller saved registers since bar won't + preserve any. */ +/* { dg-final { scan-assembler-not "jmp\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r9" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r10" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r11" { 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 } } } } */ +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { 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 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-13.c b/gcc/testsuite/gcc.target/i386/preserve-none-13.c new file mode 100644 index 00000000000..31b33201e85 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-13.c @@ -0,0 +1,50 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); +extern fn_t bar; + +void +foo (void) +{ + bar (); +} + +/* foo must save and restore all caller saved registers since bar won't + preserve any. */ +/* { dg-final { scan-assembler-not "jmp" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+" } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r9" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r10" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r11" { 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 } } } } */ +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { 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 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-14.c b/gcc/testsuite/gcc.target/i386/preserve-none-14.c new file mode 100644 index 00000000000..64a957ddf83 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-14.c @@ -0,0 +1,49 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); + +void +foo (fn_t bar) +{ + bar (); +} + +/* foo must save and restore all caller saved registers since bar won't + preserve any. */ +/* { dg-final { scan-assembler-not "jmp" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+" } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r9" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r10" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r11" { 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 } } } } */ +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { 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 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-15.c b/gcc/testsuite/gcc.target/i386/preserve-none-15.c new file mode 100644 index 00000000000..8af930bd914 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-15.c @@ -0,0 +1,46 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mgeneral-regs-only -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +extern void bar (void) __attribute__ ((preserve_none)); + +__attribute__ ((no_caller_saved_registers)) +void +foo (void) +{ + bar (); +} + +/* foo must save and restore all caller saved registers since bar won't + preserve any. */ +/* { dg-final { scan-assembler-not "jmp\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)si" 1 } } */ +/* { dg-final { scan-assembler-times "push(?:l|q)\[\\t \]*%(?:e|r)di" 1 } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "pushq\[\\t \]*%r11" 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 } } } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)ax" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)cx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)dx" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)si" 1 } } */ +/* { dg-final { scan-assembler-times "pop(?:l|q)\[\\t \]*%(?:e|r)di" 1 } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r8" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r9" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r10" 1 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "popq\[\\t \]*%r11" 1 { 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 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-16.c b/gcc/testsuite/gcc.target/i386/preserve-none-16.c new file mode 100644 index 00000000000..680083646fc --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-16.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern void foo (void); /* { dg-note "previous declaration" } */ + +__attribute__ ((preserve_none)) +void +foo (void) /* { dg-error "conflicting types" } */ +{ +} + diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-17.c b/gcc/testsuite/gcc.target/i386/preserve-none-17.c new file mode 100644 index 00000000000..e105da1b709 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-17.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern void foo (void) __attribute__ ((preserve_none)); /* { dg-note "previous declaration" } */ + +void +foo (void) /* { dg-error "conflicting types" } */ +{ +} + diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-18.c b/gcc/testsuite/gcc.target/i386/preserve-none-18.c new file mode 100644 index 00000000000..a2ac5e32ab5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-18.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-additional-options "-fno-PIE" { target ia32 } } */ + +extern void foo (void); + +__attribute__ ((preserve_none)) +void +bar (void) +{ + foo (); +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ +/* { dg-final { scan-assembler-not "call\[\\t \]+_?foo" } } */ +/* { dg-final { scan-assembler "jmp\[\\t \]+_?foo" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-19.c b/gcc/testsuite/gcc.target/i386/preserve-none-19.c new file mode 100644 index 00000000000..5e9cbd26fda --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-19.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-additional-options "-fno-PIE" { target ia32 } } */ + +extern void bar (void) __attribute__ ((preserve_none)); + +__attribute__ ((no_callee_saved_registers)) +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ +/* { dg-final { scan-assembler "jmp\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler-not "call\[\\t \]+_?bar" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-2.c b/gcc/testsuite/gcc.target/i386/preserve-none-2.c new file mode 100644 index 00000000000..027f1816ca2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +typedef void (*fn_t) (void *) __attribute__ ((preserve_none)); + +__attribute__ ((no_callee_saved_registers)) +void +foo (void *frame) +{ +} + +fn_t func = foo; /* { dg-error "incompatible pointer type" "" { target { ! ia32 } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-20.c b/gcc/testsuite/gcc.target/i386/preserve-none-20.c new file mode 100644 index 00000000000..0070ee7253e --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-20.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-additional-options "-fno-PIE" { target ia32 } } */ + +typedef void (*fn_t) (void) __attribute__ ((no_callee_saved_registers)); +extern fn_t bar; + +__attribute__ ((preserve_none)) +void +foo (void) +{ + bar (); +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ +/* { dg-final { scan-assembler "jmp" } } */ +/* { dg-final { scan-assembler-not "call\[\\t \]+" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-21.c b/gcc/testsuite/gcc.target/i386/preserve-none-21.c new file mode 100644 index 00000000000..4550d22fe4b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-21.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); + +__attribute__ ((no_callee_saved_registers)) +void +foo (fn_t bar) +{ + bar (); +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ +/* { dg-final { scan-assembler "jmp" } } */ +/* { dg-final { scan-assembler-not "call\[\\t \]+" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-22.c b/gcc/testsuite/gcc.target/i386/preserve-none-22.c new file mode 100644 index 00000000000..6ec8d0cfe95 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-22.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ +/* { dg-additional-options "-fno-PIE" { target ia32 } } */ + +extern void foo (void) __attribute__ ((no_caller_saved_registers)); + +__attribute__ ((preserve_none)) +void +bar (void) +{ + foo (); +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ +/* { dg-final { scan-assembler-not "call\[\\t \]+_?foo" } } */ +/* { dg-final { scan-assembler "jmp\[\\t \]+_?foo" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-23.c b/gcc/testsuite/gcc.target/i386/preserve-none-23.c new file mode 100644 index 00000000000..8cc933f8aa8 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-23.c @@ -0,0 +1,51 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move" } */ + +#include <stdint.h> + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); + +void +foo (uintptr_t p) +{ + ((fn_t) p) (); +} + +/* foo must save and restore all caller saved registers since bar won't + preserve any. */ +/* { dg-final { scan-assembler-not "jmp" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+" } } */ +/* { dg-final { scan-assembler-not "push(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "push(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r9" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r10" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "pushq\[\\t \]*%r11" { 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 } } } } */ +/* { dg-final { scan-assembler-not "pop(?:l|q)\[\\t \]*%(?:e|r)ax" } } */ +/* { 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-times "pop(?:l|q)\[\\t \]*%(?:e|r)bp" 1 } } */ +/* { 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 } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%rdi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "popq\[\\t \]*%r8" { target { ! ia32 } } } } */ +/* { 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 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-24.c b/gcc/testsuite/gcc.target/i386/preserve-none-24.c new file mode 100644 index 00000000000..d7adfba8ddd --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-24.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +__attribute__ ((preserve_none, no_callee_saved_registers)) +void +foo (void) +{ /* { dg-error "attributes are not compatible" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-25.c b/gcc/testsuite/gcc.target/i386/preserve-none-25.c new file mode 100644 index 00000000000..e22da50427f --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-25.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**entry: +**.LFB[0-9]+: +** .cfi_startproc +** movq %rdi, %r12 +** movq %rsi, %r13 +** movq %rdx, %r14 +** movq %rcx, %r15 +** jmp continuation +** .cfi_endproc +**... +*/ + +extern void continuation (void *, void *, void *, void *) + __attribute__ ((preserve_none)); + +__attribute__ ((no_callee_saved_registers)) +void +entry (void *a, void *b, void *c, void *d) +{ + continuation (a, b, c, d); +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-26.c b/gcc/testsuite/gcc.target/i386/preserve-none-26.c new file mode 100644 index 00000000000..926d127b576 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-26.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**entry: +**.LFB[0-9]+: +** .cfi_startproc +** movq %r15, %rcx +** movq %r14, %rdx +** movq %r13, %rsi +** movq %r12, %rdi +** jmp continuation +** .cfi_endproc +**... +*/ + +extern void continuation (void *, void *, void *, void *) + __attribute__ ((no_callee_saved_registers)); + +__attribute__ ((preserve_none)) +void +entry (void *a, void *b, void *c, void *d) +{ + continuation(a, b, c, d); +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-27.c b/gcc/testsuite/gcc.target/i386/preserve-none-27.c new file mode 100644 index 00000000000..17aa57d60ed --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-27.c @@ -0,0 +1,33 @@ +/* { dg-do compile { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**entry: +**.LFB[0-9]+: +** .cfi_startproc +**... +** movl %edi, %r12d +** movl %esi, %r13d +** movl %edx, %r14d +** pushq \$-559038737 +**... +** movl %ecx, %r15d +** movl %r9d, %esi +** movl %r8d, %edi +** xorl %eax, %eax +**... +** call continuation +**... +*/ + +extern void continuation (int, int, int, int, int, int, ...) + __attribute__ ((preserve_none)); + +__attribute__ ((no_callee_saved_registers)) +void +entry (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + continuation (arg1, arg2, arg3, arg4, arg5, arg6, 0xdeadbeef); +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-28.c b/gcc/testsuite/gcc.target/i386/preserve-none-28.c new file mode 100644 index 00000000000..7042b8db667 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-28.c @@ -0,0 +1,48 @@ +/* { dg-do run { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ + +#include <stdlib.h> + +__attribute__ ((preserve_none, weak)) +void +continuation (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + if (arg1 != 17) + abort (); + if (arg2 != 8) + abort (); + if (arg3 != 20) + abort (); + if (arg4 != -3) + abort (); + if (arg5 != -4) + abort (); + if (arg6 != 26) + abort (); +} + +__attribute__ ((no_callee_saved_registers, weak)) +void +entry (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + if (arg1 != 17) + abort (); + if (arg2 != 8) + abort (); + if (arg3 != 20) + abort (); + if (arg4 != -3) + abort (); + if (arg5 != -4) + abort (); + if (arg6 != 26) + abort (); + continuation (arg1, arg2, arg3, arg4, arg5, arg6); +} + +int +main (void) +{ + entry (17, 8, 20, -3, -4, 26); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-29.c b/gcc/testsuite/gcc.target/i386/preserve-none-29.c new file mode 100644 index 00000000000..e6520fa380b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-29.c @@ -0,0 +1,57 @@ +/* { dg-do run { target { *-*-linux* && { ! ia32 } } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ + +#include <stdarg.h> +#include <stdlib.h> + +__attribute__ ((preserve_none, weak)) +void +continuation (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, + ...) +{ + int a; + va_list va_arglist; + va_start (va_arglist, arg6); + if (arg1 != 17) + abort (); + if (arg2 != 8) + abort (); + if (arg3 != 20) + abort (); + if (arg4 != -3) + abort (); + if (arg5 != -4) + abort (); + if (arg6 != 26) + abort (); + a = va_arg (va_arglist, int); + if (a != 0xdeadbeef) + abort (); + va_end (va_arglist); +} + +__attribute__ ((no_callee_saved_registers, weak)) +void +entry (int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) +{ + if (arg1 != 17) + abort (); + if (arg2 != 8) + abort (); + if (arg3 != 20) + abort (); + if (arg4 != -3) + abort (); + if (arg5 != -4) + abort (); + if (arg6 != 26) + abort (); + continuation (arg1, arg2, arg3, arg4, arg5, arg6, 0xdeadbeef); +} + +int +main (void) +{ + entry (17, 8, 20, -3, -4, 26); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-3.c b/gcc/testsuite/gcc.target/i386/preserve-none-3.c new file mode 100644 index 00000000000..df484a5184c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-3.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer -mnoreturn-no-callee-saved-registers" } */ + +extern void bar (void) __attribute__ ((preserve_none)); +extern void fn (void) __attribute__ ((noreturn)); + +__attribute__ ((noreturn)) +void +foo (void) +{ + bar (); + fn (); +} + +/* { dg-final { scan-assembler-not "push\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "pop\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "jmp\[\\t \]+_?bar" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+_?bar" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-30a.c b/gcc/testsuite/gcc.target/i386/preserve-none-30a.c new file mode 100644 index 00000000000..2a21ef52708 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-30a.c @@ -0,0 +1,31 @@ +/* { dg-do compile { target { *-*-linux* && lp64 } } } */ +/* { dg-options "-O2 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**entry: +**.LFB[0-9]+: +** .cfi_startproc +** subq \$8, %rsp +** .cfi_def_cfa_offset 16 +** call boring +** addq \$8, %rsp +** .cfi_def_cfa_offset 8 +** jmp \*continuation\(%rip\) +** .cfi_endproc +**... +*/ + +extern void boring (void); + +extern void (*continuation) (void *, void *, void *, void *) + __attribute__ ((preserve_none)); + +__attribute__ ((preserve_none)) +void +entry (void *a, void *b, void *c, void *d) +{ + boring (); + continuation (a, b, c, d); +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-30b.c b/gcc/testsuite/gcc.target/i386/preserve-none-30b.c new file mode 100644 index 00000000000..425d0aa24a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-30b.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target { *-*-linux* && maybe_x32 } } } */ +/* { dg-options "-O2 -mx32 -fno-pic -mtune=generic -msse2 -mno-apxf -mtune-ctrl=prologue_using_move,epilogue_using_move" } */ +/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */ +/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */ + +/* +**entry: +**.LFB[0-9]+: +** .cfi_startproc +** subl \$8, %esp +** .cfi_def_cfa_offset 16 +** call boring +** movl continuation\(%rip\), %eax +** addl \$8, %esp +** .cfi_def_cfa_offset 8 +** jmp \*%rax +** .cfi_endproc +**... +*/ + +#include "preserve-none-30a.c" diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-4.c b/gcc/testsuite/gcc.target/i386/preserve-none-4.c new file mode 100644 index 00000000000..35c3501f6f0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-4.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer -mnoreturn-no-callee-saved-registers" } */ + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); +extern fn_t bar; +extern void fn (void) __attribute__ ((noreturn)); + +__attribute__ ((noreturn)) +void +foo (void) +{ + bar (); + fn (); +} + +/* { dg-final { scan-assembler-not "push\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "pop\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "jmp" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-5.c b/gcc/testsuite/gcc.target/i386/preserve-none-5.c new file mode 100644 index 00000000000..1498886a986 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-5.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer -mnoreturn-no-callee-saved-registers" } */ + +typedef void (*fn_t) (void) __attribute__ ((preserve_none)); +extern void fn (void) __attribute__ ((noreturn)); + +__attribute__ ((noreturn)) +void +foo (fn_t bar) +{ + bar (); + fn (); +} + +/* { dg-final { scan-assembler-not "push\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "pop\[^\n\r\]*(?:\[abcd\]x|\[sd\]i|sp|r\[0-9\]|\[xyz\]mm)" } } */ +/* { dg-final { scan-assembler-not "jmp" } } */ +/* { dg-final { scan-assembler "call\[\\t \]+" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-6.c b/gcc/testsuite/gcc.target/i386/preserve-none-6.c new file mode 100644 index 00000000000..2606ea3bc19 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-6.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ + +extern int bar (int) +#ifndef __x86_64__ +__attribute__ ((regparm(3))) +#endif +; + +__attribute__ ((preserve_none)) +void +foo (void *frame) +{ + int a,b,c,d,e,f,i; + a = bar (5); + b = bar (a); + c = bar (b); + d = bar (c); + e = bar (d); + f = bar (e); + for (i = 1; i < 10; i++) + { + a += bar (a + i) + bar (b + i) + + bar (c + i) + bar (d + i) + + bar (e + i) + bar (f + i); + } +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-7.c b/gcc/testsuite/gcc.target/i386/preserve-none-7.c new file mode 100644 index 00000000000..79ce761eaf5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-7.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune-ctrl=^prologue_using_move,^epilogue_using_move -fomit-frame-pointer" } */ + +extern int bar (int) __attribute__ ((no_caller_saved_registers)) +#ifndef __x86_64__ +__attribute__ ((regparm(3))) +#endif +; + +__attribute__ ((preserve_none)) +void +foo (void *frame) +{ + int a,b,c,d,e,f,i; + a = bar (5); + b = bar (a); + c = bar (b); + d = bar (c); + e = bar (d); + f = bar (e); + for (i = 1; i < 10; i++) + { + a += bar (a + i) + bar (b + i) + + bar (c + i) + bar (d + i) + + bar (e + i) + bar (f + i); + } +} + +/* { dg-final { scan-assembler-not "push" } } */ +/* { dg-final { scan-assembler-not "pop" } } */ diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-8.c b/gcc/testsuite/gcc.target/i386/preserve-none-8.c new file mode 100644 index 00000000000..9309ceba388 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-8.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +__attribute__ ((preserve_none, no_caller_saved_registers)) +void +foo (void) +{ /* { dg-error "attributes are not compatible" } */ +} diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-9.c b/gcc/testsuite/gcc.target/i386/preserve-none-9.c new file mode 100644 index 00000000000..f28ddeb17ec --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/preserve-none-9.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mgeneral-regs-only" } */ + +__attribute__ ((preserve_none, interrupt)) +void +foo (void *frame) /* { dg-error "attributes are not compatible" } */ +{ +} -- 2.49.0