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]

[PATCH] Add sseregparm function attribute for x86


This patch adds __attribute__((sseregparm)) to be able to switch to
SSE/SSE2 register passing conventions for SFmode and DFmode arguments
and return values.  It re-uses the infrastructure we have for changing
calling conventions for (cgraph) local functions.

One open question may be how we want to handle the situation of
calling an external function with SSE calling conventions without
-msse or -msse2 enabled.  With the current patch we warn, but
continue to create (FP regs) code.  I personally would rather
error out for this case, or at least create good (SSE regs) code
and possibly fail at runtime.

Bootstrapped and tested on i686-unknown-linux-gnu and
x86_64-unknown-linux-gnu.

Ok for mainline?

Thanks,
Richard.
2005-06-08  Richard Guenther  <rguenth@gcc.gnu.org>

	* config/i386/i386.c: Add new target attribute sseregparm.
	(ix86_handle_sseregparm_attribute): New function.
	(ix86_function_sseregparm): New function, split out from ...
	(init_cumulative_args): ... here.
	(function_arg_advance, function_arg): Do not use SSE
	registers for SFmode if !TARGET_SSE.
	(ix86_value_regno): Handle return in SSE register for
	sseregparm functions.
	* doc/extend.texi: Document sseregparm target attribute.

	* gcc.dg/i386-sseregparm-1.c: New testcase.
	* gcc.dg/i386-sseregparm-2.c: Likewise.


Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.826
diff -c -3 -p -r1.826 i386.c
*** config/i386/i386.c	8 Jun 2005 05:05:18 -0000	1.826
--- config/i386/i386.c	8 Jun 2005 11:28:20 -0000
*************** const struct attribute_spec ix86_attribu
*** 892,897 ****
--- 892,898 ----
  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_sseregparm_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
*** 1659,1664 ****
--- 1660,1668 ----
    /* Regparm attribute specifies how many integer arguments are to be
       passed in registers.  */
    { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
+   /* Sseregparm attribute says we are using x86_64 calling conventions
+      for FP arguments.  */
+   { "sseregparm", 0, 0, false, true, true, ix86_handle_sseregparm_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_handle_regparm_attribute (tree *nod
*** 1824,1829 ****
--- 1828,1858 ----
    return NULL_TREE;
  }
  
+ /* Handle a "sseregparm" attribute;
+    arguments as in struct attribute_spec.handler.  */
+ static tree
+ ix86_handle_sseregparm_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;
+     }
+ 
+   if (!TARGET_SSE)
+     warning (0, "%qs attribute without SSE enabled changes the ABI",
+ 	     IDENTIFIER_POINTER (name));
+ 
+   return NULL_TREE;
+ }
+ 
  /* Return 0 if the attributes for two types are incompatible, 1 if they
     are compatible, and 2 if they are nearly compatible (which causes a
     warning to be generated).  */
*************** ix86_function_regparm (tree type, tree d
*** 1897,1902 ****
--- 1926,1959 ----
    return regparm;
  }
  
+ /* Return true, if we can pass up to 8 SFmode and DFmode 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.  */
+ 
+ static bool
+ 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)))
+     return 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 && 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;
+     }
+ 
+   return false;
+ }
+ 
  /* 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
*** 2083,2101 ****
        || (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)
--- 2140,2154 ----
        || (fntype && !TYPE_ARG_TYPES (fntype)))
      cum->maybe_vaarg = true;
  
!   /* Set up the number of SSE registers used for passing SFmode
!      and DFmode arguments.  Warn for mismatching ABI.  */
!   if (!cum->maybe_vaarg && !cum->fastcall
!       && ix86_function_sseregparm (fntype, fndecl))
!     {
!       cum->sse_nregs = 8;
!       cum->float_in_sse = true;
!       if (!TARGET_SSE && fndecl)
! 	warning (0, "Calling %qD without SSE enabled", fndecl);
      }
  
    if (TARGET_DEBUG_ARG)
*************** function_arg_advance (CUMULATIVE_ARGS *c
*** 2778,2784 ****
  	  if (!TARGET_SSE2)
  	    break;
  	case SFmode:
! 	  if (!cum->float_in_sse)
  	    break;
  	  /* FALLTHRU */
  
--- 2831,2837 ----
  	  if (!TARGET_SSE2)
  	    break;
  	case SFmode:
! 	  if (!TARGET_SSE || !cum->float_in_sse)
  	    break;
  	  /* FALLTHRU */
  
*************** function_arg (CUMULATIVE_ARGS *cum, enum
*** 2907,2913 ****
  	if (!TARGET_SSE2)
  	  break;
        case SFmode:
! 	if (!cum->float_in_sse)
  	  break;
  	/* FALLTHRU */
        case TImode:
--- 2960,2966 ----
  	if (!TARGET_SSE2)
  	  break;
        case SFmode:
! 	if (!TARGET_SSE || !cum->float_in_sse)
  	  break;
  	/* FALLTHRU */
        case TImode:
*************** ix86_value_regno (enum machine_mode mode
*** 3243,3248 ****
--- 3296,3309 ----
    if (GET_MODE_CLASS (mode) != MODE_FLOAT || !TARGET_FLOAT_RETURNS_IN_80387)
      return 0;
  
+   /* Floating point return values with sseregparm marked functions go
+      in SSE registers.  */
+   if (func && SSE_FLOAT_MODE_P (mode)
+       && lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (TREE_TYPE (func))))
+     {
+       return FIRST_SSE_REG;
+     }
+ 
    /* 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
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	8 Jun 2005 10:50:00 -0000
*************** safe since the loaders there save all re
*** 2141,2146 ****
--- 2149,2167 ----
  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 FP stack.  Functions that take a
+ variable number of arguments or marked with the @code{fastcall}
+ attribute will continue to be passed all of their FP arguments on the
+ FP stack.
+ 
+ Beware that calling external functions with SSE calling conventions
+ and without SSE support enabled with @code{-msse} will invoke
+ undefined behavior at runtime.
+ 
  @item returns_twice
  @cindex @code{returns_twice} attribute
  The @code{returns_twice} attribute tells the compiler that a function may


/*  { dg-do compile { target i?86-*-* x86_64-*-* } } */
/*  { dg-options "-O2 -msse2" } */

float essef(float) __attribute__((sseregparm));
double essed(double) __attribute__((sseregparm));
float ssef(float) __attribute__((sseregparm, noinline));
double ssed(double) __attribute__((sseregparm, noinline));
float ssef(float f) { return f; }
double 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 { target i?86-*-* } } */
/*  { dg-options "-mno-sse" } */

float essef(float) __attribute__((sseregparm)); /* { dg-warning "SSE" } */
double essed(double) __attribute__((sseregparm)); /* { dg-warning "SSE" } */
float ssef(float) __attribute__((sseregparm, noinline)); /* { dg-warning "SSE" } */
double ssed(double) __attribute__((sseregparm, noinline)); /* { dg-warning "SSE" } */
float ssef(float f) { return f; } /* { dg-warning "SSE" } */
double 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]