OSDN Git Service

* config/i386/i386.c (ix86_handle_cdecl_attribute): Check for
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 19 Dec 2002 22:00:33 +0000 (22:00 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 19 Dec 2002 22:00:33 +0000 (22:00 +0000)
        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

gcc/ChangeLog
gcc/config/i386/cygwin.h
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/mingw32.h
gcc/config/i386/winnt.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/i386-fastcall-1.c [new file with mode: 0644]

index 07810fd..7ca3375 100644 (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 
index f630d1f..7697898 100644 (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 {                                                                        \
 \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
index e403950..a06a160 100644 (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 *));
index b12a7f2..4ebf16b 100644 (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)
index c1f40dc..964237d 100644 (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};
 \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:
index e7c5e8b..78dd19b 100644 (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 ();                                       \
index bc2527a..89dd007 100644 (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
@@ -334,6 +335,43 @@ i386_pe_mark_dllimport (decl)
 }
 
 /* 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;
index b904c7e..e18ad13 100644 (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
index 0e978c2..2db4a8e 100644 (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.
diff --git a/gcc/testsuite/gcc.dg/i386-fastcall-1.c b/gcc/testsuite/gcc.dg/i386-fastcall-1.c
new file mode 100644 (file)
index 0000000..c286ed3
--- /dev/null
@@ -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) { }