i386.c (ix86_handle_cdecl_attribute): Check for attributes incompatible with fastcall attribute.

* config/i386/i386.c (ix86_handle_cdecl_attribute): Check for
        attributes incompatible with fastcall attribute.
        (ix86_handle_regparm_attribute): Likewise.

        * config/i386/i386.c (ix86_comp_type_attributes): Check for mismatched
        fastcall types.

        * config/i386/cygwin.h (TARGET_OS_CPP_BUILTINS): Add fastcall
        attributes.
        (ASM_OUTPUT_LABELREF): Define as i386_pe_output_labelref.
        * config/i386/i386-protos.h (i386_pe_output_labelref): Declare.
        * config/i386/winnt.c (i386_pe_mark_dllimport). Add __imp_ prefix in
        i386_pe_output_labelref rather than here.
        (gen_fastcall_suffix): New function. Decorates a label name with the
        fastcall prefix (@) and the stdcall suffix.
        (i386_pe_encode_section_info): Call gen_fastcall_suffix() if a symbol
        has a fastcall attribute.
        (i386_pe_output_labelref): New function. Outputs a label reference.
        * config/i386/i386.c (ix86_attribute_table): Accept 'fastcall' as a
        valid attribute.
        (ix86_return_pops_args): Fastcall functions pop the stack.
        (init_cumulative_args): Reserve registers ECX and EDX if function has
        fastcall attribute.
        (function_arg): Use registers ECX and EDX if function has fastcall
        attribute.
        * config/i386/i386.h (CUMULATIVE_ARGS): Add fastcall attribute flag.
        (DLL_IMPORT_EXPORT_PREFIX): Redefine as '#'.
        (FASTCALL_PREFIX): Define as '@'.
        * config/i386/mingw32.h (TARGET_OS_CPP_BUILTINS): Add fastcall
        attributes.
        * doc/extend.texi: Add documentation of fastcall attribute.

        * testsuite/gcc.dg/i386-fastcall-1.c: New.

Co-Authored-By: Danny Smith <dannysmith@users.sourceforge.net>
Co-Authored-By: Eric Kohl <ekohl@rz-online.de>

From-SVN: r60337
This commit is contained in:
Casper S. Hornstrup 2002-12-19 22:00:33 +00:00 committed by Richard Henderson
parent 61138bb628
commit e91f04de4b
10 changed files with 234 additions and 16 deletions

View File

@ -1,3 +1,39 @@
2002-12-19 Casper S. Hornstrup <chorns@users.sourceforge.net>
Danny Smith <dannysmith@users.sourceforge.net>
Eric Kohl <ekohl@rz-online.de>
* config/i386/i386.c (ix86_handle_cdecl_attribute): Check for
attributes incompatible with fastcall attribute.
(ix86_handle_regparm_attribute): Likewise.
* config/i386/i386.c (ix86_comp_type_attributes): Check for mismatched
fastcall types.
* config/i386/cygwin.h (TARGET_OS_CPP_BUILTINS): Add fastcall
attributes.
(ASM_OUTPUT_LABELREF): Define as i386_pe_output_labelref.
* config/i386/i386-protos.h (i386_pe_output_labelref): Declare.
* config/i386/winnt.c (i386_pe_mark_dllimport). Add __imp_ prefix in
i386_pe_output_labelref rather than here.
(gen_fastcall_suffix): New function. Decorates a label name with the
fastcall prefix (@) and the stdcall suffix.
(i386_pe_encode_section_info): Call gen_fastcall_suffix() if a symbol
has a fastcall attribute.
(i386_pe_output_labelref): New function. Outputs a label reference.
* config/i386/i386.c (ix86_attribute_table): Accept 'fastcall' as a
valid attribute.
(ix86_return_pops_args): Fastcall functions pop the stack.
(init_cumulative_args): Reserve registers ECX and EDX if function has
fastcall attribute.
(function_arg): Use registers ECX and EDX if function has fastcall
attribute.
* config/i386/i386.h (CUMULATIVE_ARGS): Add fastcall attribute flag.
(DLL_IMPORT_EXPORT_PREFIX): Redefine as '#'.
(FASTCALL_PREFIX): Define as '@'.
* config/i386/mingw32.h (TARGET_OS_CPP_BUILTINS): Add fastcall
attributes.
* doc/extend.texi: Add documentation of fastcall attribute.
2002-12-19 Nathanael Nerode <neroden@gcc.gnu.org>
* configure.in: FORBUILD when build!=host changed from

View File

@ -61,11 +61,13 @@ Boston, MA 02111-1307, USA. */
builtin_define ("_X86_=1"); \
builtin_assert ("system=winnt"); \
builtin_define ("__stdcall=__attribute__((__stdcall__))"); \
builtin_define ("__fastcall=__attribute__((__fastcall__))"); \
builtin_define ("__cdecl=__attribute__((__cdecl__))"); \
builtin_define ("__declspec(x)=__attribute__((x))"); \
if (!flag_iso) \
{ \
builtin_define ("_stdcall=__attribute__((__stdcall__))"); \
builtin_define ("_fastcall=__attribute__((__fastcall__))"); \
builtin_define ("_cdecl=__attribute__((__cdecl__))"); \
} \
MAYBE_UWIN_CPP_BUILTINS (); \
@ -271,9 +273,7 @@ do { \
/* Output a reference to a label. */
#undef ASM_OUTPUT_LABELREF
#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, \
i386_pe_strip_name_encoding (NAME)) \
#define ASM_OUTPUT_LABELREF i386_pe_output_labelref
/* Output a common block. */
#undef ASM_OUTPUT_COMMON

View File

@ -233,3 +233,4 @@ extern void i386_pe_asm_file_end PARAMS ((FILE *));
extern void i386_pe_encode_section_info PARAMS ((tree, int));
extern const char *i386_pe_strip_name_encoding PARAMS ((const char *));
extern const char *i386_pe_strip_name_encoding_full PARAMS ((const char *));
extern void i386_pe_output_labelref PARAMS ((FILE *, const char *));

View File

@ -1443,6 +1443,9 @@ const struct attribute_spec ix86_attribute_table[] =
/* Stdcall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "stdcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute },
/* Fastcall attribute says callee is responsible for popping arguments
if they are not variable. */
{ "fastcall", 0, 0, false, true, true, ix86_handle_cdecl_attribute },
/* Cdecl attribute says the callee is a normal C declaration */
{ "cdecl", 0, 0, false, true, true, ix86_handle_cdecl_attribute },
/* Regparm attribute specifies how many integer arguments are to be
@ -1510,7 +1513,7 @@ ix86_function_ok_for_sibcall (decl, exp)
return true;
}
/* Handle a "cdecl" or "stdcall" attribute;
/* Handle a "cdecl", "stdcall", or "fastcall" attribute;
arguments as in struct attribute_spec.handler. */
static tree
ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs)
@ -1529,6 +1532,27 @@ ix86_handle_cdecl_attribute (node, name, args, flags, no_add_attrs)
IDENTIFIER_POINTER (name));
*no_add_attrs = true;
}
else
{
if (is_attribute_p ("fastcall", name))
{
if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
{
error ("fastcall and stdcall attributes are not compatible");
}
else if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node)))
{
error ("fastcall and regparm attributes are not compatible");
}
}
else if (is_attribute_p ("stdcall", name))
{
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
{
error ("fastcall and stdcall attributes are not compatible");
}
}
}
if (TARGET_64BIT)
{
@ -1575,6 +1599,11 @@ ix86_handle_regparm_attribute (node, name, args, flags, no_add_attrs)
IDENTIFIER_POINTER (name), REGPARM_MAX);
*no_add_attrs = true;
}
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
{
error ("fastcall and regparm attributes are not compatible");
}
}
return NULL_TREE;
@ -1595,6 +1624,11 @@ ix86_comp_type_attributes (type1, type2)
if (TREE_CODE (type1) != FUNCTION_TYPE)
return 1;
/* Check for mismatched fastcall types */
if (!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1))
!= !lookup_attribute ("fastcall", 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)))
@ -1645,8 +1679,9 @@ ix86_return_pops_args (fundecl, funtype, size)
/* Cdecl functions override -mrtd, and never pop the stack. */
if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
/* Stdcall functions will pop the stack if not variable args. */
if (lookup_attribute ("stdcall", 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)))
rtd = 1;
if (rtd
@ -1732,6 +1767,17 @@ init_cumulative_args (cum, fntype, libname)
}
cum->maybe_vaarg = false;
/* Use ecx and edx registers if function has fastcall attribute */
if (fntype && !TARGET_64BIT)
{
if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
{
cum->nregs = 2;
cum->fastcall = 1;
}
}
/* Determine if this function has variable arguments. This is
indicated by the last argument being 'void_type_mode' if there
are no variable arguments. If there are variable arguments, then
@ -1746,7 +1792,10 @@ init_cumulative_args (cum, fntype, libname)
if (next_param == 0 && TREE_VALUE (param) != void_type_node)
{
if (!TARGET_64BIT)
cum->nregs = 0;
{
cum->nregs = 0;
cum->fastcall = 0;
}
cum->maybe_vaarg = true;
}
}
@ -2396,7 +2445,22 @@ function_arg (cum, mode, type, named)
case HImode:
case QImode:
if (words <= cum->nregs)
ret = gen_rtx_REG (mode, cum->regno);
{
int regno = cum->regno;
/* Fastcall allocates the first two DWORD (SImode) or
smaller arguments to ECX and EDX. */
if (cum->fastcall)
{
if (mode == BLKmode || mode == DImode)
break;
/* ECX not EAX is the first allocated register. */
if (regno == 0)
regno = 2;
}
ret = gen_rtx_REG (mode, regno);
}
break;
case TImode:
if (cum->sse_nregs)

View File

@ -1710,6 +1710,7 @@ 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 sse_words; /* # sse words passed so far */
int sse_nregs; /* # sse registers available for passing */
int sse_regno; /* next available sse register number */
@ -3479,7 +3480,9 @@ enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
#define MACHINE_DEPENDENT_REORG(X) x86_machine_dependent_reorg(X)
#define DLL_IMPORT_EXPORT_PREFIX '@'
#define DLL_IMPORT_EXPORT_PREFIX '#'
#define FASTCALL_PREFIX '@'
/*
Local variables:

View File

@ -50,11 +50,13 @@ Boston, MA 02111-1307, USA. */
builtin_define_std ("WINNT"); \
builtin_define ("_X86_=1"); \
builtin_define ("__stdcall=__attribute__((__stdcall__))"); \
builtin_define ("__fastcall=__attribute__((__fastcall__))"); \
builtin_define ("__cdecl=__attribute__((__cdecl__))"); \
builtin_define ("__declspec(x)=__attribute__((x))"); \
if (!flag_iso) \
{ \
builtin_define ("_stdcall=__attribute__((__stdcall__))"); \
builtin_define ("_fastcall=__attribute__((__fastcall__))"); \
builtin_define ("_cdecl=__attribute__((__cdecl__))"); \
} \
EXTRA_OS_CPP_BUILTINS (); \

View File

@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA. */
static tree associated_type PARAMS ((tree));
const char * gen_stdcall_suffix PARAMS ((tree));
const char * gen_fastcall_suffix PARAMS ((tree));
int i386_pe_dllexport_p PARAMS ((tree));
int i386_pe_dllimport_p PARAMS ((tree));
void i386_pe_mark_dllexport PARAMS ((tree));
@ -315,8 +316,8 @@ i386_pe_mark_dllimport (decl)
return;
}
newname = alloca (strlen (oldname) + 11);
sprintf (newname, "%ci._imp__%s", DLL_IMPORT_EXPORT_PREFIX, oldname);
newname = alloca (strlen (oldname) + 4);
sprintf (newname, "%ci.%s", DLL_IMPORT_EXPORT_PREFIX, oldname);
/* We pass newname through get_identifier to ensure it has a unique
address. RTL processing can sometimes peek inside the symbol ref
@ -333,6 +334,43 @@ i386_pe_mark_dllimport (decl)
DECL_NON_ADDR_CONST_P (decl) = 1;
}
/* Return string which is the former assembler name modified with a
prefix consisting of FASTCALL_PREFIX and a suffix consisting of an
atsign (@) followed by the number of bytes of arguments. */
const char *
gen_fastcall_suffix (decl)
tree decl;
{
int total = 0;
const char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
if (TYPE_ARG_TYPES (TREE_TYPE (decl)))
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
while (TREE_VALUE (formal_type) != void_type_node)
{
int parm_size
= TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
/* Must round up to include padding. This is done the same
way as in store_one_arg. */
parm_size = ((parm_size + PARM_BOUNDARY - 1)
/ PARM_BOUNDARY * PARM_BOUNDARY);
total += parm_size;
formal_type = TREE_CHAIN (formal_type);
}
}
newsym = xmalloc (strlen (asmname) + 11);
sprintf (newsym, "%c%s@%d", FASTCALL_PREFIX, asmname, total/BITS_PER_UNIT);
return IDENTIFIER_POINTER (get_identifier (newsym));
}
/* Return string which is the former assembler name modified with a
suffix consisting of an atsign (@) followed by the number of bytes of
arguments */
@ -389,10 +427,16 @@ i386_pe_encode_section_info (decl, first)
}
if (TREE_CODE (decl) == FUNCTION_DECL)
if (lookup_attribute ("stdcall",
TYPE_ATTRIBUTES (TREE_TYPE (decl))))
XEXP (DECL_RTL (decl), 0) =
gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
{
if (lookup_attribute ("stdcall",
TYPE_ATTRIBUTES (TREE_TYPE (decl))))
XEXP (DECL_RTL (decl), 0) =
gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
else if (lookup_attribute ("fastcall",
TYPE_ATTRIBUTES (TREE_TYPE (decl))))
XEXP (DECL_RTL (decl), 0) =
gen_rtx (SYMBOL_REF, Pmode, gen_fastcall_suffix (decl));
}
/* Mark the decl so we can tell from the rtl whether the object is
dllexport'd or dllimport'd. */
@ -426,7 +470,8 @@ i386_pe_encode_section_info (decl, first)
}
}
/* Strip only the leading encoding, leaving the stdcall suffix. */
/* Strip only the leading encoding, leaving the stdcall suffix and fastcall
prefix if it exists. */
const char *
i386_pe_strip_name_encoding (str)
@ -455,6 +500,44 @@ i386_pe_strip_name_encoding_full (str)
return name;
}
/* Output a reference to a label. Fastcall symbols are prefixed with @,
whereas symbols for functions using other calling conventions don't
have a prefix (unless they are marked dllimport or dllexport). */
void i386_pe_output_labelref (stream, name)
FILE *stream;
const char *name;
{
char prefix[4];
sprintf (prefix, "%ci.", DLL_IMPORT_EXPORT_PREFIX);
if (strncmp (name, prefix, strlen (prefix)) == 0)
{
if (name[3] == FASTCALL_PREFIX)
{
fprintf (stream, "__imp_%s",
i386_pe_strip_name_encoding (name));
}
else
{
fprintf (stream, "__imp__%s",
i386_pe_strip_name_encoding (name));
}
}
else if ((name[0] == FASTCALL_PREFIX)
|| ((name[0] == DLL_IMPORT_EXPORT_PREFIX)
&& (name[3] == FASTCALL_PREFIX)))
{
fprintf (stream, "%s",
i386_pe_strip_name_encoding (name));
}
else
{
fprintf (stream, "%s%s", USER_LABEL_PREFIX,
i386_pe_strip_name_encoding (name));
}
}
void
i386_pe_unique_section (decl, reloc)
tree decl;

View File

@ -2370,6 +2370,14 @@ pass arguments, unless it takes a variable number of arguments.
The PowerPC compiler for Windows NT currently ignores the @code{stdcall}
attribute.
@item fastcall
@cindex functions that pop the argument stack on the 386
On the Intel 386, the @code{fastcall} attribute causes the compiler to
pass the first two arguments in the registers ECX and EDX. Subsequent
arguments are passed on the stack. The called function will pop the
arguments off the stack. If the number of arguments is variable all
arguments are pushed on the stack.
@item cdecl
@cindex functions that do pop the argument stack on the 386
@opindex mrtd

View File

@ -1,3 +1,7 @@
2002-12-19 Casper S. Hornstrup <chorns@users.sourceforge.net>
* gcc.dg/i386-fastcall-1.c: New.
2002-12-19 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.c-torture/execute/20021219-1.c: New test.

View File

@ -0,0 +1,17 @@
/* { dg-do compile { target i386-pc-mingw32* i386-pc-cygwin* } } */
void
__attribute__ ((fastcall))
f1() { }
void
_fastcall
f2() { }
void
__fastcall
f3() { }
int
__attribute__ ((fastcall))
f4(int x, int y, int z) { }