* [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
@ 2011-04-07 13:53 Kai Tietz
2011-04-08 21:10 ` Richard Henderson
0 siblings, 1 reply; 6+ messages in thread
From: Kai Tietz @ 2011-04-07 13:53 UTC (permalink / raw)
To: GCC Patches; +Cc: Richard Henderson
[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]
Hello,
This patch cleans up a bit the calling convention checking in i386
architecture. By this
I could fix some pretty old bugs about the -mrtd option. See as reference
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11772
and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=9601
For none-prototyped function calls nowadays the linker is able to do
the stdcall fixup
successful (avoiding warning via -Wl,--enable-stdcall-fixup). So we
emit for this case
just the undecorated function's symbol name.
ChangeLog
2011-04-07 Kai Tietz
PR target/9601
PR target/11772
* config/i386/i386-protos.h (ix86_get_callcvt): New prototype.
* config/i386/i386.c (ix86_handle_cconv_attribute): Adjust
comment.
(ix86_is_msabi_thiscall): Removed.
(ix86_is_type_thiscall): Likewise.
(ix86_get_callcvt): New function.
(ix86_comp_type_attributes): Simplify check.
(ix86_function_regparm): Use ix86_get_callcvt for calling
convention attribute checks.
(ix86_return_pops_args): Likewise.
(ix86_static_chain): Likewise.
(x86_this_parameter): Likewise.
(x86_output_mi_thunk): Likewise.
* config/i386/i386.h (IX86_CALLCVT_CDECL, IX86_CALLCVT_STDCALL,
IX86_CALLCVT_FASTCALL, IX86_CALLCVT_THISCALL, IX86_CALLCVT_REGPARM,
IX86_CALLCVT_SSEREGPARM): New macros to represent calling convention
by flag-values.
(IX86_BASE_CALLCVT): Helper macro.
* config/i386/netware.c (i386_nlm_maybe_mangle_decl_assembler_name):
Use ix86_get_callcvt for calling convention attribute checks.
* config/i386/winnt.c (i386_pe_maybe_mangle_decl_assembler_name):
Likewise.
(gen_stdcall_or_fastcall_suffix): Handle TARGET_RTD case for
none-prototyped function calls.
Tested for i686-w64-mingw32, x86_64-w64-mingw32, and
x86_64-pc-linux-gnu. Ok for apply?
Regards,
Kai
[-- Attachment #2: cleanup_i386_cvt.txt --]
[-- Type: text/plain, Size: 14750 bytes --]
Index: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h 2011-01-13 20:55:30.000000000 +0100
+++ gcc/gcc/config/i386/i386-protos.h 2011-04-07 11:02:16.645985200 +0200
@@ -191,6 +191,8 @@ extern tree ix86_handle_shared_attribute
extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
extern int x86_field_alignment (tree, int);
extern tree ix86_valid_target_attribute_tree (tree);
+extern unsigned int ix86_get_callcvt (const_tree);
+
#endif
extern rtx ix86_tls_get_addr (void);
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c 2011-04-06 19:13:30.000000000 +0200
+++ gcc/gcc/config/i386/i386.c 2011-04-07 14:51:22.411975800 +0200
@@ -5312,7 +5312,7 @@ ix86_handle_cconv_attribute (tree *node,
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;
@@ -5436,38 +5436,50 @@ ix86_handle_cconv_attribute (tree *node,
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;
-/* 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;
+ if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (type)))
+ ret |= IX86_CALLCVT_CDECL;
+ else if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (type)))
+ ret |= IX86_CALLCVT_STDCALL;
+ else if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
+ ret |= IX86_CALLCVT_FASTCALL;
+ else if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type)))
+ 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", TYPE_ATTRIBUTES (type)))
+ ret |= IX86_CALLCVT_REGPARM;
+ if (lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type)))
+ ret |= IX86_CALLCVT_SSEREGPARM;
+ }
+
+ if (IX86_BASE_CALLCVT(ret) != 0)
+ return ret;
+
+ /* Special case regparm/sseregparm, which are either cdecl or stdcall. */
+ if ((ret & (IX86_CALLCVT_REGPARM | IX86_CALLCVT_SSEREGPARM)) != 0)
+ return (ret | ((TARGET_RTD && !stdarg_p (type)) ? IX86_CALLCVT_STDCALL
+ : IX86_CALLCVT_CDECL));
+
+ /* We don't have found a default call-convention specifier,
+ so apply default. */
+ if (TARGET_RTD && !stdarg_p (type))
+ return IX86_CALLCVT_STDCALL;
+ else if (TREE_CODE (type) != METHOD_TYPE || stdarg_p (type)
+ || ix86_function_type_abi (type) != MS_ABI)
+ return IX86_CALLCVT_CDECL;
+ return IX86_CALLCVT_THISCALL;
}
/* Return 0 if the attributes for two types are incompatible, 1 if they
@@ -5477,43 +5489,18 @@ ix86_is_type_thiscall (const_tree type)
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)))
+ ccvt1 = ix86_get_callcvt (type1);
+ ccvt2 = ix86_get_callcvt (type2);
+ if (ccvt1 != ccvt2)
return 0;
-
- /* Check for mismatched sseregparm types. */
- if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
- != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
- 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;
@@ -5528,23 +5515,26 @@ ix86_function_regparm (const_tree type,
{
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)
return 2;
-
- if (ix86_is_type_thiscall (type))
+ else if (ccvt == IX86_CALLCVT_THISCALL)
return 1;
/* Use register calling convention for local functions when possible. */
@@ -5695,28 +5685,27 @@ ix86_keep_aggregate_return_pointer (tree
static int
ix86_return_pops_args (tree fundecl, tree funtype, int size)
{
- int rtd;
+ int rtd = 0;
+ 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)))
+ switch (IX86_BASE_CALLCVT (ccvt))
{
- /* 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;
+ case IX86_CALLCVT_STDCALL:
+ case IX86_CALLCVT_FASTCALL:
+ case IX86_CALLCVT_THISCALL:
+ rtd = 1;
+ break;
}
+ if (rtd && ! 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)
&& !ix86_keep_aggregate_return_pointer (funtype))
@@ -6048,12 +6037,13 @@ init_cumulative_args (CUMULATIVE_ARGS *c
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)
{
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)
{
cum->nregs = 2;
cum->fastcall = 1;
@@ -9839,13 +9829,14 @@ find_drap_reg (void)
/* 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
+ && ccvt != IX86_CALLCVT_THISCALL)
+ return CX_REG;
+ }
+ return DI_REG;
}
}
@@ -23282,17 +23273,20 @@ ix86_static_chain (const_tree fndecl, bo
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)
{
/* 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))
+ else if (ccvt == IX86_CALLCVT_THISCALL)
{
/* Thiscall functions use ecx for arguments, which leaves
us with EAX for the static chain. */
@@ -29846,10 +29840,11 @@ x86_this_parameter (tree function)
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)
regno = aggr ? DX_REG : CX_REG;
- else if (ix86_is_type_thiscall (type))
+ else if (ccvt == IX86_CALLCVT_THISCALL)
{
regno = CX_REG;
if (aggr)
@@ -29966,9 +29961,9 @@ x86_output_mi_thunk (FILE *file,
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
+ || ccvt == IX86_CALLCVT_THISCALL)
tmp_regno = AX_REG;
tmp = gen_rtx_REG (SImode, tmp_regno);
}
Index: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h 2011-04-03 13:59:54.000000000 +0200
+++ gcc/gcc/config/i386/i386.h 2011-04-07 11:02:37.430624500 +0200
@@ -2368,6 +2368,18 @@ extern void debug_dispatch_window (int);
((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+/* Flags returned by ix86_get_callcvt (). */
+#define IX86_CALLCVT_CDECL 0x1
+#define IX86_CALLCVT_STDCALL 0x2
+#define IX86_CALLCVT_FASTCALL 0x4
+#define IX86_CALLCVT_THISCALL 0x8
+#define IX86_CALLCVT_REGPARM 0x10
+#define IX86_CALLCVT_SSEREGPARM 0x20
+
+#define IX86_BASE_CALLCVT(FLAGS) \
+ ((FLAGS) & (IX86_CALLCVT_CDECL | IX86_CALLCVT_STDCALL \
+ | IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL))
+
/*
Local variables:
version-control: t
Index: gcc/gcc/config/i386/netware.c
===================================================================
--- gcc.orig/gcc/config/i386/netware.c 2010-11-30 21:01:15.000000000 +0100
+++ gcc/gcc/config/i386/netware.c 2011-04-07 13:09:47.983581700 +0200
@@ -148,12 +148,14 @@ i386_nlm_maybe_mangle_decl_assembler_nam
{
tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
tree new_id;
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
- else if (lookup_attribute ("fastcall", type_attributes))
+ else if (ccvt == IX86_CALLCVT_FASTCALL)
new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
- else if ((new_id = lookup_attribute ("regparm", type_attributes)))
+ else if ((cvt & IX86_CALLCVT_REGPARM) != 0
+ && (new_id = lookup_attribute ("regparm", type_attributes)))
new_id = gen_regparm_prefix (decl, id,
TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (new_id))));
else
Index: gcc/gcc/config/i386/winnt.c
===================================================================
--- gcc.orig/gcc/config/i386/winnt.c 2011-01-13 20:55:30.000000000 +0100
+++ gcc/gcc/config/i386/winnt.c 2011-04-07 15:21:42.568606300 +0200
@@ -170,7 +170,7 @@ gen_stdcall_or_fastcall_suffix (tree dec
HOST_WIDE_INT total = 0;
const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
char *new_str, *p;
- tree type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (DECL_ORIGIN (decl));
tree arg;
function_args_iterator args_iter;
@@ -202,7 +202,12 @@ gen_stdcall_or_fastcall_suffix (tree dec
/ parm_boundary_bytes * parm_boundary_bytes);
total += parm_size;
}
- }
+ }
+ else if (TARGET_RTD && fastcall == false)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_RTX;
+
/* Assume max of 8 base 10 digits in the suffix. */
p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
if (fastcall)
@@ -222,10 +227,10 @@ i386_pe_maybe_mangle_decl_assembler_name
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
- else if (lookup_attribute ("fastcall", type_attributes))
+ else if (ccvt == IX86_CALLCVT_FASTCALL)
new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
2011-04-07 13:53 [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772 Kai Tietz
@ 2011-04-08 21:10 ` Richard Henderson
2011-04-09 12:56 ` Kai Tietz
0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2011-04-08 21:10 UTC (permalink / raw)
To: Kai Tietz; +Cc: GCC Patches
> + /* Special case regparm/sseregparm, which are either cdecl or stdcall. */
> + if ((ret & (IX86_CALLCVT_REGPARM | IX86_CALLCVT_SSEREGPARM)) != 0)
> + return (ret | ((TARGET_RTD && !stdarg_p (type)) ? IX86_CALLCVT_STDCALL
> + : IX86_CALLCVT_CDECL));
> +
> + /* We don't have found a default call-convention specifier,
> + so apply default. */
> + if (TARGET_RTD && !stdarg_p (type))
> + return IX86_CALLCVT_STDCALL;
> + else if (TREE_CODE (type) != METHOD_TYPE || stdarg_p (type)
> + || ix86_function_type_abi (type) != MS_ABI)
> + return IX86_CALLCVT_CDECL;
> + return IX86_CALLCVT_THISCALL;
Perhaps clearer as
bool stdarg = stdarg_p (type);
if (TARGET_RTD && !stdarg)
return IX86_CALLCVT_STDCALL | ret;
if (ret != 0
|| stdarg
|| TREE_CODE (type) != METHOD_TYPE
|| ix86_function_type_abi (type) != MS_ABI)
return IX86_CALLCVT_CDECL | ret;
return IX86_CALLCVT_THISCALL;
> + case IX86_CALLCVT_STDCALL:
> + case IX86_CALLCVT_FASTCALL:
> + case IX86_CALLCVT_THISCALL:
> + rtd = 1;
> + break;
> }
>
> + if (rtd && ! stdarg_p (funtype))
> + return size;
You can move the stdarg_p test into the switch and drop the rtd variable.
> + if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
> new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
> + else if (ccvt == IX86_CALLCVT_FASTCALL)
> new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
I think perhaps it would be cleaner to consistently test bits,
rather than sometimes test bits and sometimes test equality.
I know that FASTCALL isn't supposed to have any other bits set,
but we shouldn't have to constantly think about which is which.
Not just here in netware.c, where I noticed, but elsewhere as well.
r~
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
2011-04-08 21:10 ` Richard Henderson
@ 2011-04-09 12:56 ` Kai Tietz
2011-04-10 7:53 ` Kai Tietz
0 siblings, 1 reply; 6+ messages in thread
From: Kai Tietz @ 2011-04-09 12:56 UTC (permalink / raw)
To: Richard Henderson; +Cc: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 3457 bytes --]
2011/4/8 Richard Henderson <rth@redhat.com>:
>> + /* Special case regparm/sseregparm, which are either cdecl or stdcall. */
>> + if ((ret & (IX86_CALLCVT_REGPARM | IX86_CALLCVT_SSEREGPARM)) != 0)
>> + return (ret | ((TARGET_RTD && !stdarg_p (type)) ? IX86_CALLCVT_STDCALL
>> + : IX86_CALLCVT_CDECL));
>> +
>> + /* We don't have found a default call-convention specifier,
>> + so apply default. */
>> + if (TARGET_RTD && !stdarg_p (type))
>> + return IX86_CALLCVT_STDCALL;
>> + else if (TREE_CODE (type) != METHOD_TYPE || stdarg_p (type)
>> + || ix86_function_type_abi (type) != MS_ABI)
>> + return IX86_CALLCVT_CDECL;
>> + return IX86_CALLCVT_THISCALL;
>
> Perhaps clearer as
>
> bool stdarg = stdarg_p (type);
>
> if (TARGET_RTD && !stdarg)
> return IX86_CALLCVT_STDCALL | ret;
>
> if (ret != 0
> || stdarg
> || TREE_CODE (type) != METHOD_TYPE
> || ix86_function_type_abi (type) != MS_ABI)
> return IX86_CALLCVT_CDECL | ret;
>
> return IX86_CALLCVT_THISCALL;
Yes, patch adjusted for this.
>> + case IX86_CALLCVT_STDCALL:
>> + case IX86_CALLCVT_FASTCALL:
>> + case IX86_CALLCVT_THISCALL:
>> + rtd = 1;
>> + break;
>> }
>>
>> + if (rtd && ! stdarg_p (funtype))
>> + return size;
>
> You can move the stdarg_p test into the switch and drop the rtd variable.
Rewrote switch so that just an if is used and the rtd variable isn't
necessary anymore.
>> + if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
>> new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
>> + else if (ccvt == IX86_CALLCVT_FASTCALL)
>> new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
>
> I think perhaps it would be cleaner to consistently test bits,
> rather than sometimes test bits and sometimes test equality.
> I know that FASTCALL isn't supposed to have any other bits set,
> but we shouldn't have to constantly think about which is which.
>
> Not just here in netware.c, where I noticed, but elsewhere as well.
Ok, changed comparison by bit-tests.
2011-04-09 Kai Tietz
PR target/9601
PR target/11772
* config/i386/i386-protos.h (ix86_get_callcvt): New prototype.
* config/i386/i386.c (ix86_handle_cconv_attribute): Adjust
comment.
(ix86_is_msabi_thiscall): Removed.
(ix86_is_type_thiscall): Likewise.
(ix86_get_callcvt): New function.
(ix86_comp_type_attributes): Simplify check.
(ix86_function_regparm): Use ix86_get_callcvt for calling
convention attribute checks.
(ix86_return_pops_args): Likewise.
(ix86_static_chain): Likewise.
(x86_this_parameter): Likewise.
(x86_output_mi_thunk): Likewise.
(ix86_function_type_abi): Optimize check for types without attributes.
* config/i386/i386.h (IX86_CALLCVT_CDECL, IX86_CALLCVT_STDCALL,
IX86_CALLCVT_FASTCALL, IX86_CALLCVT_THISCALL, IX86_CALLCVT_REGPARM,
IX86_CALLCVT_SSEREGPARM): New macros to represent calling convention
by flag-values.
(IX86_BASE_CALLCVT): Helper macro.
* config/i386/netware.c (i386_nlm_maybe_mangle_decl_assembler_name):
Use ix86_get_callcvt for calling convention attribute checks and avoid
symbol-decoration for stdcall in TARGET_RTD case.
* config/i386/winnt.c (i386_pe_maybe_mangle_decl_assembler_name):
Likewise.
(gen_stdcall_or_fastcall_suffix): Adjust ident and use DECL_ORIGIN
for declaration.
Regards,
Kai
[-- Attachment #2: cleanup_i386_cvt.txt --]
[-- Type: text/plain, Size: 15154 bytes --]
Index: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h 2011-04-08 16:00:16.264411500 +0200
+++ gcc/gcc/config/i386/i386-protos.h 2011-04-09 12:38:15.360805300 +0200
@@ -191,6 +191,8 @@ extern tree ix86_handle_shared_attribute
extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
extern int x86_field_alignment (tree, int);
extern tree ix86_valid_target_attribute_tree (tree);
+extern unsigned int ix86_get_callcvt (const_tree);
+
#endif
extern rtx ix86_tls_get_addr (void);
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c 2011-04-08 16:00:16.272411500 +0200
+++ gcc/gcc/config/i386/i386.c 2011-04-09 14:01:32.239610400 +0200
@@ -5312,7 +5312,7 @@ ix86_handle_cconv_attribute (tree *node,
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;
@@ -5436,38 +5436,54 @@ ix86_handle_cconv_attribute (tree *node,
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;
+ const_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
@@ -5477,43 +5493,18 @@ ix86_is_type_thiscall (const_tree type)
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;
@@ -5528,23 +5519,26 @@ ix86_function_regparm (const_tree type,
{
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. */
@@ -5695,27 +5689,18 @@ ix86_keep_aggregate_return_pointer (tree
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)
@@ -5818,7 +5803,7 @@ ix86_reg_parm_stack_space (const_tree fn
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)
@@ -6048,12 +6033,13 @@ init_cumulative_args (CUMULATIVE_ARGS *c
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;
@@ -9839,13 +9825,13 @@ find_drap_reg (void)
/* 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;
}
}
@@ -23282,20 +23268,19 @@ ix86_static_chain (const_tree fndecl, bo
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)
@@ -29846,10 +29831,11 @@ x86_this_parameter (tree function)
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)
@@ -29966,9 +29952,8 @@ x86_output_mi_thunk (FILE *file,
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);
}
Index: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h 2011-04-08 16:00:16.274411500 +0200
+++ gcc/gcc/config/i386/i386.h 2011-04-09 12:38:15.444810100 +0200
@@ -2368,6 +2368,18 @@ extern void debug_dispatch_window (int);
((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+/* Flags returned by ix86_get_callcvt (). */
+#define IX86_CALLCVT_CDECL 0x1
+#define IX86_CALLCVT_STDCALL 0x2
+#define IX86_CALLCVT_FASTCALL 0x4
+#define IX86_CALLCVT_THISCALL 0x8
+#define IX86_CALLCVT_REGPARM 0x10
+#define IX86_CALLCVT_SSEREGPARM 0x20
+
+#define IX86_BASE_CALLCVT(FLAGS) \
+ ((FLAGS) & (IX86_CALLCVT_CDECL | IX86_CALLCVT_STDCALL \
+ | IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL))
+
/*
Local variables:
version-control: t
Index: gcc/gcc/config/i386/netware.c
===================================================================
--- gcc.orig/gcc/config/i386/netware.c 2011-04-08 16:00:16.279411500 +0200
+++ gcc/gcc/config/i386/netware.c 2011-04-09 12:46:52.578388500 +0200
@@ -148,12 +148,20 @@ i386_nlm_maybe_mangle_decl_assembler_nam
{
tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
tree new_id;
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
- new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
- else if (lookup_attribute ("fastcall", type_attributes))
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+ {
+ if (TARGET_RTD)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_TREE;
+ new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
+ }
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
- else if ((new_id = lookup_attribute ("regparm", type_attributes)))
+ else if ((cvt & IX86_CALLCVT_REGPARM) != 0
+ && (new_id = lookup_attribute ("regparm", type_attributes)))
new_id = gen_regparm_prefix (decl, id,
TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (new_id))));
else
Index: gcc/gcc/config/i386/winnt.c
===================================================================
--- gcc.orig/gcc/config/i386/winnt.c 2011-04-08 16:00:16.328411500 +0200
+++ gcc/gcc/config/i386/winnt.c 2011-04-09 12:48:32.982131200 +0200
@@ -170,7 +170,7 @@ gen_stdcall_or_fastcall_suffix (tree dec
HOST_WIDE_INT total = 0;
const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
char *new_str, *p;
- tree type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (DECL_ORIGIN (decl));
tree arg;
function_args_iterator args_iter;
@@ -202,7 +202,8 @@ gen_stdcall_or_fastcall_suffix (tree dec
/ parm_boundary_bytes * parm_boundary_bytes);
total += parm_size;
}
- }
+ }
+
/* Assume max of 8 base 10 digits in the suffix. */
p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
if (fastcall)
@@ -222,10 +223,16 @@ i386_pe_maybe_mangle_decl_assembler_name
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
- new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
- else if (lookup_attribute ("fastcall", type_attributes))
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+ {
+ if (TARGET_RTD)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_TREE;
+ new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
+ }
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
2011-04-09 12:56 ` Kai Tietz
@ 2011-04-10 7:53 ` Kai Tietz
2011-04-11 16:00 ` Richard Henderson
0 siblings, 1 reply; 6+ messages in thread
From: Kai Tietz @ 2011-04-10 7:53 UTC (permalink / raw)
To: Richard Henderson; +Cc: GCC Patches
[-- Attachment #1: Type: text/plain, Size: 81 bytes --]
I had introduced an const issue by recent patch. Attached patch fixes that.
Kai
[-- Attachment #2: cleanup_i386_cvt.txt --]
[-- Type: text/plain, Size: 15148 bytes --]
Index: gcc/gcc/config/i386/i386-protos.h
===================================================================
--- gcc.orig/gcc/config/i386/i386-protos.h 2011-04-08 16:00:16.264411500 +0200
+++ gcc/gcc/config/i386/i386-protos.h 2011-04-09 12:38:15.360805300 +0200
@@ -191,6 +191,8 @@ extern tree ix86_handle_shared_attribute
extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
extern int x86_field_alignment (tree, int);
extern tree ix86_valid_target_attribute_tree (tree);
+extern unsigned int ix86_get_callcvt (const_tree);
+
#endif
extern rtx ix86_tls_get_addr (void);
Index: gcc/gcc/config/i386/i386.c
===================================================================
--- gcc.orig/gcc/config/i386/i386.c 2011-04-08 16:00:16.272411500 +0200
+++ gcc/gcc/config/i386/i386.c 2011-04-09 19:31:13.991227800 +0200
@@ -5312,7 +5312,7 @@ ix86_handle_cconv_attribute (tree *node,
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;
@@ -5436,38 +5436,54 @@ ix86_handle_cconv_attribute (tree *node,
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
@@ -5477,43 +5493,18 @@ ix86_is_type_thiscall (const_tree type)
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;
@@ -5528,23 +5519,26 @@ ix86_function_regparm (const_tree type,
{
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. */
@@ -5695,27 +5689,18 @@ ix86_keep_aggregate_return_pointer (tree
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)
@@ -5818,7 +5803,7 @@ ix86_reg_parm_stack_space (const_tree fn
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)
@@ -6048,12 +6033,13 @@ init_cumulative_args (CUMULATIVE_ARGS *c
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;
@@ -9839,13 +9825,13 @@ find_drap_reg (void)
/* 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;
}
}
@@ -23282,20 +23268,19 @@ ix86_static_chain (const_tree fndecl, bo
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)
@@ -29846,10 +29831,11 @@ x86_this_parameter (tree function)
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)
@@ -29966,9 +29952,8 @@ x86_output_mi_thunk (FILE *file,
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);
}
Index: gcc/gcc/config/i386/i386.h
===================================================================
--- gcc.orig/gcc/config/i386/i386.h 2011-04-08 16:00:16.274411500 +0200
+++ gcc/gcc/config/i386/i386.h 2011-04-09 12:38:15.444810100 +0200
@@ -2368,6 +2368,18 @@ extern void debug_dispatch_window (int);
((VALUE) = GET_MODE_BITSIZE (MODE), TARGET_BMI)
+/* Flags returned by ix86_get_callcvt (). */
+#define IX86_CALLCVT_CDECL 0x1
+#define IX86_CALLCVT_STDCALL 0x2
+#define IX86_CALLCVT_FASTCALL 0x4
+#define IX86_CALLCVT_THISCALL 0x8
+#define IX86_CALLCVT_REGPARM 0x10
+#define IX86_CALLCVT_SSEREGPARM 0x20
+
+#define IX86_BASE_CALLCVT(FLAGS) \
+ ((FLAGS) & (IX86_CALLCVT_CDECL | IX86_CALLCVT_STDCALL \
+ | IX86_CALLCVT_FASTCALL | IX86_CALLCVT_THISCALL))
+
/*
Local variables:
version-control: t
Index: gcc/gcc/config/i386/netware.c
===================================================================
--- gcc.orig/gcc/config/i386/netware.c 2011-04-08 16:00:16.279411500 +0200
+++ gcc/gcc/config/i386/netware.c 2011-04-09 12:46:52.578388500 +0200
@@ -148,12 +148,20 @@ i386_nlm_maybe_mangle_decl_assembler_nam
{
tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
tree new_id;
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
- new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
- else if (lookup_attribute ("fastcall", type_attributes))
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+ {
+ if (TARGET_RTD)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_TREE;
+ new_id = gen_stdcall_or_fastcall_decoration (decl, id, '_');
+ }
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
new_id = gen_stdcall_or_fastcall_decoration (decl, id, FASTCALL_PREFIX);
- else if ((new_id = lookup_attribute ("regparm", type_attributes)))
+ else if ((cvt & IX86_CALLCVT_REGPARM) != 0
+ && (new_id = lookup_attribute ("regparm", type_attributes)))
new_id = gen_regparm_prefix (decl, id,
TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (new_id))));
else
Index: gcc/gcc/config/i386/winnt.c
===================================================================
--- gcc.orig/gcc/config/i386/winnt.c 2011-04-08 16:00:16.328411500 +0200
+++ gcc/gcc/config/i386/winnt.c 2011-04-09 12:48:32.982131200 +0200
@@ -170,7 +170,7 @@ gen_stdcall_or_fastcall_suffix (tree dec
HOST_WIDE_INT total = 0;
const char *old_str = IDENTIFIER_POINTER (id != NULL_TREE ? id : DECL_NAME (decl));
char *new_str, *p;
- tree type = TREE_TYPE (decl);
+ tree type = TREE_TYPE (DECL_ORIGIN (decl));
tree arg;
function_args_iterator args_iter;
@@ -202,7 +202,8 @@ gen_stdcall_or_fastcall_suffix (tree dec
/ parm_boundary_bytes * parm_boundary_bytes);
total += parm_size;
}
- }
+ }
+
/* Assume max of 8 base 10 digits in the suffix. */
p = new_str = XALLOCAVEC (char, 1 + strlen (old_str) + 1 + 8 + 1);
if (fastcall)
@@ -222,10 +223,16 @@ i386_pe_maybe_mangle_decl_assembler_name
if (TREE_CODE (decl) == FUNCTION_DECL)
{
- tree type_attributes = TYPE_ATTRIBUTES (TREE_TYPE (decl));
- if (lookup_attribute ("stdcall", type_attributes))
- new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
- else if (lookup_attribute ("fastcall", type_attributes))
+ unsigned int ccvt = ix86_get_callcvt (TREE_TYPE (decl));
+ if ((ccvt & IX86_CALLCVT_STDCALL) != 0)
+ {
+ if (TARGET_RTD)
+ /* If we are using -mrtd emit undecorated symbol and let linker
+ do the proper resolving. */
+ return NULL_TREE;
+ new_id = gen_stdcall_or_fastcall_suffix (decl, id, false);
+ }
+ else if ((ccvt & IX86_CALLCVT_FASTCALL) != 0)
new_id = gen_stdcall_or_fastcall_suffix (decl, id, true);
}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
2011-04-10 7:53 ` Kai Tietz
@ 2011-04-11 16:00 ` Richard Henderson
2011-04-11 17:45 ` Kai Tietz
0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2011-04-11 16:00 UTC (permalink / raw)
To: Kai Tietz; +Cc: GCC Patches
On 04/10/2011 12:01 AM, Kai Tietz wrote:
> I had introduced an const issue by recent patch. Attached patch fixes that.
Patch is ok.
r~
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772
2011-04-11 16:00 ` Richard Henderson
@ 2011-04-11 17:45 ` Kai Tietz
0 siblings, 0 replies; 6+ messages in thread
From: Kai Tietz @ 2011-04-11 17:45 UTC (permalink / raw)
To: Richard Henderson; +Cc: GCC Patches
2011/4/11 Richard Henderson <rth@redhat.com>:
> On 04/10/2011 12:01 AM, Kai Tietz wrote:
>> I had introduced an const issue by recent patch. Attached patch fixes that.
>
> Patch is ok.
Applied at revision 172268.
Thanks,
Kai
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2011-04-11 17:45 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-07 13:53 [patch i386]: Cleanup calling convention handling in i386.c and fix PR target/9601 and PR target/11772 Kai Tietz
2011-04-08 21:10 ` Richard Henderson
2011-04-09 12:56 ` Kai Tietz
2011-04-10 7:53 ` Kai Tietz
2011-04-11 16:00 ` Richard Henderson
2011-04-11 17:45 ` Kai Tietz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).