diff options
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/i386/cygming.h | 2 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 77 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 3 |
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. */ |