summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/i386/cygming.h2
-rw-r--r--gcc/config/i386/i386.c77
-rw-r--r--gcc/config/i386/i386.h3
3 files changed, 76 insertions, 6 deletions
diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h
index 5e9ccb2add4..a726bb4455e 100644
--- a/gcc/config/i386/cygming.h
+++ b/gcc/config/i386/cygming.h
@@ -79,11 +79,13 @@ along with GCC; see the file COPYING3. If not see
builtin_assert ("system=winnt"); \
builtin_define ("__stdcall=__attribute__((__stdcall__))"); \
builtin_define ("__fastcall=__attribute__((__fastcall__))"); \
+ builtin_define ("__thiscall=__attribute__((__thiscall__))"); \
builtin_define ("__cdecl=__attribute__((__cdecl__))"); \
if (!flag_iso) \
{ \
builtin_define ("_stdcall=__attribute__((__stdcall__))"); \
builtin_define ("_fastcall=__attribute__((__fastcall__))"); \
+ builtin_define ("_thiscall=__attribute__((__thiscall__))"); \
builtin_define ("_cdecl=__attribute__((__cdecl__))"); \
} \
/* Even though linkonce works with static libs, this is needed \
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 5387fae6259..f65220c2911 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4395,8 +4395,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
return true;
}
-/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
- calling convention attributes;
+/* Handle "cdecl", "stdcall", "fastcall", "regparm", "thiscall",
+ and "sseregparm" calling convention attributes;
arguments as in struct attribute_spec.handler. */
static tree
@@ -4426,6 +4426,11 @@ ix86_handle_cconv_attribute (tree *node, tree name,
error ("fastcall and regparm attributes are not compatible");
}
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("regparam and thiscall attributes are not compatible");
+ }
+
cst = TREE_VALUE (args);
if (TREE_CODE (cst) != INTEGER_CST)
{
@@ -4471,6 +4476,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
{
error ("fastcall and regparm attributes are not compatible");
}
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("fastcall and thiscall attributes are not compatible");
+ }
}
/* Can combine stdcall with fastcall (redundant), regparm and
@@ -4485,6 +4494,10 @@ ix86_handle_cconv_attribute (tree *node, tree name,
{
error ("stdcall and fastcall attributes are not compatible");
}
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("stdcall and thiscall attributes are not compatible");
+ }
}
/* Can combine cdecl with regparm and sseregparm. */
@@ -4498,6 +4511,28 @@ ix86_handle_cconv_attribute (tree *node, tree name,
{
error ("fastcall and cdecl attributes are not compatible");
}
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("cdecl and thiscall attributes are not compatible");
+ }
+ }
+ else if (is_attribute_p ("thiscall", name))
+ {
+ if (TREE_CODE (*node) != METHOD_TYPE && pedantic)
+ warning (OPT_Wattributes, "%qE attribute is used for none class-method",
+ name);
+ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("stdcall and thiscall attributes are not compatible");
+ }
+ if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("fastcall and thiscall attributes are not compatible");
+ }
+ if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
+ {
+ error ("cdecl and thiscall attributes are not compatible");
+ }
}
/* Can combine sseregparm with all attributes. */
@@ -4531,6 +4566,11 @@ ix86_comp_type_attributes (const_tree type1, const_tree type2)
!= !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
return 0;
+ /* Check for mismatched thiscall types. */
+ 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)))
@@ -4564,6 +4604,9 @@ ix86_function_regparm (const_tree type, const_tree decl)
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
return 2;
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type)))
+ return 1;
+
/* Use register calling convention for local functions when possible. */
if (decl
&& TREE_CODE (decl) == FUNCTION_DECL
@@ -4701,7 +4744,8 @@ ix86_return_pops_args (tree fundecl, tree funtype, int size)
/* 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)))
+ || lookup_attribute ("fastcall", TYPE_ATTRIBUTES (funtype))
+ || lookup_attribute ("thiscall", TYPE_ATTRIBUTES (funtype)))
rtd = 1;
if (rtd && ! stdarg_p (funtype))
@@ -4964,7 +5008,12 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
else look for regparm information. */
if (fntype)
{
- if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
+ if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (fntype)))
+ {
+ cum->nregs = 1;
+ cum->fastcall = 1; /* Same first register as in fastcall. */
+ }
+ else if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
{
cum->nregs = 2;
cum->fastcall = 1;
@@ -8303,6 +8352,8 @@ find_drap_reg (void)
passing. */
if (ix86_function_regparm (TREE_TYPE (decl), decl) <= 2
&& !lookup_attribute ("fastcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl)))
+ && !lookup_attribute ("thiscall",
TYPE_ATTRIBUTES (TREE_TYPE (decl))))
return CX_REG;
else
@@ -20157,6 +20208,12 @@ ix86_static_chain (const_tree fndecl, bool incoming_p)
us with EAX for the static chain. */
regno = AX_REG;
}
+ else if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (fntype)))
+ {
+ /* Thiscall functions use ecx for arguments, which leaves
+ us with EAX for the static chain. */
+ regno = AX_REG;
+ }
else if (ix86_function_regparm (fntype, fndecl) == 3)
{
/* For regparm 3, we have no free call-clobbered registers in
@@ -26124,6 +26181,11 @@ x86_this_parameter (tree function)
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)))
regno = aggr ? DX_REG : CX_REG;
+ /* ???: To be verified. It is not absolutely clear how aggregates
+ have to be treated for thiscall. We assume that they are
+ identical to fastcall. */
+ else if (lookup_attribute ("thiscall", TYPE_ATTRIBUTES (type)))
+ regno = aggr ? DX_REG : CX_REG;
else
{
regno = AX_REG;
@@ -26235,7 +26297,9 @@ x86_output_mi_thunk (FILE *file,
{
int tmp_regno = CX_REG;
if (lookup_attribute ("fastcall",
- TYPE_ATTRIBUTES (TREE_TYPE (function))))
+ TYPE_ATTRIBUTES (TREE_TYPE (function)))
+ || lookup_attribute ("thiscall",
+ TYPE_ATTRIBUTES (TREE_TYPE (function))))
tmp_regno = AX_REG;
tmp = gen_rtx_REG (SImode, tmp_regno);
}
@@ -28975,6 +29039,9 @@ static const struct attribute_spec ix86_attribute_table[] =
/* Fastcall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "fastcall", 0, 0, false, true, true, ix86_handle_cconv_attribute },
+ /* Thiscall attribute says callee is responsible for popping arguments
+ if they are not variable. */
+ { "thiscall", 0, 0, false, true, true, ix86_handle_cconv_attribute },
/* Cdecl attribute says the callee is a normal C declaration */
{ "cdecl", 0, 0, false, true, true, ix86_handle_cconv_attribute },
/* Regparm attribute specifies how many integer arguments are to be
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 0f133593ad8..4b83370c9a6 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -1580,7 +1580,8 @@ typedef struct ix86_args {
int words; /* # words passed so far */
int nregs; /* # registers available for passing */
int regno; /* next available register number */
- int fastcall; /* fastcall calling convention is used */
+ int fastcall; /* fastcall or thiscall calling convention
+ is used */
int sse_words; /* # sse words passed so far */
int sse_nregs; /* # sse registers available for passing */
int warn_avx; /* True when we want to warn about AVX ABI. */