extend.texi: Document sseregparm target attribute.
authorRichard Guenther <rguenth@gcc.gnu.org>
Thu, 16 Jun 2005 16:39:51 +0000 (16:39 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 16 Jun 2005 16:39:51 +0000 (16:39 +0000)
2005-06-16  Richard Guenther  <rguenth@gcc.gnu.org>

* doc/extend.texi: Document sseregparm target attribute.
Clarify fastcall and regparm documentation.
* config/i386/i386.h: Adjust float_in_sse documentation.
* config/i386/i386.c: Add new target attribute sseregparm.
(ix86_handle_cdecl_attribute, ix86_handle_regparm_attribute):
Merge into ...
(ix86_handle_cconv_attribute): ... here.  Also handle
sseregparm attribute.
(ix86_comp_type_attributes): Compare sseregparm attributes.
(ix86_function_sseregparm): New function, split out from ...
(init_cumulative_args): ... here.  Use to decide use
of SSE registers and error in case of missing support.
(ix86_value_regno): Likewise.
(function_arg_advance): Do not bail out for DFmode if we need
to pass doubles in registers.
(function_arg): Likewise.

* gcc.target/i386/attributes-error.c: New testcase.
* gcc.target/i386/fastcall-sseregparm.c: Likewise.
* gcc.target/i386/regparm-stdcall.c: Likewise.
* gcc.target/i386/sseregparm-1.c: Likewise.
* gcc.target/i386/sseregparm-2.c: Likewise.

From-SVN: r101085

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/attributes-error.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/regparm-stdcall.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/sseregparm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/sseregparm-2.c [new file with mode: 0644]

index 4a6bae3..40e204c 100644 (file)
@@ -1,3 +1,22 @@
+2005-06-16  Richard Guenther  <rguenth@gcc.gnu.org>
+
+       * doc/extend.texi: Document sseregparm target attribute.
+       Clarify fastcall and regparm documentation.
+       * config/i386/i386.h: Adjust float_in_sse documentation.
+       * config/i386/i386.c: Add new target attribute sseregparm.
+       (ix86_handle_cdecl_attribute, ix86_handle_regparm_attribute):
+       Merge into ...
+       (ix86_handle_cconv_attribute): ... here.  Also handle
+       sseregparm attribute.
+       (ix86_comp_type_attributes): Compare sseregparm attributes.
+       (ix86_function_sseregparm): New function, split out from ...
+       (init_cumulative_args): ... here.  Use to decide use
+       of SSE registers and error in case of missing support.
+       (ix86_value_regno): Likewise.
+       (function_arg_advance): Do not bail out for DFmode if we need
+       to pass doubles in registers.
+       (function_arg): Likewise.
+
 2005-06-16  Paolo Bonzini  <bonzini@gnu.org>
             Daniel Jacobowitz  <dan@codesourcery.com>
            Alan Modra <amodra.bigpond.net.au>
index 9ced831..781daee 100644 (file)
@@ -890,8 +890,7 @@ static int ix86_comp_type_attributes (tree, tree);
 static int ix86_function_regparm (tree, tree);
 const struct attribute_spec ix86_attribute_table[];
 static bool ix86_function_ok_for_sibcall (tree, tree);
-static tree ix86_handle_cdecl_attribute (tree *, tree, tree, int, bool *);
-static tree ix86_handle_regparm_attribute (tree *, tree, tree, int, bool *);
+static tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *);
 static int ix86_value_regno (enum machine_mode, tree);
 static bool contains_128bit_aligned_vector_p (tree);
 static rtx ix86_struct_value_rtx (tree, int);
@@ -1660,15 +1659,18 @@ const struct attribute_spec ix86_attribute_table[] =
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
   /* Stdcall attribute says callee is responsible for popping arguments
      if they are not variable.  */
-  { "stdcall",   0, 0, false, true,  true,  ix86_handle_cdecl_attribute },
+  { "stdcall",   0, 0, false, true,  true,  ix86_handle_cconv_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 },
+  { "fastcall",  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_cdecl_attribute },
+  { "cdecl",     0, 0, false, true,  true,  ix86_handle_cconv_attribute },
   /* Regparm attribute specifies how many integer arguments are to be
      passed in registers.  */
-  { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
+  { "regparm",   1, 1, false, true,  true,  ix86_handle_cconv_attribute },
+  /* Sseregparm attribute says we are using x86_64 calling conventions
+     for FP arguments.  */
+  { "sseregparm", 0, 0, false, true, true, ix86_handle_cconv_attribute },
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
   { "dllimport", 0, 0, false, false, false, handle_dll_attribute },
   { "dllexport", 0, 0, false, false, false, handle_dll_attribute },
@@ -1743,59 +1745,15 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
   return true;
 }
 
-/* Handle a "cdecl", "stdcall", or "fastcall" attribute;
+/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
+   calling convention attributes;
    arguments as in struct attribute_spec.handler.  */
-static tree
-ix86_handle_cdecl_attribute (tree *node, tree name,
-                            tree args ATTRIBUTE_UNUSED,
-                            int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
-{
-  if (TREE_CODE (*node) != FUNCTION_TYPE
-      && TREE_CODE (*node) != METHOD_TYPE
-      && TREE_CODE (*node) != FIELD_DECL
-      && TREE_CODE (*node) != TYPE_DECL)
-    {
-      warning (OPT_Wattributes, "%qs attribute only applies to functions",
-              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)
-    {
-      warning (OPT_Wattributes, "%qs attribute ignored",
-              IDENTIFIER_POINTER (name));
-      *no_add_attrs = true;
-    }
 
-  return NULL_TREE;
-}
-
-/* Handle a "regparm" attribute;
-   arguments as in struct attribute_spec.handler.  */
 static tree
-ix86_handle_regparm_attribute (tree *node, tree name, tree args,
-                              int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+ix86_handle_cconv_attribute (tree *node, tree name,
+                                  tree args,
+                                  int flags ATTRIBUTE_UNUSED,
+                                  bool *no_add_attrs)
 {
   if (TREE_CODE (*node) != FUNCTION_TYPE
       && TREE_CODE (*node) != METHOD_TYPE
@@ -1805,11 +1763,19 @@ ix86_handle_regparm_attribute (tree *node, tree name, tree args,
       warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
+      return NULL_TREE;
     }
-  else
+
+  /* Can combine regparm with all attributes but fastcall.  */
+  if (is_attribute_p ("regparm", name))
     {
       tree cst;
 
+      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("fastcall and regparm attributes are not compatible");
+       }
+
       cst = TREE_VALUE (args);
       if (TREE_CODE (cst) != INTEGER_CST)
        {
@@ -1825,12 +1791,63 @@ ix86_handle_regparm_attribute (tree *node, tree name, tree args,
          *no_add_attrs = true;
        }
 
-      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
-       {
+      return NULL_TREE;
+    }
+
+  if (TARGET_64BIT)
+    {
+      warning (OPT_Wattributes, "%qs attribute ignored",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Can combine fastcall with stdcall (redundant) and sseregparm.  */
+  if (is_attribute_p ("fastcall", name))
+    {
+      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("fastcall and cdecl attributes are not compatible");
+       }
+      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("fastcall and stdcall attributes are not compatible");
+       }
+      if (lookup_attribute ("regparm", TYPE_ATTRIBUTES (*node)))
+        {
          error ("fastcall and regparm attributes are not compatible");
        }
     }
 
+  /* Can combine stdcall with fastcall (redundant), regparm and
+     sseregparm.  */
+  else if (is_attribute_p ("stdcall", name))
+    {
+      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("stdcall and cdecl attributes are not compatible");
+       }
+      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("stdcall and fastcall attributes are not compatible");
+       }
+    }
+
+  /* Can combine cdecl with regparm and sseregparm.  */
+  else if (is_attribute_p ("cdecl", name))
+    {
+      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("stdcall and cdecl attributes are not compatible");
+       }
+      if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
+        {
+         error ("fastcall and cdecl attributes are not compatible");
+       }
+    }
+
+  /* Can combine sseregparm with all attributes.  */
+
   return NULL_TREE;
 }
 
@@ -1847,18 +1864,23 @@ ix86_comp_type_attributes (tree type1, tree 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)))
+  /* Check for mismatched fastcall/regparm types.  */
+  if ((!lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type1))
+       != !lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type2)))
+      || (ix86_function_regparm (type1, NULL)
+         != ix86_function_regparm (type2, NULL)))
+    return 0;
+
+  /* Check for mismatched sseregparm types.  */
+  if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
+      != !lookup_attribute ("sseregparm", 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)))
     return 0;
-  if (ix86_function_regparm (type1, NULL)
-      != ix86_function_regparm (type2, NULL))
-    return 0;
+
   return 1;
 }
 \f
@@ -1907,6 +1929,47 @@ ix86_function_regparm (tree type, tree decl)
   return regparm;
 }
 
+/* Return 1 or 2, if we can pass up to 8 SFmode (1) and DFmode (2) arguments
+   in SSE registers for a function with the indicated TYPE and DECL.
+   DECL may be NULL when calling function indirectly
+   or considering a libcall.  Otherwise return 0.  */
+
+static int
+ix86_function_sseregparm (tree type, tree decl)
+{
+  /* Use SSE registers to pass SFmode and DFmode arguments if requested
+     by the sseregparm attribute.  */
+  if (type
+      && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type)))
+    {
+      if (!TARGET_SSE)
+       {
+         if (decl)
+           error ("Calling %qD with attribute sseregparm without "
+                  "SSE/SSE2 enabled", decl);
+         else
+           error ("Calling %qT with attribute sseregparm without "
+                  "SSE/SSE2 enabled", type);
+         return 0;
+       }
+
+      return 2;
+    }
+
+  /* For local functions, pass SFmode (and DFmode for SSE2) arguments
+     in SSE registers even for 32-bit mode and not just 3, but up to
+     8 SSE arguments in registers.  */
+  if (!TARGET_64BIT && decl
+      && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
+    {
+      struct cgraph_local_info *i = cgraph_local_info (decl);
+      if (i && i->local)
+       return TARGET_SSE2 ? 2 : 1;
+    }
+
+  return 0;
+}
+
 /* Return true if EAX is live at the start of the function.  Used by
    ix86_expand_prologue to determine if we need special help before
    calling allocate_stack_worker.  */
@@ -2041,10 +2104,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
   *cum = zero_cum;
 
   /* Set up the number of registers to use for passing arguments.  */
-  if (fntype)
-    cum->nregs = ix86_function_regparm (fntype, fndecl);
-  else
-    cum->nregs = ix86_regparm;
+  cum->nregs = ix86_regparm;
   if (TARGET_SSE)
     cum->sse_nregs = SSE_REGPARM_MAX;
   if (TARGET_MMX)
@@ -2053,7 +2113,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
   cum->warn_mmx = true;
   cum->maybe_vaarg = false;
 
-  /* Use ecx and edx registers if function has fastcall attribute */
+  /* Use ecx and edx registers if function has fastcall attribute,
+     else look for regparm information.  */
   if (fntype && !TARGET_64BIT)
     {
       if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (fntype)))
@@ -2061,8 +2122,14 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
          cum->nregs = 2;
          cum->fastcall = 1;
        }
+      else
+       cum->nregs = ix86_function_regparm (fntype, fndecl);
     }
 
+  /* Set up the number of SSE registers used for passing SFmode
+     and DFmode arguments.  Warn for mismatching ABI.  */
+  cum->float_in_sse = ix86_function_sseregparm (fntype, fndecl);
+
   /* 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
@@ -2084,6 +2151,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
                  cum->warn_sse = 0;
                  cum->warn_mmx = 0;
                  cum->fastcall = 0;
+                 cum->float_in_sse = 0;
                }
              cum->maybe_vaarg = true;
            }
@@ -2093,21 +2161,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
       || (fntype && !TYPE_ARG_TYPES (fntype)))
     cum->maybe_vaarg = true;
 
-  /* For local functions, pass SFmode (and DFmode for SSE2) arguments
-     in SSE registers even for 32-bit mode and not just 3, but up to
-     8 SSE arguments in registers.  */
-  if (!TARGET_64BIT && !cum->maybe_vaarg && !cum->fastcall
-      && cum->sse_nregs == SSE_REGPARM_MAX && fndecl
-      && TARGET_SSE_MATH && flag_unit_at_a_time && !profile_flag)
-    {
-      struct cgraph_local_info *i = cgraph_local_info (fndecl);
-      if (i && i->local)
-       {
-         cum->sse_nregs = 8;
-         cum->float_in_sse = true;
-       }
-    }
-
   if (TARGET_DEBUG_ARG)
     fprintf (stderr, ", nregs=%d )\n", cum->nregs);
 
@@ -2785,10 +2838,10 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          break;
 
        case DFmode:
-         if (!TARGET_SSE2)
+         if (cum->float_in_sse < 2)
            break;
        case SFmode:
-         if (!cum->float_in_sse)
+         if (cum->float_in_sse < 1)
            break;
          /* FALLTHRU */
 
@@ -2914,10 +2967,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
          }
        break;
       case DFmode:
-       if (!TARGET_SSE2)
+       if (cum->float_in_sse < 2)
          break;
       case SFmode:
-       if (!cum->float_in_sse)
+       if (cum->float_in_sse < 1)
          break;
        /* FALLTHRU */
       case TImode:
@@ -3274,13 +3327,13 @@ ix86_value_regno (enum machine_mode mode, tree func)
     return 0;
 
   /* Floating point return values in %st(0), except for local functions when
-     SSE math is enabled.  */
-  if (func && SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH
-      && flag_unit_at_a_time)
+     SSE math is enabled or for functions with sseregparm attribute.  */
+  if (func && (mode == SFmode || mode == DFmode))
     {
-      struct cgraph_local_info *i = cgraph_local_info (func);
-      if (i && i->local)
-       return FIRST_SSE_REG;
+      int sse_level = ix86_function_sseregparm (TREE_TYPE (func), func);
+      if ((sse_level >= 1 && mode == SFmode)
+         || (sse_level == 2 && mode == DFmode))
+        return FIRST_SSE_REG;
     }
 
   return FIRST_FLOAT_REG;
index c9c4cfc..3358948 100644 (file)
@@ -1478,8 +1478,8 @@ typedef struct ix86_args {
   int mmx_nregs;               /* # mmx registers available for passing */
   int mmx_regno;               /* next available mmx register number */
   int maybe_vaarg;             /* true for calls to possibly vardic fncts.  */
-  int float_in_sse;            /* true if in 32-bit mode SFmode/DFmode should
-                                  be passed in SSE registers.  */
+  int float_in_sse;            /* 1 if in 32-bit mode SFmode (2 for DFmode) should
+                                  be passed in SSE registers.  Otherwise 0.  */
 } CUMULATIVE_ARGS;
 
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
index 7d83c2b..6a31e9c 100644 (file)
@@ -1752,9 +1752,10 @@ the @code{rtc}.
 @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
+pass the first argument (if of integral type) in the register ECX and
+the second argument (if of integral type) in the register EDX@.  Subsequent
+and other typed 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 format (@var{archetype}, @var{string-index}, @var{first-to-check})
@@ -2126,9 +2127,9 @@ than 2.96.
 @cindex @code{regparm} attribute
 @cindex functions that are passed arguments in registers on the 386
 On the Intel 386, the @code{regparm} attribute causes the compiler to
-pass up to @var{number} integer arguments in registers EAX,
-EDX, and ECX instead of on the stack.  Functions that take a
-variable number of arguments will continue to be passed all of their
+pass arguments number one to @var{number} if they are of integral type
+in registers EAX, EDX, and ECX instead of on the stack.  Functions that
+take a variable number of arguments will continue to be passed all of their
 arguments on the stack.
 
 Beware that on some ELF systems this attribute is unsuitable for
@@ -2141,6 +2142,14 @@ safe since the loaders there save all registers.  (Lazy binding can be
 disabled with the linker or the loader if desired, to avoid the
 problem.)
 
+@item sseregparm
+@cindex @code{sseregparm} attribute
+On the Intel 386 with SSE support, the @code{sseregparm} attribute
+causes the compiler to pass up to 8 floating point arguments in
+SSE registers instead of on the stack.  Functions that take a
+variable number of arguments will continue to pass all of their
+floating point arguments on the stack.
+
 @item returns_twice
 @cindex @code{returns_twice} attribute
 The @code{returns_twice} attribute tells the compiler that a function may
index 34f4fe5..09f9d71 100644 (file)
@@ -1,3 +1,11 @@
+2005-06-16  Richard Guenther  <rguenth@gcc.gnu.org>
+
+       * gcc.target/i386/attributes-error.c: New testcase.
+       * gcc.target/i386/fastcall-sseregparm.c: Likewise.
+       * gcc.target/i386/regparm-stdcall.c: Likewise.
+       * gcc.target/i386/sseregparm-1.c: Likewise.
+       * gcc.target/i386/sseregparm-2.c: Likewise.
+
 2005-06-16  Nathan Sidwell  <nathan@codesourcery.com>
 
        * g++.dg/rtti/crash2.C: New.
diff --git a/gcc/testsuite/gcc.target/i386/attributes-error.c b/gcc/testsuite/gcc.target/i386/attributes-error.c
new file mode 100644 (file)
index 0000000..05c2129
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile { target i?86-*-* } } */
+
+void foo1(int i, int j) __attribute__((fastcall, cdecl)); /* { dg-error "not compatible" } */
+void foo2(int i, int j) __attribute__((fastcall, stdcall)); /* { dg-error "not compatible" } */
+void foo3(int i, int j) __attribute__((fastcall, regparm(2))); /* { dg-error "not compatible" } */
+void foo4(int i, int j) __attribute__((stdcall, cdecl)); /* { dg-error "not compatible" } */
+void foo5(int i, int j) __attribute__((stdcall, fastcall)); /* { dg-error "not compatible" } */
+void foo6(int i, int j) __attribute__((cdecl, fastcall)); /* { dg-error "not compatible" } */
+void foo7(int i, int j) __attribute__((cdecl, stdcall)); /* { dg-error "not compatible" } */
+void foo8(int i, int j) __attribute__((regparm(2), fastcall)); /* { dg-error "not compatible" } */
+
diff --git a/gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c b/gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c
new file mode 100644 (file)
index 0000000..e711411
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-mpreferred-stack-boundary=4 -msse" } */
+
+extern void abort(void);
+
+void __attribute__((fastcall, sseregparm)) foo(int i, int j, float x)
+{
+  static int last_align = -1;
+  int dummy, align = (int)&dummy & 15;
+  if (last_align < 0)
+    last_align = align;
+  else if (align != last_align)
+    abort ();
+}
+
+int main()
+{
+       foo(0,0,0.0);
+       foo(0,0,0.0);
+       return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/regparm-stdcall.c b/gcc/testsuite/gcc.target/i386/regparm-stdcall.c
new file mode 100644 (file)
index 0000000..6605e79
--- /dev/null
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options -mpreferred-stack-boundary=4 } */
+
+extern void abort(void);
+
+void __attribute__((regparm(2), stdcall)) foo(int i, int j, float x)
+{
+  static int last_align = -1;
+  int dummy, align = (int)&dummy & 15;
+  if (last_align < 0)
+    last_align = align;
+  else if (align != last_align)
+    abort ();
+}
+
+int main()
+{
+       foo(0,0,0.0);
+       foo(0,0,0.0);
+       return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sseregparm-1.c b/gcc/testsuite/gcc.target/i386/sseregparm-1.c
new file mode 100644 (file)
index 0000000..afe012b
--- /dev/null
@@ -0,0 +1,18 @@
+/*  { dg-do compile } */
+/*  { dg-options "-O2 -msse" } */
+
+float essef(float) __attribute__((sseregparm));
+double essed(double) __attribute__((sseregparm));
+float __attribute__((sseregparm, noinline)) ssef(float f) { return f; }
+double __attribute__((sseregparm, noinline)) ssed(double d) { return d; }
+extern double d;
+extern float f;
+void test(void)
+{
+  f = essef(f);
+  d = essed(d);
+  f = ssef(f);
+  d = ssed(d);
+}
+
+/* { dg-final { scan-assembler-not "fldl" } } */
diff --git a/gcc/testsuite/gcc.target/i386/sseregparm-2.c b/gcc/testsuite/gcc.target/i386/sseregparm-2.c
new file mode 100644 (file)
index 0000000..32510b9
--- /dev/null
@@ -0,0 +1,16 @@
+/*  { dg-do compile } */
+/*  { dg-options "-mno-sse" } */
+
+float essef(float) __attribute__((sseregparm));
+double essed(double) __attribute__((sseregparm));
+float __attribute__((sseregparm, noinline)) ssef(float f) { return f; } /* { dg-warning "SSE" } */
+double __attribute__((sseregparm, noinline)) ssed(double d) { return d; } /* { dg-warning "SSE" } */
+extern double d;
+extern float f;
+void test(void)
+{
+  f = essef(f); /* { dg-warning "SSE" } */
+  d = essed(d); /* { dg-warning "SSE" } */
+  f = ssef(f); /* { dg-warning "SSE" } */
+  d = ssed(d); /* { dg-warning "SSE" } */
+}