This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] 4th try: Add sseregparm function attribute for x86


Richard Henderson wrote:
> On Wed, Jun 15, 2005 at 10:30:49PM +0200, Richard Guenther wrote:
>>+   /* 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 true;
>>+     }
> 
> 
> This comment is now in error and we'll be introducing a performance
> regression with SSE1 -mfpmath=sse.  For functions that are promoted
> internally from cdecl, we only want floats to be put into SSE registers.
> 
> This can be fixed by returning {0,1,2} from this function, indicating
> what level of SSE parameter passing we'd like, and using that

Hm, indeed.  With your suggested changes, re-bootstrapped and regtested
on i686-pc-linux-gnu and x86_64-unknown-linux-gnu.

Ok for mainline?

Thanks,
Richard.

2005-06-15  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.


Index: doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.254
diff -c -3 -p -r1.254 extend.texi
*** doc/extend.texi	30 May 2005 20:15:46 -0000	1.254
--- doc/extend.texi	15 Jun 2005 17:52:57 -0000
*************** the @code{rtc}.
*** 1752,1760 ****
  @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 format (@var{archetype}, @var{string-index}, @var{first-to-check})
--- 1760,1769 ----
  @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 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})
*************** than 2.96.
*** 2126,2134 ****
  @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
  arguments on the stack.
  
  Beware that on some ELF systems this attribute is unsuitable for
--- 2135,2143 ----
  @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 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
*************** safe since the loaders there save all re
*** 2141,2146 ****
--- 2150,2163 ----
  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: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.437
diff -c -3 -p -r1.437 i386.h
*** config/i386/i386.h	8 Jun 2005 05:05:22 -0000	1.437
--- config/i386/i386.h	16 Jun 2005 09:09:48 -0000
*************** typedef struct ix86_args {
*** 1478,1485 ****
    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.  */
  } CUMULATIVE_ARGS;
  
  /* Initialize a variable CUM of type CUMULATIVE_ARGS
--- 1478,1485 ----
    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;		/* 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: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.829
diff -c -3 -p -r1.829 i386.c
*** config/i386/i386.c	10 Jun 2005 21:45:12 -0000	1.829
--- config/i386/i386.c	16 Jun 2005 09:09:49 -0000
*************** static int ix86_comp_type_attributes (tr
*** 890,897 ****
  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 int ix86_value_regno (enum machine_mode, tree);
  static bool contains_128bit_aligned_vector_p (tree);
  static rtx ix86_struct_value_rtx (tree, int);
--- 890,896 ----
  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_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);
*************** const struct attribute_spec ix86_attribu
*** 1660,1674 ****
    /* { 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 },
    /* 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
       passed in registers.  */
!   { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
  #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
    { "dllimport", 0, 0, false, false, false, handle_dll_attribute },
    { "dllexport", 0, 0, false, false, false, handle_dll_attribute },
--- 1659,1676 ----
    /* { 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_cconv_attribute },
    /* Fastcall attribute says callee is responsible for popping arguments
       if they are not variable.  */
!   { "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_cconv_attribute },
    /* Regparm attribute specifies how many integer arguments are to be
       passed in registers.  */
!   { "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 },
*************** ix86_function_ok_for_sibcall (tree decl,
*** 1743,1801 ****
    return true;
  }
  
! /* Handle a "cdecl", "stdcall", or "fastcall" attribute;
     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)
  {
    if (TREE_CODE (*node) != FUNCTION_TYPE
        && TREE_CODE (*node) != METHOD_TYPE
--- 1745,1759 ----
    return true;
  }
  
! /* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
!    calling convention attributes;
     arguments as in struct attribute_spec.handler.  */
  
  static tree
! 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
*************** ix86_handle_regparm_attribute (tree *nod
*** 1805,1815 ****
        warning (OPT_Wattributes, "%qs attribute only applies to functions",
  	       IDENTIFIER_POINTER (name));
        *no_add_attrs = true;
      }
!   else
      {
        tree cst;
  
        cst = TREE_VALUE (args);
        if (TREE_CODE (cst) != INTEGER_CST)
  	{
--- 1763,1781 ----
        warning (OPT_Wattributes, "%qs attribute only applies to functions",
  	       IDENTIFIER_POINTER (name));
        *no_add_attrs = true;
+       return NULL_TREE;
      }
! 
!   /* 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)
  	{
*************** ix86_handle_regparm_attribute (tree *nod
*** 1825,1836 ****
  	  *no_add_attrs = true;
  	}
  
!       if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node)))
! 	{
  	  error ("fastcall and regparm attributes are not compatible");
  	}
      }
  
    return NULL_TREE;
  }
  
--- 1791,1853 ----
  	  *no_add_attrs = true;
  	}
  
!       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;
  }
  
*************** ix86_comp_type_attributes (tree type1, t
*** 1847,1864 ****
    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)))
      return 0;
!   if (ix86_function_regparm (type1, NULL)
!       != ix86_function_regparm (type2, NULL))
!     return 0;
    return 1;
  }
  
--- 1864,1886 ----
    if (TREE_CODE (type1) != FUNCTION_TYPE)
      return 1;
  
!   /* 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;
! 
    return 1;
  }
  
*************** ix86_function_regparm (tree type, tree d
*** 1907,1912 ****
--- 1929,1975 ----
    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.  */
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2041,2050 ****
    *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;
    if (TARGET_SSE)
      cum->sse_nregs = SSE_REGPARM_MAX;
    if (TARGET_MMX)
--- 2104,2110 ----
    *cum = zero_cum;
  
    /* Set up the number of registers to use for passing arguments.  */
!   cum->nregs = ix86_regparm;
    if (TARGET_SSE)
      cum->sse_nregs = SSE_REGPARM_MAX;
    if (TARGET_MMX)
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2053,2059 ****
    cum->warn_mmx = true;
    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)))
--- 2113,2120 ----
    cum->warn_mmx = true;
    cum->maybe_vaarg = false;
  
!   /* 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)))
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2061,2068 ****
--- 2122,2135 ----
  	  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
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2084,2089 ****
--- 2151,2157 ----
  		  cum->warn_sse = 0;
  		  cum->warn_mmx = 0;
  		  cum->fastcall = 0;
+ 		  cum->float_in_sse = 0;
  		}
  	      cum->maybe_vaarg = true;
  	    }
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2093,2113 ****
        || (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);
  
--- 2161,2166 ----
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 2785,2794 ****
  	  break;
  
  	case DFmode:
! 	  if (!TARGET_SSE2)
  	    break;
  	case SFmode:
! 	  if (!cum->float_in_sse)
  	    break;
  	  /* FALLTHRU */
  
--- 2838,2847 ----
  	  break;
  
  	case DFmode:
! 	  if (cum->float_in_sse < 2)
  	    break;
  	case SFmode:
! 	  if (cum->float_in_sse < 1)
  	    break;
  	  /* FALLTHRU */
  
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 2914,2923 ****
  	  }
  	break;
        case DFmode:
! 	if (!TARGET_SSE2)
  	  break;
        case SFmode:
! 	if (!cum->float_in_sse)
  	  break;
  	/* FALLTHRU */
        case TImode:
--- 2967,2976 ----
  	  }
  	break;
        case DFmode:
! 	if (cum->float_in_sse < 2)
  	  break;
        case SFmode:
! 	if (cum->float_in_sse < 1)
  	  break;
  	/* FALLTHRU */
        case TImode:
*************** ix86_value_regno (enum machine_mode mode
*** 3274,3286 ****
      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)
      {
!       struct cgraph_local_info *i = cgraph_local_info (func);
!       if (i && i->local)
! 	return FIRST_SSE_REG;
      }
  
    return FIRST_FLOAT_REG;
--- 3327,3339 ----
      return 0;
  
    /* Floating point return values in %st(0), except for local functions when
!      SSE math is enabled or for functions with sseregparm attribute.  */
!   if (func && (mode == SFmode || mode == DFmode))
      {
!       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;



/* { 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" } */


/* { 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;
}

/* { 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;
}

/*  { 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" } } */

/*  { 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" } */
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]