From d3feb168e2c58264b575ea1b88e4f58a49374287 Mon Sep 17 00:00:00 2001 From: ktietz Date: Tue, 3 Jun 2008 08:05:25 +0000 Subject: [PATCH] 2008-06-03 Kai Tietz * doc/tm.texi (OVERRIDE_ABI_FORMAT): New. * doc/extend.texi (ms_abi,sysv_abi): New attribute description. * function.c (allocate_struct_function): Use of OVERRIDE_ABI_FORMAT. * config/i386/cygming.h (TARGET_64BIT_MS_ABI): Make use of cfun and DEFAULT_ABI to deceide abi mode. (DEFAULT_ABI): New. (REG_PARM_STACK_SPACE): Removed. (OUTGOING_REG_PARM_STACK_SPACE): Removed. (STACK_BOUNDARY): Use default target to deceide stack boundary. * config/i386/i386-protos.h (ix86_cfun_abi): New. (ix86_function_abi): Likewise. (ix86_function_type_abi): Likewise. (ix86_call_abi_override): Likewise. * confid/i386/i386.md (SSE_REGPARM_MAX): Replaced by abi specific define X86_64_SSE_REGPARM_MAX/X64_SSE_REGPARM_MAX. * config/i386/i386.c (override_options): Replace TARGET_64BIT_MS_ABI. (X86_64_VARARGS_SIZE): Replace REGPARM_MAX and SSE_REGPARM_MAX by abi specific defines. (X86_64_REGPARM_MAX): New. (X86_64_SSE_REGPARM_MAX): New. (X64_REGPARM_MAX): New. (X64_SSE_REGPARM_MAX): New. (X86_32_REGPARM_MAX): New. (X86_32_SSE_REGPARM_MAX): New. (ix86_handle_cconv_attribute): Replace TARGET_64BIT_MS_ABI. (ix86_function_regparm): Handle user calling abi. (ix86_function_arg_regno_p): Replace TARGET_64BIT_MS_ABI by DEFAULT_ABI versus SYSV_ABI check. (ix86_reg_parm_stack_space): New. (ix86_function_type_abi): New. (ix86_call_abi_override): New. (ix86_function_abi): New. (ix86_cfun_abi): New. (init_cumulative_args): Call abi specific initialization. (function_arg_advance): Remove TARGET_64BIT_MS_ABI. (function_arg_64): Extend SSE_REGPARM_MAX check. (function_arg (): Remove TARGET_64BIT_MS_ABI. (ix86_pass_by_reference): Likewise. (ix86_function_value_regno_p): Likewise. (function_value_64): Replace REGPARM_MAX, and SSE_REGPARM_MAX. (ix86_function_value_1): Replace TARGET_64BIT_MS_ABI. (return_in_memory_ms_64): Replace TARGET_64BIT_MS_ABI. (ix86_build_builtin_va_list): Replace TARGET_64BIT_MS_ABI. (setup_incoming_varargs_64): Adjust regparm for call abi. (ix86_setup_incoming_varargs): Replace TARGET_64BIT_MS_ABI. (ix86_va_start): Likewise. (ix86_gimplify_va_arg): Likewise. (ix86_expand_prologue): Likewise. (output_pic_addr_const): Likewise. (ix86_init_machine_status): Initialize call_abi by DEFAULT_ABI. (x86_this_parameter): Replace TARGET_64BIT_MS_ABI. (x86_output_mi_thunk): Likewise. (x86_function_profiler): Likewise. * config/i386/i386.h (TARGET_64BIT_MS_ABI): Use ix64_cfun_abi. (SYSV_ABI, MS_ABI): New constants. (DEFAULT_ABI): New. (init_regs): Add prototype of function in regclass.c file. (OVERRIDE_ABI_FORMAT): New. (CONDITIONAL_REGISTER_USAGE): Remove TARGET_64BIT_MS_ABI part. (REG_PARM_STACK_SPACE): Use ix86_reg_parm_stack_space. (OUTGOING_REG_PARM_STACK_SPACE): New. (ix86_reg_parm_stack_space): New prototype. (CUMULATIVE_ARGS): Add call_abi member. (machine_function): Add call_abi member. * config/i386/mingw32.h (EXTRA_OS_CPP_BUILTINS): Replace TARGET_64BIT_MS_ABI by DEFAULT_ABI compare to MS_ABI. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@136311 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 70 +++++++++++++++ gcc/config/i386/cygming.h | 19 ++-- gcc/config/i386/i386-protos.h | 5 ++ gcc/config/i386/i386.c | 203 ++++++++++++++++++++++++++++++++++-------- gcc/config/i386/i386.h | 47 ++++++++-- gcc/config/i386/i386.md | 9 +- gcc/config/i386/mingw32.h | 2 +- gcc/doc/extend.texi | 13 +++ gcc/doc/tm.texi | 9 ++ gcc/function.c | 4 + gcc/target-def.h | 2 - 11 files changed, 320 insertions(+), 63 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 56b6ddb..7f75646 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,73 @@ +2008-06-03 Kai Tietz + + * doc/tm.texi (OVERRIDE_ABI_FORMAT): New. + * doc/extend.texi (ms_abi,sysv_abi): New attribute description. + * function.c (allocate_struct_function): Use of + OVERRIDE_ABI_FORMAT. + * config/i386/cygming.h (TARGET_64BIT_MS_ABI): Make use + of cfun and DEFAULT_ABI to deceide abi mode. + (DEFAULT_ABI): New. + (REG_PARM_STACK_SPACE): Removed. + (OUTGOING_REG_PARM_STACK_SPACE): Removed. + (STACK_BOUNDARY): Use default target to deceide stack boundary. + * config/i386/i386-protos.h (ix86_cfun_abi): New. + (ix86_function_abi): Likewise. + (ix86_function_type_abi): Likewise. + (ix86_call_abi_override): Likewise. + * confid/i386/i386.md (SSE_REGPARM_MAX): Replaced by abi + specific define X86_64_SSE_REGPARM_MAX/X64_SSE_REGPARM_MAX. + * config/i386/i386.c (override_options): Replace TARGET_64BIT_MS_ABI. + (X86_64_VARARGS_SIZE): Replace REGPARM_MAX and SSE_REGPARM_MAX by abi + specific defines. + (X86_64_REGPARM_MAX): New. + (X86_64_SSE_REGPARM_MAX): New. + (X64_REGPARM_MAX): New. + (X64_SSE_REGPARM_MAX): New. + (X86_32_REGPARM_MAX): New. + (X86_32_SSE_REGPARM_MAX): New. + (ix86_handle_cconv_attribute): Replace TARGET_64BIT_MS_ABI. + (ix86_function_regparm): Handle user calling abi. + (ix86_function_arg_regno_p): Replace TARGET_64BIT_MS_ABI + by DEFAULT_ABI versus SYSV_ABI check. + (ix86_reg_parm_stack_space): New. + (ix86_function_type_abi): New. + (ix86_call_abi_override): New. + (ix86_function_abi): New. + (ix86_cfun_abi): New. + (init_cumulative_args): Call abi specific initialization. + (function_arg_advance): Remove TARGET_64BIT_MS_ABI. + (function_arg_64): Extend SSE_REGPARM_MAX check. + (function_arg (): Remove TARGET_64BIT_MS_ABI. + (ix86_pass_by_reference): Likewise. + (ix86_function_value_regno_p): Likewise. + (function_value_64): Replace REGPARM_MAX, and SSE_REGPARM_MAX. + (ix86_function_value_1): Replace TARGET_64BIT_MS_ABI. + (return_in_memory_ms_64): Replace TARGET_64BIT_MS_ABI. + (ix86_build_builtin_va_list): Replace TARGET_64BIT_MS_ABI. + (setup_incoming_varargs_64): Adjust regparm for call abi. + (ix86_setup_incoming_varargs): Replace TARGET_64BIT_MS_ABI. + (ix86_va_start): Likewise. + (ix86_gimplify_va_arg): Likewise. + (ix86_expand_prologue): Likewise. + (output_pic_addr_const): Likewise. + (ix86_init_machine_status): Initialize call_abi by DEFAULT_ABI. + (x86_this_parameter): Replace TARGET_64BIT_MS_ABI. + (x86_output_mi_thunk): Likewise. + (x86_function_profiler): Likewise. + * config/i386/i386.h (TARGET_64BIT_MS_ABI): Use ix64_cfun_abi. + (SYSV_ABI, MS_ABI): New constants. + (DEFAULT_ABI): New. + (init_regs): Add prototype of function in regclass.c file. + (OVERRIDE_ABI_FORMAT): New. + (CONDITIONAL_REGISTER_USAGE): Remove TARGET_64BIT_MS_ABI part. + (REG_PARM_STACK_SPACE): Use ix86_reg_parm_stack_space. + (OUTGOING_REG_PARM_STACK_SPACE): New. + (ix86_reg_parm_stack_space): New prototype. + (CUMULATIVE_ARGS): Add call_abi member. + (machine_function): Add call_abi member. + * config/i386/mingw32.h (EXTRA_OS_CPP_BUILTINS): Replace TARGET_64BIT_MS_ABI + by DEFAULT_ABI compare to MS_ABI. + 2008-06-02 Andy Hutchinson PR target/34879 diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index bf46cab..1070c85 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -34,7 +34,10 @@ along with GCC; see the file COPYING3. If not see #endif #undef TARGET_64BIT_MS_ABI -#define TARGET_64BIT_MS_ABI TARGET_64BIT +#define TARGET_64BIT_MS_ABI (!cfun ? DEFAULT_ABI == MS_ABI : TARGET_64BIT && cfun->machine->call_abi == MS_ABI) + +#undef DEFAULT_ABI +#define DEFAULT_ABI (TARGET_64BIT ? MS_ABI : SYSV_ABI) #undef DBX_REGISTER_NUMBER #define DBX_REGISTER_NUMBER(n) \ @@ -123,18 +126,6 @@ along with GCC; see the file COPYING3. If not see #undef LONG_TYPE_SIZE #define LONG_TYPE_SIZE 32 -#undef REG_PARM_STACK_SPACE -#define REG_PARM_STACK_SPACE(FNDECL) (TARGET_64BIT_MS_ABI ? 32 : 0) - -#undef OUTGOING_REG_PARM_STACK_SPACE -#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) (TARGET_64BIT_MS_ABI ? 1 : 0) - -#undef REGPARM_MAX -#define REGPARM_MAX (TARGET_64BIT_MS_ABI ? 4 : 3) - -#undef SSE_REGPARM_MAX -#define SSE_REGPARM_MAX (TARGET_64BIT_MS_ABI ? 4 : TARGET_SSE ? 3 : 0) - /* Enable parsing of #pragma pack(push,) and #pragma pack(pop). */ #define HANDLE_PRAGMA_PACK_PUSH_POP 1 /* Enable push_macro & pop_macro */ @@ -214,7 +205,7 @@ do { \ #define CHECK_STACK_LIMIT 4000 #undef STACK_BOUNDARY -#define STACK_BOUNDARY (TARGET_64BIT_MS_ABI ? 128 : BITS_PER_WORD) +#define STACK_BOUNDARY (DEFAULT_ABI == MS_ABI ? 128 : BITS_PER_WORD) /* By default, target has a 80387, uses IEEE compatible arithmetic, returns float values in the 387 and needs stack probes. diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 6fdea06..a92272b 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -137,6 +137,11 @@ extern int ix86_function_arg_boundary (enum machine_mode, tree); extern bool ix86_sol10_return_in_memory (const_tree,const_tree); extern rtx ix86_force_to_memory (enum machine_mode, rtx); extern void ix86_free_from_memory (enum machine_mode); +extern int ix86_cfun_abi (void); +extern int ix86_function_abi (const_tree); +extern int ix86_function_type_abi (const_tree); +extern void ix86_call_abi_override (const_tree); + extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx, rtx, rtx, rtx, rtx); extern bool ix86_hard_regno_mode_ok (int, enum machine_mode); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 16e7422..b159ce4 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1619,7 +1619,7 @@ rtx ix86_compare_op1 = NULL_RTX; rtx ix86_compare_emitted = NULL_RTX; /* Size of the register save area. */ -#define X86_64_VARARGS_SIZE (REGPARM_MAX * UNITS_PER_WORD + SSE_REGPARM_MAX * 16) +#define X86_64_VARARGS_SIZE (X86_64_REGPARM_MAX * UNITS_PER_WORD + X86_64_SSE_REGPARM_MAX * 16) /* Define the structure for the machine field in struct function. */ @@ -2306,11 +2306,11 @@ override_options (void) } else { - /* For TARGET_64BIT_MS_ABI, force pic on, in order to enable the + /* For TARGET_64BIT and MS_ABI, force pic on, in order to enable the use of rip-relative addressing. This eliminates fixups that would otherwise be needed if this object is to be placed in a DLL, and is essentially just as efficient as direct addressing. */ - if (TARGET_64BIT_MS_ABI) + if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) ix86_cmodel = CM_SMALL_PIC, flag_pic = 1; else if (TARGET_64BIT) ix86_cmodel = flag_pic ? CM_SMALL_PIC : CM_SMALL; @@ -2761,8 +2761,9 @@ override_options (void) set_param_value ("l2-cache-size", ix86_cost->l2_cache_size); /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0) - can be optimized to ap = __builtin_next_arg (0). */ - if (!TARGET_64BIT || TARGET_64BIT_MS_ABI) + can be optimized to ap = __builtin_next_arg (0). + For abi switching it should be corrected. */ + if (!TARGET_64BIT || DEFAULT_ABI == MS_ABI) targetm.expand_builtin_va_start = NULL; #ifdef USE_IX86_CLD @@ -3166,7 +3167,7 @@ ix86_handle_cconv_attribute (tree *node, tree name, if (TARGET_64BIT) { /* Do not warn when emulating the MS ABI. */ - if (!TARGET_64BIT_MS_ABI) + if (TREE_CODE (*node) != FUNCTION_TYPE || !ix86_function_type_abi (*node)) warning (OPT_Wattributes, "%qs attribute ignored", IDENTIFIER_POINTER (name)); *no_add_attrs = true; @@ -3269,7 +3270,11 @@ ix86_function_regparm (const_tree type, const_tree decl) static bool error_issued; if (TARGET_64BIT) - return regparm; + { + if (ix86_function_type_abi (type) == DEFAULT_ABI) + return regparm; + return DEFAULT_ABI != SYSV_ABI ? X86_64_REGPARM_MAX : X64_REGPARM_MAX; + } attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type)); if (attr) @@ -3500,15 +3505,20 @@ ix86_function_arg_regno_p (int regno) return true; } + /* TODO: The function should depend on current function ABI but + builtins.c would need updating then. Therefore we use the + default ABI. */ + /* RAX is used as hidden argument to va_arg functions. */ - if (!TARGET_64BIT_MS_ABI && regno == AX_REG) + if (DEFAULT_ABI == SYSV_ABI && regno == AX_REG) return true; - if (TARGET_64BIT_MS_ABI) + if (DEFAULT_ABI == MS_ABI) parm_regs = x86_64_ms_abi_int_parameter_registers; else parm_regs = x86_64_int_parameter_registers; - for (i = 0; i < REGPARM_MAX; i++) + for (i = 0; i < (DEFAULT_ABI == MS_ABI ? X64_REGPARM_MAX + : X86_64_REGPARM_MAX); i++) if (regno == parm_regs[i]) return true; return false; @@ -3529,6 +3539,98 @@ ix86_must_pass_in_stack (enum machine_mode mode, const_tree type) && type && TREE_CODE (type) != VECTOR_TYPE); } +/* It returns the size, in bytes, of the area reserved for arguments passed + in registers for the function represented by fndecl dependent to the used + abi format. */ +unsigned int +ix86_reg_parm_stack_space (const_tree fndecl) +{ + int call_abi = 0; + /* For libcalls it is possible that there is no fndecl at hand. + Therefore assume for this case the default abi of the target. */ + if (!fndecl) + call_abi = DEFAULT_ABI; + else + call_abi = ix86_function_abi (fndecl); + if (call_abi == 1) + return 32; + return 0; +} + +/* Returns value SYSV_ABI, MS_ABI dependent on fntype, specifying the + call abi used. */ +int +ix86_function_type_abi (const_tree fntype) +{ + if (TARGET_64BIT && fntype != NULL) + { + int abi; + if (DEFAULT_ABI == SYSV_ABI) + abi = lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype)) ? MS_ABI : SYSV_ABI; + else + abi = lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_ABI; + + if (DEFAULT_ABI == MS_ABI && abi == SYSV_ABI) + sorry ("using sysv calling convention on target w64 is not supported"); + + return abi; + } + return DEFAULT_ABI; +} + +int +ix86_function_abi (const_tree fndecl) +{ + if (! fndecl) + return DEFAULT_ABI; + return ix86_function_type_abi (TREE_TYPE (fndecl)); +} + +/* Returns value SYSV_ABI, MS_ABI dependent on cfun, specifying the + call abi used. */ +int +ix86_cfun_abi (void) +{ + if (! cfun || ! TARGET_64BIT) + return DEFAULT_ABI; + return cfun->machine->call_abi; +} + +/* regclass.c */ +extern void init_regs (void); + +/* Implementation of call abi switching target hook. Specific to FNDECL + the specific call register sets are set. See also CONDITIONAL_REGISTER_USAGE + for more details. + To prevent redudant calls of costy function init_regs (), it checks not to + reset register usage for default abi. */ +void +ix86_call_abi_override (const_tree fndecl) +{ + if (fndecl == NULL_TREE) + cfun->machine->call_abi = DEFAULT_ABI; + else + cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (fndecl)); + if (TARGET_64BIT && cfun->machine->call_abi == MS_ABI && call_used_regs) + { + if (call_used_regs[4 /*RSI*/] != 0 || call_used_regs[5 /*RDI*/] != 0) + { + call_used_regs[4 /*RSI*/] = 0; + call_used_regs[5 /*RDI*/] = 0; + init_regs (); + } + } + else if (TARGET_64BIT && call_used_regs) + { + if (call_used_regs[4 /*RSI*/] != 1 || call_used_regs[5 /*RDI*/] != 1) + { + call_used_regs[4 /*RSI*/] = 1; + call_used_regs[5 /*RDI*/] = 1; + init_regs (); + } + } +} + /* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ @@ -3542,10 +3644,25 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ struct cgraph_local_info *i = fndecl ? cgraph_local_info (fndecl) : NULL; memset (cum, 0, sizeof (*cum)); + cum->call_abi = ix86_function_type_abi (fntype); /* Set up the number of registers to use for passing arguments. */ cum->nregs = ix86_regparm; + if (TARGET_64BIT) + { + if (cum->call_abi != DEFAULT_ABI) + cum->nregs = DEFAULT_ABI != SYSV_ABI ? X86_64_REGPARM_MAX + : X64_REGPARM_MAX; + } if (TARGET_SSE) - cum->sse_nregs = SSE_REGPARM_MAX; + { + cum->sse_nregs = SSE_REGPARM_MAX; + if (TARGET_64BIT) + { + if (cum->call_abi != DEFAULT_ABI) + cum->sse_nregs = DEFAULT_ABI != SYSV_ABI ? X86_64_SSE_REGPARM_MAX + : X64_SSE_REGPARM_MAX; + } + } if (TARGET_MMX) cum->mmx_nregs = MMX_REGPARM_MAX; cum->warn_sse = true; @@ -4331,7 +4448,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (type) mode = type_natural_mode (type); - if (TARGET_64BIT_MS_ABI) + if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI) function_arg_advance_ms_64 (cum, bytes, words); else if (TARGET_64BIT) function_arg_advance_64 (cum, mode, type, words); @@ -4458,8 +4575,11 @@ function_arg_64 (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (mode == VOIDmode) return GEN_INT (cum->maybe_vaarg ? (cum->sse_nregs < 0 - ? SSE_REGPARM_MAX - : cum->sse_regno) + ? (cum->call_abi == DEFAULT_ABI + ? SSE_REGPARM_MAX + : (DEFAULT_ABI != SYSV_ABI ? X86_64_SSE_REGPARM_MAX + : X64_SSE_REGPARM_MAX)) + : cum->sse_regno) : -1); return construct_container (mode, orig_mode, type, 0, cum->nregs, @@ -4533,7 +4653,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode omode, if (type && TREE_CODE (type) == VECTOR_TYPE) mode = type_natural_mode (type); - if (TARGET_64BIT_MS_ABI) + if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI) return function_arg_ms_64 (cum, mode, omode, named, bytes); else if (TARGET_64BIT) return function_arg_64 (cum, mode, omode, type); @@ -4553,7 +4673,7 @@ ix86_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, const_tree type, bool named ATTRIBUTE_UNUSED) { /* See Windows x64 Software Convention. */ - if (TARGET_64BIT_MS_ABI) + if (TARGET_64BIT && (cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI) { int msize = (int) GET_MODE_SIZE (mode); if (type) @@ -4686,7 +4806,10 @@ ix86_function_value_regno_p (int regno) return true; case FIRST_FLOAT_REG: - if (TARGET_64BIT_MS_ABI) + /* TODO: The function should depend on current function ABI but + builtins.c would need updating then. Therefore we use the + default ABI. */ + if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) return false; return TARGET_FLOAT_RETURNS_IN_80387; @@ -4777,7 +4900,7 @@ function_value_64 (enum machine_mode orig_mode, enum machine_mode mode, } ret = construct_container (mode, orig_mode, valtype, 1, - REGPARM_MAX, SSE_REGPARM_MAX, + X86_64_REGPARM_MAX, X86_64_SSE_REGPARM_MAX, x86_64_int_return_registers, 0); /* For zero sized structures, construct_container returns NULL, but we @@ -4825,7 +4948,7 @@ ix86_function_value_1 (const_tree valtype, const_tree fntype_or_decl, fn = fntype_or_decl; fntype = fn ? TREE_TYPE (fn) : fntype_or_decl; - if (TARGET_64BIT_MS_ABI) + if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI) return function_value_ms_64 (orig_mode, mode); else if (TARGET_64BIT) return function_value_64 (orig_mode, mode, valtype); @@ -5022,7 +5145,7 @@ ix86_build_builtin_va_list (void) tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl; /* For i386 we use plain pointer to argument area. */ - if (!TARGET_64BIT || TARGET_64BIT_MS_ABI) + if (!TARGET_64BIT || ix86_cfun_abi () == MS_ABI) return build_pointer_type (char_type_node); record = (*lang_hooks.types.make_type) (RECORD_TYPE); @@ -5070,6 +5193,10 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) rtx nsse_reg; alias_set_type set; int i; + int regparm = ix86_regparm; + + if((cum ? cum->call_abi : ix86_cfun_abi ()) != DEFAULT_ABI) + regparm = DEFAULT_ABI != SYSV_ABI ? X86_64_REGPARM_MAX : X64_REGPARM_MAX; if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size) return; @@ -5089,7 +5216,7 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) set = get_varargs_alias_set (); for (i = cum->regno; - i < ix86_regparm + i < regparm && i < cum->regno + cfun->va_list_gpr_size / UNITS_PER_WORD; i++) { @@ -5136,7 +5263,7 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum) tmp_reg = gen_reg_rtx (Pmode); emit_insn (gen_rtx_SET (VOIDmode, tmp_reg, plus_constant (save_area, - 8 * REGPARM_MAX + 127))); + 8 * X86_64_REGPARM_MAX + 127))); mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127)); MEM_NOTRAP_P (mem) = 1; set_mem_alias_set (mem, set); @@ -5154,7 +5281,7 @@ setup_incoming_varargs_ms_64 (CUMULATIVE_ARGS *cum) alias_set_type set = get_varargs_alias_set (); int i; - for (i = cum->regno; i < REGPARM_MAX; i++) + for (i = cum->regno; i < X64_REGPARM_MAX; i++) { rtx reg, mem; @@ -5192,7 +5319,7 @@ ix86_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, if (stdarg_p (fntype)) function_arg_advance (&next_cum, mode, type, 1); - if (TARGET_64BIT_MS_ABI) + if ((cum ? cum->call_abi : DEFAULT_ABI) == MS_ABI) setup_incoming_varargs_ms_64 (&next_cum); else setup_incoming_varargs_64 (&next_cum); @@ -5209,7 +5336,7 @@ ix86_va_start (tree valist, rtx nextarg) tree type; /* Only 64bit target needs something special. */ - if (!TARGET_64BIT || TARGET_64BIT_MS_ABI) + if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI) { std_expand_builtin_va_start (valist, nextarg); return; @@ -5244,7 +5371,7 @@ ix86_va_start (tree valist, rtx nextarg) { type = TREE_TYPE (fpr); t = build2 (GIMPLE_MODIFY_STMT, type, fpr, - build_int_cst (type, n_fpr * 16 + 8*REGPARM_MAX)); + build_int_cst (type, n_fpr * 16 + 8*X86_64_REGPARM_MAX)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } @@ -5288,7 +5415,7 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) enum machine_mode nat_mode; /* Only 64bit target needs something special. */ - if (!TARGET_64BIT || TARGET_64BIT_MS_ABI) + if (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI) return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node)); @@ -5310,7 +5437,8 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) nat_mode = type_natural_mode (type); container = construct_container (nat_mode, TYPE_MODE (type), type, 0, - REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0); + X86_64_REGPARM_MAX, X86_64_SSE_REGPARM_MAX, + intreg, 0); /* Pull the value out of the saved registers. */ @@ -5379,7 +5507,7 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) if (needed_intregs) { t = build_int_cst (TREE_TYPE (gpr), - (REGPARM_MAX - needed_intregs + 1) * 8); + (X86_64_REGPARM_MAX - needed_intregs + 1) * 8); t = build2 (GE_EXPR, boolean_type_node, gpr, t); t2 = build1 (GOTO_EXPR, void_type_node, lab_false); t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE); @@ -5388,8 +5516,8 @@ ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p) if (needed_sseregs) { t = build_int_cst (TREE_TYPE (fpr), - (SSE_REGPARM_MAX - needed_sseregs + 1) * 16 - + REGPARM_MAX * 8); + (X86_64_SSE_REGPARM_MAX - needed_sseregs + 1) * 16 + + X86_64_REGPARM_MAX * 8); t = build2 (GE_EXPR, boolean_type_node, fpr, t); t2 = build1 (GOTO_EXPR, void_type_node, lab_false); t = build3 (COND_EXPR, void_type_node, t, t2, NULL_TREE); @@ -6515,9 +6643,9 @@ ix86_expand_prologue (void) bool eax_live; rtx t; - gcc_assert (!TARGET_64BIT || TARGET_64BIT_MS_ABI); + gcc_assert (!TARGET_64BIT || cfun->machine->call_abi == MS_ABI); - if (TARGET_64BIT_MS_ABI) + if (cfun->machine->call_abi == MS_ABI) eax_live = false; else eax_live = ix86_eax_live_at_start_p (); @@ -8331,7 +8459,7 @@ output_pic_addr_const (FILE *file, rtx x, int code) #endif assemble_name (file, name); } - if (!TARGET_MACHO && !TARGET_64BIT_MS_ABI + if (!TARGET_MACHO && !(TARGET_64BIT && DEFAULT_ABI == MS_ABI) && code == 'P' && ! SYMBOL_REF_LOCAL_P (x)) fputs ("@PLT", file); break; @@ -16422,6 +16550,7 @@ ix86_init_machine_status (void) f = GGC_CNEW (struct machine_function); f->use_fast_prologue_epilogue_nregs = -1; f->tls_descriptor_call_expanded_p = 0; + f->call_abi = DEFAULT_ABI; return f; } @@ -23009,7 +23138,7 @@ x86_this_parameter (tree function) { const int *parm_regs; - if (TARGET_64BIT_MS_ABI) + 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; @@ -23177,7 +23306,7 @@ x86_output_mi_thunk (FILE *file ATTRIBUTE_UNUSED, output_asm_insn ("jmp\t%P0", xops); /* All thunks should be in the same object as their target, and thus binds_local_p should be true. */ - else if (TARGET_64BIT_MS_ABI) + else if (TARGET_64BIT && cfun->machine->call_abi == MS_ABI) gcc_unreachable (); else { @@ -23259,7 +23388,7 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) fprintf (file, "\tleaq\t%sP%d@(%%rip),%%r11\n", LPREFIX, labelno); #endif - if (!TARGET_64BIT_MS_ABI && flag_pic) + if (DEFAULT_ABI == SYSV_ABI && flag_pic) fprintf (file, "\tcall\t*%s@GOTPCREL(%%rip)\n", MCOUNT_NAME); else fprintf (file, "\tcall\t%s\n", MCOUNT_NAME); diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index ef8da17..552515f 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -446,7 +446,17 @@ extern tree x86_mfence; #define TARGET_MACHO 0 /* Likewise, for the Windows 64-bit ABI. */ -#define TARGET_64BIT_MS_ABI 0 +#define TARGET_64BIT_MS_ABI (TARGET_64BIT && ix86_cfun_abi () == MS_ABI) + +/* Available call abi. */ +enum +{ + SYSV_ABI = 0, + MS_ABI = 1 +}; + +/* The default abi form used by target. */ +#define DEFAULT_ABI SYSV_ABI /* Subtargets may reset this to 1 in order to enable 96-bit long double with the rounding mode forced to 53 bits. */ @@ -804,7 +814,8 @@ enum target_cpu_default #define PARM_BOUNDARY BITS_PER_WORD /* Boundary (in *bits*) on which stack pointer should be aligned. */ -#define STACK_BOUNDARY BITS_PER_WORD +#define STACK_BOUNDARY (TARGET_64BIT && DEFAULT_ABI == MS_ABI ? 128 \ + : BITS_PER_WORD) /* Boundary (in *bits*) on which the stack pointer prefers to be aligned; the compiler cannot rely on having this alignment. */ @@ -1044,6 +1055,8 @@ enum target_cpu_default #define ORDER_REGS_FOR_LOCAL_ALLOC x86_order_regs_for_local_alloc () +#define OVERRIDE_ABI_FORMAT(FNDECL) ix86_call_abi_override (FNDECL) + /* Macro to conditionally modify fixed_regs/call_used_regs. */ #define CONDITIONAL_REGISTER_USAGE \ do { \ @@ -1094,7 +1107,7 @@ do { \ for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) \ reg_names[i] = ""; \ } \ - if (TARGET_64BIT_MS_ABI) \ + if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) \ { \ call_used_regs[4 /*RSI*/] = 0; \ call_used_regs[5 /*RDI*/] = 0; \ @@ -1624,7 +1637,11 @@ enum reg_class This space can be allocated by the caller, or be a part of the machine-dependent stack frame: `OUTGOING_REG_PARM_STACK_SPACE' says which. */ -#define REG_PARM_STACK_SPACE(FNDECL) 0 +#define REG_PARM_STACK_SPACE(FNDECL) ix86_reg_parm_stack_space (FNDECL) + +#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) (ix86_function_type_abi (FNTYPE) == MS_ABI ? 1 : 0) + +extern unsigned int ix86_reg_parm_stack_space (const_tree); /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. @@ -1686,6 +1703,8 @@ typedef struct ix86_args { int maybe_vaarg; /* true for calls to possibly vardic fncts. */ int float_in_sse; /* 1 if in 32-bit mode SFmode (2 for DFmode) should be passed in SSE registers. Otherwise 0. */ + int call_abi; /* Set to SYSV_ABI for sysv abi. Otherwise + MS_ABI for ms abi. */ } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS @@ -1953,9 +1972,22 @@ do { \ is also used as the pic register in ELF. So for now, don't allow more than 3 registers to be passed in registers. */ -#define REGPARM_MAX (TARGET_64BIT ? 6 : 3) +/* Abi specific values for REGPARM_MAX and SSE_REGPARM_MAX */ +#define X86_64_REGPARM_MAX 6 +#define X64_REGPARM_MAX 4 +#define X86_32_REGPARM_MAX 3 + +#define X86_64_SSE_REGPARM_MAX 8 +#define X64_SSE_REGPARM_MAX 4 +#define X86_32_SSE_REGPARM_MAX (TARGET_SSE ? 3 : 0) + +#define REGPARM_MAX (TARGET_64BIT ? (TARGET_64BIT_MS_ABI ? X64_REGPARM_MAX \ + : X86_64_REGPARM_MAX) \ + : X86_32_REGPARM_MAX) -#define SSE_REGPARM_MAX (TARGET_64BIT ? 8 : (TARGET_SSE ? 3 : 0)) +#define SSE_REGPARM_MAX (TARGET_64BIT ? (TARGET_64BIT_MS_ABI ? X64_SSE_REGPARM_MAX \ + : X86_64_SSE_REGPARM_MAX) \ + : X86_32_SSE_REGPARM_MAX) #define MMX_REGPARM_MAX (TARGET_64BIT ? 0 : (TARGET_MMX ? 3 : 0)) @@ -2464,6 +2496,9 @@ struct machine_function GTY(()) ix86_current_function_calls_tls_descriptor macro for a better approximation. */ int tls_descriptor_call_expanded_p; + /* This value is used for amd64 targets and specifies the current abi + to be used. MS_ABI means ms abi. Otherwise SYSV_ABI means sysv abi. */ + int call_abi; }; #define ix86_stack_locals (cfun->machine->stack_locals) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 2eec13e..ba438fe 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -14708,7 +14708,10 @@ ix86_expand_call ((TARGET_FLOAT_RETURNS_IN_80387 ? gen_rtx_REG (XCmode, FIRST_FLOAT_REG) : NULL), - operands[0], const0_rtx, GEN_INT (SSE_REGPARM_MAX - 1), + operands[0], const0_rtx, + GEN_INT ((DEFAULT_ABI == SYSV_ABI ? X86_64_SSE_REGPARM_MAX + : X64_SSE_REGPARM_MAX) + - 1), NULL, 0); for (i = 0; i < XVECLEN (operands[2], 0); i++) @@ -20846,14 +20849,14 @@ (use (match_operand:DI 2 "const_int_operand" "i")) (use (label_ref:DI (match_operand 3 "" "X")))] "TARGET_64BIT - && INTVAL (operands[4]) + SSE_REGPARM_MAX * 16 - 16 < 128 + && INTVAL (operands[4]) + X86_64_SSE_REGPARM_MAX * 16 - 16 < 128 && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128" { int i; operands[0] = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, operands[0], operands[4])); output_asm_insn ("jmp\t%A1", operands); - for (i = SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--) + for (i = X86_64_SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--) { operands[4] = adjust_address (operands[0], DImode, i*16); operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i)); diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index 3a3b74c..7628896 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see builtin_define_std ("WINNT"); \ builtin_define_with_int_value ("_INTEGRAL_MAX_BITS", \ TYPE_PRECISION (intmax_type_node));\ - if (TARGET_64BIT_MS_ABI) \ + if (TARGET_64BIT && DEFAULT_ABI == MS_ABI) \ { \ builtin_define ("__MINGW64__"); \ builtin_define_std ("WIN64"); \ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 103af2c..9c02560 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2508,6 +2508,19 @@ instruction). Caveat: such addressing is by definition not position independent and hence this attribute must not be used for objects defined by shared libraries. +@item ms_abi/sysv_abi +@cindex @code[ms_abi} attribute +@cindex @code{sysv_abi} attribute + +On 64-bit x86_65-*-* targets, you can use an ABI attribute to indicate +which calling convention should be used for a function. The @code{ms_abi} +attribute tells the compiler to use the Microsoft ABI, while the +@code{sysv_abi} attribute tells the compiler to use the ABI used on +GNU/Linux and other systems. The default is to use the Microsoft ABI +when targeting Windows. On all other systems, the default is the AMD ABI. + +Note, This feature is currently sorried out for Windows targets trying to + @item naked @cindex function without a prologue/epilogue code Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate that diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 3e4d2b7..d18bf2e 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4055,6 +4055,15 @@ arguments are passed on the stack, there is no need to store anything in should not be empty, so use @code{int}. @end defmac +@defmac OVERRIDE_ABI_FORMAT (@var{fndecl}) +If defined, this macro is called before generating any code for a +function, but after the @var{cfun} descriptor for the function has been +created. The back end may use this macro to update @var{cfun} to +reflect an ABI other than that which would normally be used by default. +If the compiler is generating code for a compiler-generated function, +@var{fndecl} may be @code{NULL}. +@end defmac + @defmac INIT_CUMULATIVE_ARGS (@var{cum}, @var{fntype}, @var{libname}, @var{fndecl}, @var{n_named_args}) A C statement (sans semicolon) for initializing the variable @var{cum} for the state at the beginning of the argument list. The diff --git a/gcc/function.c b/gcc/function.c index bb4a2e6..30dd9f3 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3852,6 +3852,10 @@ allocate_struct_function (tree fndecl, bool abstract_p) if (init_machine_status) cfun->machine = (*init_machine_status) (); +#ifdef OVERRIDE_ABI_FORMAT + OVERRIDE_ABI_FORMAT (fndecl); +#endif + if (fndecl != NULL_TREE) { DECL_STRUCT_FUNCTION (fndecl) = cfun; diff --git a/gcc/target-def.h b/gcc/target-def.h index 19e882f..69b6169 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -545,9 +545,7 @@ #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false #define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null -#ifndef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY default_return_in_memory -#endif #define TARGET_RETURN_IN_MSB hook_bool_const_tree_false #define TARGET_EXPAND_BUILTIN_SAVEREGS default_expand_builtin_saveregs -- 2.7.4