* config/i386/i386.opt: New target option -mx87regparm.
authoruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 15 Nov 2006 16:21:58 +0000 (16:21 +0000)
committeruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 15 Nov 2006 16:21:58 +0000 (16:21 +0000)
* config/i386/i386.h (struct ix86_args): Add x87_nregs, x87_regno,
float_in_x87: Add new variables. mmx_words, sse_words: Remove.
(X87_REGPARM_MAX): Define.

* config/i386/i386.c (override_options): Error out for
-mx87regparm but no 80387 support.
(ix86_attribute_table): Add x87regparm.
(ix86_handle_cconv_attribute): Update comments for x87regparm.
(ix86_comp_type_attributes): Check for mismatched x87regparm types.
(ix86_function_x87regparm): New function.
(ix86_function_arg_regno_p): Add X87_REGPARM_MAX 80387 floating
point registers.
(init_cumulative_args): Initialize x87_nregs and float_in_x87
variables.
(function_arg_advance): Process x87_nregs and x87_regno when
floating point argument is to be passed in 80387 register.
(function_arg): Pass XFmode arguments in 80387 registers for local
functions.  Pass SFmode and DFmode arguments to local functions
in 80387 registers when flag_unsafe_math_optimizations is set.

* reg-stack.c (convert_regs_entry): Disable NaN load for
stack registers that are used for argument passing.

* doc/extend.texi: Document x87regparm function attribute.
* doc/invoke.texi: Document -mx87regparm.

testsuite/ChangeLog:

* gcc.target/i386/x87regparm-1.c: New test.
* gcc.target/i386/x87regparm-2.c: New test.
* gcc.target/i386/x87regparm-3.c: New test.
* gcc.target/i386/x87regparm-4.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118859 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.opt
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/reg-stack.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/x87regparm-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/x87regparm-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/x87regparm-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/x87regparm-4.c [new file with mode: 0644]

index 67a5d80..eb0dd2e 100644 (file)
@@ -1,3 +1,33 @@
+2006-11-15  Uros Bizjak  <ubizjak@gmail.com>
+
+       * config/i386/i386.opt: New target option -mx87regparm.
+
+       * config/i386/i386.h (struct ix86_args): Add x87_nregs, x87_regno,
+       float_in_x87: Add new variables. mmx_words, sse_words: Remove.
+       (X87_REGPARM_MAX): Define.
+
+       * config/i386/i386.c (override_options): Error out for
+       -mx87regparm but no 80387 support.
+       (ix86_attribute_table): Add x87regparm.
+       (ix86_handle_cconv_attribute): Update comments for x87regparm.
+       (ix86_comp_type_attributes): Check for mismatched x87regparm types.
+       (ix86_function_x87regparm): New function.
+       (ix86_function_arg_regno_p): Add X87_REGPARM_MAX 80387 floating
+       point registers.
+       (init_cumulative_args): Initialize x87_nregs and float_in_x87
+       variables.
+       (function_arg_advance): Process x87_nregs and x87_regno when
+       floating point argument is to be passed in 80387 register.
+       (function_arg): Pass XFmode arguments in 80387 registers for local
+       functions.  Pass SFmode and DFmode arguments to local functions
+       in 80387 registers when flag_unsafe_math_optimizations is set.
+
+       * reg-stack.c (convert_regs_entry): Disable NaN load for
+       stack registers that are used for argument passing.
+
+       * doc/extend.texi: Document x87regparm function attribute.
+       * doc/invoke.texi: Document -mx87regparm.
+
 2006-11-15  Bernd Schmidt  <bernd.schmidt@analog.com>
 
        * tree-flow.h (multiplier_allowed_in_address_p): Adjust prototype.
index 249b2b6..2583fc0 100644 (file)
@@ -1991,6 +1991,11 @@ override_options (void)
        ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
     }
 
+  /* Accept -mx87regparm only if 80387 support is enabled.  */
+  if (TARGET_X87REGPARM
+      && ! TARGET_80387)
+    error ("-mx87regparm used without 80387 enabled");
+
   /* Accept -msseregparm only if at least SSE support is enabled.  */
   if (TARGET_SSEREGPARM
       && ! TARGET_SSE)
@@ -2298,6 +2303,9 @@ const struct attribute_spec ix86_attribute_table[] =
   /* Regparm attribute specifies how many integer arguments are to be
      passed in registers.  */
   { "regparm",   1, 1, false, true,  true,  ix86_handle_cconv_attribute },
+  /* X87regparm attribute says we are passing floating point arguments
+     in 80387 registers.  */
+  { "x87regparm", 0, 0, 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 },
@@ -2400,8 +2408,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", "x87regparm"
+   and "sseregparm" calling convention attributes;
    arguments as in struct attribute_spec.handler.  */
 
 static tree
@@ -2466,7 +2474,8 @@ ix86_handle_cconv_attribute (tree *node, tree name,
       return NULL_TREE;
     }
 
-  /* Can combine fastcall with stdcall (redundant) and sseregparm.  */
+  /* Can combine fastcall with stdcall (redundant), x87regparm
+     and sseregparm.  */
   if (is_attribute_p ("fastcall", name))
     {
       if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
@@ -2483,8 +2492,8 @@ ix86_handle_cconv_attribute (tree *node, tree name,
        }
     }
 
-  /* Can combine stdcall with fastcall (redundant), regparm and
-     sseregparm.  */
+  /* Can combine stdcall with fastcall (redundant), regparm,
+     x87regparm and sseregparm.  */
   else if (is_attribute_p ("stdcall", name))
     {
       if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
@@ -2497,7 +2506,7 @@ ix86_handle_cconv_attribute (tree *node, tree name,
        }
     }
 
-  /* Can combine cdecl with regparm and sseregparm.  */
+  /* Can combine cdecl with regparm, x87regparm and sseregparm.  */
   else if (is_attribute_p ("cdecl", name))
     {
       if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
@@ -2510,7 +2519,7 @@ ix86_handle_cconv_attribute (tree *node, tree name,
        }
     }
 
-  /* Can combine sseregparm with all attributes.  */
+  /* Can combine x87regparm or sseregparm with all attributes.  */
 
   return NULL_TREE;
 }
@@ -2535,6 +2544,11 @@ ix86_comp_type_attributes (tree type1, tree type2)
          != ix86_function_regparm (type2, NULL)))
     return 0;
 
+  /* Check for mismatched x87regparm types.  */
+  if (!lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type1))
+      != !lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type2)))
+    return 0;
+
   /* Check for mismatched sseregparm types.  */
   if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
       != !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
@@ -2623,6 +2637,48 @@ ix86_function_regparm (tree type, tree decl)
   return regparm;
 }
 
+/* Return 1 if we can pass up to X87_REGPARM_MAX floating point
+   arguments in x87 registers for a function with the indicated
+   TYPE and DECL.  DECL may be NULL when calling function indirectly
+   or considering a libcall.  For local functions, return 2.
+   Otherwise return 0.  */
+
+static int
+ix86_function_x87regparm (tree type, tree decl)
+{
+  /* Use x87 registers to pass floating point arguments if requested
+     by the x87regparm attribute.  */
+  if (TARGET_X87REGPARM
+      || (type
+         && lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type))))
+    {
+      if (!TARGET_80387)
+       {
+         if (decl)
+           error ("Calling %qD with attribute x87regparm without "
+                  "80387 enabled", decl);
+         else
+           error ("Calling %qT with attribute x87regparm without "
+                  "80387 enabled", type);
+         return 0;
+       }
+
+      return 1;
+    }
+
+  /* For local functions, pass up to X87_REGPARM_MAX floating point
+     arguments in x87 registers.  */
+  if (!TARGET_64BIT && decl
+      && flag_unit_at_a_time && !profile_flag)
+    {
+      struct cgraph_local_info *i = cgraph_local_info (decl);
+      if (i && i->local)
+       return 2;
+    }
+
+  return 0;
+}
+
 /* 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
@@ -2742,6 +2798,8 @@ ix86_function_arg_regno_p (int regno)
   int i;
   if (!TARGET_64BIT)
     return (regno < REGPARM_MAX
+           || (TARGET_80387 && FP_REGNO_P (regno)
+               && (regno < FIRST_FLOAT_REG + X87_REGPARM_MAX))
            || (TARGET_MMX && MMX_REGNO_P (regno)
                && (regno < FIRST_MMX_REG + MMX_REGPARM_MAX))
            || (TARGET_SSE && SSE_REGNO_P (regno)
@@ -2805,6 +2863,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
 
   /* Set up the number of registers to use for passing arguments.  */
   cum->nregs = ix86_regparm;
+  if (TARGET_80387)
+    cum->x87_nregs = X87_REGPARM_MAX;
   if (TARGET_SSE)
     cum->sse_nregs = SSE_REGPARM_MAX;
   if (TARGET_MMX)
@@ -2826,6 +2886,10 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
        cum->nregs = ix86_function_regparm (fntype, fndecl);
     }
 
+  /* Set up the number of 80387 registers used for passing
+     floating point arguments.  Warn for mismatching ABI.  */
+  cum->float_in_x87 = ix86_function_x87regparm (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);
@@ -2835,7 +2899,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
      are no variable arguments.  If there are variable arguments, then
      we won't pass anything in registers in 32-bit mode. */
 
-  if (cum->nregs || cum->mmx_nregs || cum->sse_nregs)
+  if (cum->nregs || cum->mmx_nregs
+      || cum->x87_nregs || cum->sse_nregs)
     {
       for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
           param != 0; param = next_param)
@@ -2846,11 +2911,13 @@ init_cumulative_args (CUMULATIVE_ARGS *cum,  /* Argument info to initialize */
              if (!TARGET_64BIT)
                {
                  cum->nregs = 0;
+                 cum->x87_nregs = 0;
                  cum->sse_nregs = 0;
                  cum->mmx_nregs = 0;
                  cum->warn_sse = 0;
                  cum->warn_mmx = 0;
                  cum->fastcall = 0;
+                 cum->float_in_x87 = 0;
                  cum->float_in_sse = 0;
                }
              cum->maybe_vaarg = true;
@@ -3547,13 +3614,40 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            }
          break;
 
+       case SFmode:
+         if (cum->float_in_sse > 0)
+           goto skip_80387;
+
        case DFmode:
-         if (cum->float_in_sse < 2)
+         if (cum->float_in_sse > 1)
+           goto skip_80387;
+
+         /* Because no inherent XFmode->DFmode and XFmode->SFmode
+            rounding takes place when values are passed in x87
+            registers, pass DFmode and SFmode types to local functions
+            only when flag_unsafe_math_optimizations is set.  */
+         if (!cum->float_in_x87
+             || (cum->float_in_x87 == 2
+                 && !flag_unsafe_math_optimizations))
            break;
-       case SFmode:
-         if (cum->float_in_sse < 1)
+
+       case XFmode:
+         if (!cum->float_in_x87)
            break;
-         /* FALLTHRU */
+
+         if (!type || !AGGREGATE_TYPE_P (type))
+           {
+             cum->x87_nregs -= 1;
+             cum->x87_regno += 1;
+             if (cum->x87_nregs <= 0)
+               {
+                 cum->x87_nregs = 0;
+                 cum->x87_regno = 0;
+               }
+           }
+         break;
+
+ skip_80387:
 
        case TImode:
        case V16QImode:
@@ -3564,7 +3658,6 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        case V2DFmode:
          if (!type || !AGGREGATE_TYPE_P (type))
            {
-             cum->sse_words += words;
              cum->sse_nregs -= 1;
              cum->sse_regno += 1;
              if (cum->sse_nregs <= 0)
@@ -3581,7 +3674,6 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        case V2SFmode:
          if (!type || !AGGREGATE_TYPE_P (type))
            {
-             cum->mmx_words += words;
              cum->mmx_nregs -= 1;
              cum->mmx_regno += 1;
              if (cum->mmx_nregs <= 0)
@@ -3646,7 +3738,6 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
   else
     switch (mode)
       {
-       /* For now, pass fp/complex values on the stack.  */
       default:
        break;
 
@@ -3676,13 +3767,35 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
            ret = gen_rtx_REG (mode, regno);
          }
        break;
-      case DFmode:
-       if (cum->float_in_sse < 2)
-         break;
-      case SFmode:
-       if (cum->float_in_sse < 1)
+
+       case SFmode:
+         if (cum->float_in_sse > 0)
+           goto skip_80387;
+
+       case DFmode:
+         if (cum->float_in_sse > 1)
+           goto skip_80387;
+
+         /* Because no inherent XFmode->DFmode and XFmode->SFmode
+            rounding takes place when values are passed in x87
+            registers, pass DFmode and SFmode types to local functions
+            only when flag_unsafe_math_optimizations is set.  */
+         if (!cum->float_in_x87
+             || (cum->float_in_x87 == 2
+                 && !flag_unsafe_math_optimizations))
+           break;
+
+       case XFmode:
+         if (!cum->float_in_x87)
+           break;
+
+         if (!type || !AGGREGATE_TYPE_P (type))
+           if (cum->x87_nregs)
+             ret = gen_rtx_REG (mode, cum->x87_regno + FIRST_FLOAT_REG);
          break;
-       /* FALLTHRU */
+
+ skip_80387:
+
       case TImode:
       case V16QImode:
       case V8HImode:
index c711510..920662d 100644 (file)
@@ -1428,19 +1428,21 @@ enum reg_class
    such as FUNCTION_ARG to determine where the next arg should go.  */
 
 typedef struct ix86_args {
-  int words;                   /* # words passed so far */
   int nregs;                   /* # registers available for passing */
   int regno;                   /* next available register number */
+  int words;                   /* # words passed so far */
   int fastcall;                        /* fastcall calling convention is used */
-  int sse_words;               /* # sse words passed so far */
+  int x87_nregs;               /* # x87 registers available for passing */
+  int x87_regno;               /* # next available x87 register number */
   int sse_nregs;               /* # sse registers available for passing */
-  int warn_sse;                        /* True when we want to warn about SSE ABI.  */
-  int warn_mmx;                        /* True when we want to warn about MMX ABI.  */
   int sse_regno;               /* next available sse register number */
-  int mmx_words;               /* # mmx words passed so far */
+  int warn_sse;                        /* True when we want to warn about SSE ABI.  */
   int mmx_nregs;               /* # mmx registers available for passing */
   int mmx_regno;               /* next available mmx register number */
+  int warn_mmx;                        /* True when we want to warn about MMX ABI.  */
   int maybe_vaarg;             /* true for calls to possibly vardic fncts.  */
+  int float_in_x87;            /* 1 if floating point arguments should
+                                  be passed in 80387 registere.  */
   int float_in_sse;            /* 1 if in 32-bit mode SFmode (2 for DFmode) should
                                   be passed in SSE registers.  Otherwise 0.  */
 } CUMULATIVE_ARGS;
@@ -1727,6 +1729,8 @@ do {                                                      \
 
 #define REGPARM_MAX (TARGET_64BIT ? 6 : 3)
 
+#define X87_REGPARM_MAX 3
+
 #define SSE_REGPARM_MAX (TARGET_64BIT ? 8 : (TARGET_SSE ? 3 : 0))
 
 #define MMX_REGPARM_MAX (TARGET_64BIT ? 0 : (TARGET_MMX ? 3 : 0))
index aa24920..36e0944 100644 (file)
@@ -201,6 +201,10 @@ mssse3
 Target Report Mask(SSSE3)
 Support MMX, SSE, SSE2, SSE3 and SSSE3 built-in functions and code generation
 
+mx87regparm
+Target RejectNegative Mask(X87REGPARM)
+Use x87 register passing conventions to pass floating point arguments
+
 msseregparm
 Target RejectNegative Mask(SSEREGPARM)
 Use SSE register passing conventions for SF and DF mode
index 2a1391e..099e4dd 100644 (file)
@@ -2221,6 +2221,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 x87regparm
+@cindex @code{x87regparm} attribute
+On the Intel x86 with 80387 @code{x87regparm} attribute causes the
+compiler to pass up to 3 floating point arguments in 80387 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 sseregparm
 @cindex @code{sseregparm} attribute
 On the Intel 386 with SSE support, the @code{sseregparm} attribute
index 544467e..1a62289 100644 (file)
@@ -535,8 +535,8 @@ Objective-C and Objective-C++ Dialects}.
 -mmmx  -msse  -msse2 -msse3 -mssse3 -m3dnow @gol
 -mthreads  -mno-align-stringops  -minline-all-stringops @gol
 -mpush-args  -maccumulate-outgoing-args  -m128bit-long-double @gol
--m96bit-long-double  -mregparm=@var{num}  -msseregparm @gol
--mstackrealign @gol
+-m96bit-long-double  -mregparm=@var{num}  -mx87regparm @gol
+-msseregparm @gol  -mstackrealign @gol
 -momit-leaf-frame-pointer  -mno-red-zone -mno-tls-direct-seg-refs @gol
 -mcmodel=@var{code-model} @gol
 -m32  -m64 -mlarge-data-threshold=@var{num}}
@@ -9542,6 +9542,17 @@ function by using the function attribute @samp{regparm}.
 value, including any libraries.  This includes the system libraries and
 startup modules.
 
+@item -mx87regparm
+@opindex mx87regparm
+Use 80387 register passing conventions for floating point arguments.
+You can control this behavior for a specific function by using the
+function attribute @samp{x87regparm}.
+@xref{Function Attributes}.
+
+@strong{Warning:} if you use this switch then you must build all
+modules with the same value, including any libraries.  This includes
+the system libraries and startup modules.
+
 @item -msseregparm
 @opindex msseregparm
 Use SSE register passing conventions for float and double arguments
index 0b8b156..a96b6ef 100644 (file)
@@ -2553,11 +2553,28 @@ print_stack (FILE *file, stack s)
 static int
 convert_regs_entry (void)
 {
+  tree params = DECL_ARGUMENTS (current_function_decl);
+  tree p;
+  HARD_REG_SET incoming_regs;
+  rtx inc_rtx;
+
   int inserted = 0;
   edge e;
   edge_iterator ei;
 
-  /* Load something into each stack register live at function entry.
+  /* Find out which registers were used as argument passing registers.  */
+
+  CLEAR_HARD_REG_SET (incoming_regs);
+  for (p = params; p; p = TREE_CHAIN (p))
+    {
+      inc_rtx = DECL_INCOMING_RTL (p);
+
+      if (REG_P (inc_rtx)
+          && IN_RANGE (REGNO (inc_rtx), FIRST_STACK_REG, LAST_STACK_REG))
+       SET_HARD_REG_BIT (incoming_regs, REGNO (inc_rtx));
+    }
+
+  /* Load something into remaining stack register live at function entry.
      Such live registers can be caused by uninitialized variables or
      functions not returning values on all paths.  In order to keep
      the push/pop code happy, and to not scrog the register stack, we
@@ -2579,6 +2596,10 @@ convert_regs_entry (void)
 
            bi->stack_in.reg[++top] = reg;
 
+           /* Skip argument passing registers.  */
+           if (TEST_HARD_REG_BIT (incoming_regs, reg))
+             continue;
+
            init = gen_rtx_SET (VOIDmode,
                                FP_MODE_REG (FIRST_STACK_REG, SFmode),
                                not_a_num);
index 00b4096..d5f56ee 100644 (file)
@@ -1,3 +1,10 @@
+2006-11-15  Uros Bizjak  <ubizjak@gmail.com>
+
+       * gcc.target/i386/x87regparm-1.c: New test.
+       * gcc.target/i386/x87regparm-2.c: New test.
+       * gcc.target/i386/x87regparm-3.c: New test.
+       * gcc.target/i386/x87regparm-4.c: New test.
+
 2006-11-15  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/27546
diff --git a/gcc/testsuite/gcc.target/i386/x87regparm-1.c b/gcc/testsuite/gcc.target/i386/x87regparm-1.c
new file mode 100644 (file)
index 0000000..fa93401
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fomit-frame-pointer" } */
+/* { dg-require-effective-target ilp32 } */
+
+float foo_f(float) __attribute__((x87regparm));
+double foo_d(double) __attribute__((x87regparm));
+long double foo_ld(long double) __attribute__((x87regparm));
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+void test() 
+{
+  f = foo_f(f);
+  d = foo_d(d);
+  ld = foo_ld(ld);
+}
+
+/* Check that no memory is used to pass arguments.  */
+
+/* { dg-final { scan-assembler-not "\\(%esp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/i386/x87regparm-2.c b/gcc/testsuite/gcc.target/i386/x87regparm-2.c
new file mode 100644 (file)
index 0000000..b28dbc1
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fomit-frame-pointer -mx87regparm" } */
+/* { dg-require-effective-target ilp32 } */
+
+float efoo_f(float);
+double efoo_d(double);
+long double efoo_ld(long double);
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+void test() 
+{
+  f = efoo_f(f);
+  d = efoo_d(d);
+  ld = efoo_ld(ld);
+}
+
+/* Check that no memory is used to pass arguments.  */
+
+/* { dg-final { scan-assembler-not "\\(%esp\\)" } } */
diff --git a/gcc/testsuite/gcc.target/i386/x87regparm-3.c b/gcc/testsuite/gcc.target/i386/x87regparm-3.c
new file mode 100644 (file)
index 0000000..b90ff85
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fomit-frame-pointer" } */
+/* { dg-require-effective-target ilp32 } */
+
+static float __attribute__((noinline)) foo_f(float f) { return f; }
+static double __attribute__((noinline)) foo_d(double d) { return d; }
+static long double __attribute__((noinline)) foo_ld(long double ld) { return ld; }
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+void test() 
+{
+  f = foo_f(f);
+  d = foo_d(d);
+  ld = foo_ld(ld);
+}
+
+/* Check that float and double arguments are passed through memory.  */
+
+/* { dg-final { scan-assembler-times "\\(%esp\\)" 4 } } */
diff --git a/gcc/testsuite/gcc.target/i386/x87regparm-4.c b/gcc/testsuite/gcc.target/i386/x87regparm-4.c
new file mode 100644 (file)
index 0000000..78a6cdd
--- /dev/null
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fomit-frame-pointer -ffast-math" } */
+/* { dg-require-effective-target ilp32 } */
+
+static float __attribute__((noinline)) foo_f(float f) { return f; }
+static double __attribute__((noinline)) foo_d(double d) { return d; }
+static long double __attribute__((noinline)) foo_ld(long double ld) { return ld; }
+
+volatile float f;
+volatile double d;
+volatile long double ld;
+
+void test() 
+{
+  f = foo_f(f);
+  d = foo_d(d);
+  ld = foo_ld(ld);
+}
+
+/* Check that no memory is used to pass arguments.  */
+
+/* { dg-final { scan-assembler-not "\\(%esp\\)" } } */