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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@60337
138bc75d-0d04-0410-961f-
82ee72b054a4
+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
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 (); \
\f
/* 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
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 *));
/* 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
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)
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)
{
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;
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)))
/* 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
}
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
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;
}
}
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)
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 */
\f
#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:
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 (); \
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));
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
}
/* 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 */
}
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. */
}
}
-/* 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)
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;
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
+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.
--- /dev/null
+/* { 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) { }