return NULL_TREE;
}
- /* Can combine regparm with all attributes but fastcall. */
+ /* Can combine regparm with all attributes but fastcall, and thiscall. */
if (is_attribute_p ("regparm", name))
{
tree cst;
return NULL_TREE;
}
-/* This function checks if the method-function has default __thiscall
- calling-convention for 32-bit msabi.
- It returns true if TYPE is of kind METHOD_TYPE, no stdarg function,
- and the MS_ABI 32-bit is used. Otherwise it returns false. */
+/* This function determines from TYPE the calling-convention. */
-static bool
-ix86_is_msabi_thiscall (const_tree type)
+unsigned int
+ix86_get_callcvt (const_tree type)
{
- if (TARGET_64BIT || ix86_function_type_abi (type) != MS_ABI
- || TREE_CODE (type) != METHOD_TYPE || stdarg_p (type))
- return false;
- /* Check for different calling-conventions. */
- if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (type))
- || lookup_attribute ("stdcall", TYPE_ATTRIBUTES (type))
- || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type))
- || lookup_attribute ("regparm", TYPE_ATTRIBUTES (type))
- || lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type)))
- return false;
- return true;
-}
+ unsigned int ret = 0;
+ bool is_stdarg;
+ tree attrs;
-/* This function checks if the thiscall attribute is set for the TYPE,
- or if it is an method-type with default thiscall convention.
- It returns true if function match, otherwise false is returned. */
+ if (TARGET_64BIT)
+ return IX86_CALLCVT_CDECL;
-static bool
-ix86_is_type_thiscall (const_tree type)
-{
- if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type))
- || ix86_is_msabi_thiscall (type))
- return true;
- return false;
+ attrs = TYPE_ATTRIBUTES (type);
+ if (attrs != NULL_TREE)
+ {
+ if (lookup_attribute ("cdecl", attrs))
+ ret |= IX86_CALLCVT_CDECL;
+ else if (lookup_attribute ("stdcall", attrs))
+ ret |= IX86_CALLCVT_STDCALL;
+ else if (lookup_attribute ("fastcall", attrs))
+ ret |= IX86_CALLCVT_FASTCALL;
+ else if (lookup_attribute ("thiscall", attrs))
+ ret |= IX86_CALLCVT_THISCALL;
+
+ /* Regparam isn't allowed for thiscall and fastcall. */
+ if ((ret & (IX86_CALLCVT_THISCALL | IX86_CALLCVT_FASTCALL)) == 0)
+ {
+ if (lookup_attribute ("regparm", attrs))
+ ret |= IX86_CALLCVT_REGPARM;
+ if (lookup_attribute ("sseregparm", attrs))
+ ret |= IX86_CALLCVT_SSEREGPARM;
+ }
+
+ if (IX86_BASE_CALLCVT(ret) != 0)
+ return ret;
+ }
+
+ is_stdarg = stdarg_p (type);
+ if (TARGET_RTD && !is_stdarg)
+ return IX86_CALLCVT_STDCALL | ret;
+
+ if (ret != 0
+ || is_stdarg
+ || TREE_CODE (type) != METHOD_TYPE
+ || ix86_function_type_abi (type) != MS_ABI)
+ return IX86_CALLCVT_CDECL | ret;
+
+ return IX86_CALLCVT_THISCALL;
}
/* Return 0 if the attributes for two types are incompatible, 1 if they
static int
ix86_comp_type_attributes (const_tree type1, const_tree type2)
{
- /* Check for mismatch of non-default calling convention. */
- bool is_thiscall = ix86_is_msabi_thiscall (type1);
- const char *const rtdstr = TARGET_RTD ? (is_thiscall ? "thiscall" : "cdecl") : "stdcall";
+ unsigned int ccvt1, ccvt2;
if (TREE_CODE (type1) != FUNCTION_TYPE
&& TREE_CODE (type1) != METHOD_TYPE)
return 1;
- /* Check for mismatched fastcall/regparm types. */
- if ((!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1))
- != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2)))
- || (ix86_function_regparm (type1, NULL)
- != ix86_function_regparm (type2, NULL)))
- return 0;
-
- /* Check for mismatched sseregparm types. */
- if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
- != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
+ ccvt1 = ix86_get_callcvt (type1);
+ ccvt2 = ix86_get_callcvt (type2);
+ if (ccvt1 != ccvt2)
return 0;
-
- /* Check for mismatched thiscall types. */
- if (is_thiscall && !TARGET_RTD)
- {
- if (!lookup_attribute ("cdecl", TYPE_ATTRIBUTES (type1))
- != !lookup_attribute ("cdecl", TYPE_ATTRIBUTES (type2)))
- return 0;
- }
- else if (!is_thiscall || TARGET_RTD)
- {
- if (!lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type1))
- != !lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type2)))
- return 0;
- }
-
- /* Check for mismatched return types (cdecl vs stdcall). */
- if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
- != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
+ if (ix86_function_regparm (type1, NULL)
+ != ix86_function_regparm (type2, NULL))
return 0;
return 1;
{
tree attr;
int regparm;
+ unsigned int ccvt;
if (TARGET_64BIT)
return (ix86_function_type_abi (type) == SYSV_ABI
? X86_64_REGPARM_MAX : X86_64_MS_REGPARM_MAX);
-
+ ccvt = ix86_get_callcvt (type);
regparm = ix86_regparm;
- attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
- if (attr)
+
+ if ((ccvt & IX86_CALLCVT_REGPARM) != 0)
{
- regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
- return regparm;
+ attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type));
+ if (attr)
+ {
+ regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
+ return regparm;
+ }
}
-
- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
return 2;
-
- if (ix86_is_type_thiscall (type))
+ else if ((ccvt & IX86_CALLCVT_THISCALL) != 0)
return 1;
/* Use register calling convention for local functions when possible. */
static int
ix86_return_pops_args (tree fundecl, tree funtype, int size)
{
- int rtd;
+ unsigned int ccvt;
/* None of the 64-bit ABIs pop arguments. */
if (TARGET_64BIT)
return 0;
- rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
+ ccvt = ix86_get_callcvt (funtype);
- /* Cdecl functions override -mrtd, and never pop the stack. */
- if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
- {
- /* Stdcall and fastcall functions will pop the stack if not
- variable args. */
- if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))
- || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype))
- || ix86_is_type_thiscall (funtype))
- rtd = 1;
-
- if (rtd && ! stdarg_p (funtype))
- return size;
- }
+ if ((ccvt & (IX86_CALLCVT_STDCALL | IX86_CALLCVT_FASTCALL
+ | IX86_CALLCVT_THISCALL)) != 0
+ && ! stdarg_p (funtype))
+ return size;
/* Lose any fake structure return argument if it is passed on the stack. */
if (aggregate_value_p (TREE_TYPE (funtype), fundecl)
enum calling_abi
ix86_function_type_abi (const_tree fntype)
{
- if (fntype != NULL)
+ if (fntype != NULL_TREE && TYPE_ATTRIBUTES (fntype) != NULL_TREE)
{
enum calling_abi abi = ix86_abi;
if (abi == SYSV_ABI)
else look for regparm information. */
if (fntype)
{
- if (ix86_is_type_thiscall (fntype))
+ unsigned int ccvt = ix86_get_callcvt (fntype);
+ if ((ccvt & IX86_CALLCVT_THISCALL) != 0)
{
cum->nregs = 1;
cum->fastcall = 1; /* Same first register as in fastcall. */
}
- else if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
{
cum->nregs = 2;
cum->fastcall = 1;
/* Reuse static chain register if it isn't used for parameter
passing. */
- if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2
- && !lookup_attribute ("fastcall",
- TYPE_ATTRIBUTES (TREE_TYPE (decl)))
- && !ix86_is_type_thiscall (TREE_TYPE (decl)))
- return CX_REG;
- else
- return DI_REG;
+ if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2)
+ {
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+ if ((ccvt & (IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL)) == 0)
+ return CX_REG;
+ }
+ return DI_REG;
}
}
else
{
tree fntype;
+ unsigned int ccvt;
+
/* By default in 32-bit mode we use ECX to pass the static chain. */
regno = CX_REG;
fntype = TREE_TYPE (fndecl);
- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
+ ccvt = ix86_get_callcvt (fntype);
+ if ((ccvt & (IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL)) != 0)
{
/* Fastcall functions use ecx/edx for arguments, which leaves
- us with EAX for the static chain. */
- regno = AX_REG;
- }
- else if (ix86_is_type_thiscall (fntype))
- {
- /* Thiscall functions use ecx for arguments, which leaves
- us with EAX for the static chain. */
+ us with EAX for the static chain.
+ Thiscall functions use ecx for arguments, which also
+ leaves us with EAX for the static chain. */
regno = AX_REG;
}
else if (ix86_function_regparm (fntype, fndecl) == 3)
if (nregs > 0 && !stdarg_p (type))
{
int regno;
+ unsigned int ccvt = ix86_get_callcvt (type);
- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
+ if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
regno = aggr ? DX_REG : CX_REG;
- else if (ix86_is_type_thiscall (type))
+ else if ((ccvt & IX86_CALLCVT_THISCALL) != 0)
{
regno = CX_REG;
if (aggr)
else
{
int tmp_regno = CX_REG;
- if (lookup_attribute ("fastcall",
- TYPE_ATTRIBUTES (TREE_TYPE (function)))
- || ix86_is_type_thiscall (TREE_TYPE (function)))
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (function));
+ if ((ccvt & (IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL)) != 0)
tmp_regno = AX_REG;
tmp = gen_rtx_REG (SImode, tmp_regno);
}