rtx ix86_compare_op1 = NULL_RTX;
rtx ix86_compare_emitted = NULL_RTX;
+/* Abi specific values for REGPARM_MAX */
+#define X86_64_REGPARM_MAX 6
+#define X86_64_SSE_REGPARM_MAX 8
+
/* 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. */
}
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;
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;
}
\f
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;
static bool error_issued;
if (TARGET_64BIT)
- return regparm;
+ {
+ if (ix86_function_type_abi (type) == DEFAULT_ABI)
+ return regparm;
+ return DEFAULT_ABI != SYSV_ABI ? 6 : 4; /* $$$$ */
+ }
attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
if (attr)
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;
&& 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)
+ {
+ if (DEFAULT_ABI == SYSV_ABI)
+ return lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype)) ? MS_ABI : SYSV_ABI;
+ else
+ return lookup_attribute ("sysv_abi", TYPE_ATTRIBUTES (fntype)) ? SYSV_ABI : MS_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;
+}
+
/* 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. */
/* 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 ? 6 : 4;
+ }
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 ? 8 : 4; /* $$$$ */
+ }
+ }
if (TARGET_MMX)
cum->mmx_nregs = MMX_REGPARM_MAX;
cum->warn_sse = true;
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);
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 ? 8 : 4)) /* $$$$ */
+ : cum->sse_regno)
: -1);
return construct_container (mode, orig_mode, type, 0, cum->nregs,
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);
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)
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;
}
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
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);
return (size != 1 && size != 2 && size != 4 && size != 8);
}
-bool
+static bool
ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
+#ifdef SUBTARGET_RETURN_IN_MEMORY
+ return SUBTARGET_RETURN_IN_MEMORY (type, fntype);
+#else
const enum machine_mode mode = type_natural_mode (type);
- if (TARGET_64BIT_MS_ABI)
+ if (TARGET_64BIT && ix86_function_type_abi (fntype) == MS_ABI)
return return_in_memory_ms_64 (type, mode);
else if (TARGET_64BIT)
return return_in_memory_64 (type, mode);
else
return return_in_memory_32 (type, mode);
+#endif
}
/* Return false iff TYPE is returned in memory. This version is used
return size > 12;
}
-bool
-ix86_i386elf_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
- return (TYPE_MODE (type) == BLKmode
- || (VECTOR_MODE_P (TYPE_MODE (type)) && int_size_in_bytes (type) == 8));
-}
-
-bool
-ix86_i386interix_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
-{
- return (TYPE_MODE (type) == BLKmode
- || (AGGREGATE_TYPE_P (type) && int_size_in_bytes(type) > 8 ));
-}
-
/* When returning SSE vector types, we have a choice of either
(1) being abi incompatible with a -march switch, or
(2) generating an error.
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);
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 ? 6 : 4; /* $$$$ */
if (! cfun->va_list_gpr_size && ! cfun->va_list_fpr_size)
return;
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++)
{
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);
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;
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));
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. */
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);
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 ();
#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;
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;
}
{
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;
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
{
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);
}
/* Initialize the GCC target structure. */
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
+
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE ix86_attribute_table
#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
#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. */
#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. */
#define ORDER_REGS_FOR_LOCAL_ALLOC x86_order_regs_for_local_alloc ()
+/* regclass.c */
+extern void init_regs (void);
+
+#define OVERRIDE_ABI_FORMAT(FNDECL) \
+do { \
+ if (FNDECL == NULL) \
+ cfun->machine->call_abi = DEFAULT_ABI; \
+ else \
+ cfun->machine->call_abi = ix86_function_type_abi (TREE_TYPE (FNDECL)); \
+ if (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 (); \
+ } \
+ } \
+ } while (0)
+
/* Macro to conditionally modify fixed_regs/call_used_regs. */
#define CONDITIONAL_REGISTER_USAGE \
do { \
for (i = FIRST_REX_SSE_REG; i <= LAST_REX_SSE_REG; i++) \
reg_names[i] = ""; \
} \
- if (TARGET_64BIT_MS_ABI) \
- { \
- call_used_regs[4 /*RSI*/] = 0; \
- call_used_regs[5 /*RDI*/] = 0; \
- } \
} while (0)
/* Return number of consecutive hard regs needed starting at reg REGNO
#define GOT_SYMBOL_NAME "_GLOBAL_OFFSET_TABLE_"
-/* A C expression which can inhibit the returning of certain function
- values in registers, based on the type of value. A nonzero value
- says to return the function value in memory, just as large
- structures are always returned. Here TYPE will be a C expression
- of type `tree', representing the data type of the value.
-
- Note that values of mode `BLKmode' must be explicitly handled by
- this macro. Also, the option `-fpcc-struct-return' takes effect
- regardless of this macro. On most systems, it is possible to
- leave the macro undefined; this causes a default definition to be
- used, whose value is the constant 1 for `BLKmode' values, and 0
- otherwise.
-
- Do not use this macro to indicate that structures and unions
- should always be returned in memory. You should instead use
- `DEFAULT_PCC_STRUCT_RETURN' to indicate this. */
-
-#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
-
/* This is overridden by <cygwin.h>. */
#define MS_AGGREGATE_RETURN 0
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.
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
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)