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]

[RFC] Prototype for SSE2 calling convention libm on ia32


This patch prototypes calling of SSE2 calling convention libm routines
(with symbols matching Intel libimf) for sin and cos if -mfpmath=sse
and -ffast-math.

It does so by first exposing a new function attribute "fpregparm" that
changes calling conventions for a single function, and second, patching
optabs and builtin decls and honouring it at expansion time.

Comments to the general approach of handling this in the backend?
Suggestions?

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

	* calls.c (expand_call_1): New function from expand_call
	with extra dispatch location argument.
	(expand_call): Wrapper to expand_call_1 with NULL_RTX
	dispatch location.
	* builtins.c (expand_builtin_mathfn_3): Honour optabs
	libfunc entry via expand_call_1.
	* config/i386/i386.c (ix86_handle_fpregparm_attribute): New
	function.
	(init_cummulative_args): Query fpregparm attribute to change
	calling convention.
	(ix86_value_regno): Likewise.
	(ix86_init_builtins): Patch __builtin_sin and cos with
	fpregparm attribute.
	(ix86_init_libfuncs): Target hook for TARGET_INIT_LIBFUNCS.
	Provide alternate libfunc for sin and cos optabs.

Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.389
diff -c -3 -p -r1.389 calls.c
*** calls.c	9 May 2005 17:52:15 -0000	1.389
--- calls.c	7 Jun 2005 17:08:26 -0000
*************** shift_return_value (enum machine_mode mo
*** 1773,1779 ****
     If IGNORE is nonzero, then we ignore the value of the function call.  */
  
  rtx
! expand_call (tree exp, rtx target, int ignore)
  {
    /* Nonzero if we are currently expanding a call.  */
    static int currently_expanding_call = 0;
--- 1773,1781 ----
     If IGNORE is nonzero, then we ignore the value of the function call.  */
  
  rtx
! expand_call_1 (tree exp, rtx target, int ignore, rtx dispatch_to);
! rtx
! expand_call_1 (tree exp, rtx target, int ignore, rtx dispatch_to)
  {
    /* Nonzero if we are currently expanding a call.  */
    static int currently_expanding_call = 0;
*************** expand_call (tree exp, rtx target, int i
*** 2511,2517 ****
  	 be deferred during the evaluation of the arguments.  */
        NO_DEFER_POP;
  
!       funexp = rtx_for_function_call (fndecl, addr);
  
        /* Figure out the register where the value, if any, will come back.  */
        valreg = 0;
--- 2513,2522 ----
  	 be deferred during the evaluation of the arguments.  */
        NO_DEFER_POP;
  
!       if (! dispatch_to)
! 	funexp = rtx_for_function_call (fndecl, addr);
!       else
! 	funexp = dispatch_to;
  
        /* Figure out the register where the value, if any, will come back.  */
        valreg = 0;
*************** expand_call (tree exp, rtx target, int i
*** 3022,3027 ****
--- 3027,3038 ----
    return target;
  }
  
+ rtx
+ expand_call (tree exp, rtx target, int ignore)
+ {
+   return expand_call_1 (exp, target, ignore, NULL_RTX);
+ }
+ 
  /* A sibling call sequence invalidates any REG_EQUIV notes made for
     this function's incoming arguments.
  
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.462
diff -c -3 -p -r1.462 builtins.c
*** builtins.c	17 May 2005 08:59:50 -0000	1.462
--- builtins.c	7 Jun 2005 17:08:46 -0000
*************** expand_builtin_mathfn_2 (tree exp, rtx t
*** 1997,2002 ****
--- 1997,2004 ----
    return target;
  }
  
+ extern rtx expand_call_1 (tree, rtx, int, rtx);
+ 
  /* Expand a call to the builtin sin and cos math functions.
     Return 0 if a normal call should be emitted rather than expanding the
     function in-line.  EXP is the expression that is a call to the builtin
*************** expand_builtin_mathfn_3 (tree exp, rtx t
*** 2123,2129 ****
        end_sequence ();
      }
  
!   target = expand_call (exp, target, target == const0_rtx);
  
    return target;
  }
--- 2125,2132 ----
        end_sequence ();
      }
  
!   target = expand_call_1 (exp, target, target == const0_rtx,
! 			  builtin_optab->handlers[(int) mode].libfunc);
  
    return target;
  }
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.824
diff -c -3 -p -r1.824 i386.c
*** config/i386/i386.c	5 Jun 2005 10:58:28 -0000	1.824
--- config/i386/i386.c	7 Jun 2005 17:09:22 -0000
*************** const struct attribute_spec ix86_attribu
*** 891,896 ****
--- 891,897 ----
  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_fpregparm_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);
*************** static bool ix86_pass_by_reference (CUMU
*** 905,910 ****
--- 906,912 ----
  				    tree, bool);
  static void ix86_init_builtins (void);
  static rtx ix86_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+ static void ix86_init_libfuncs (void);
  
  /* This function is only used on Solaris.  */
  static void i386_solaris_elf_named_section (const char *, unsigned int, tree)
*************** static void init_ext_80387_constants (vo
*** 960,965 ****
--- 962,970 ----
  #undef TARGET_EXPAND_BUILTIN
  #define TARGET_EXPAND_BUILTIN ix86_expand_builtin
  
+ #undef TARGET_INIT_LIBFUNCS
+ #define TARGET_INIT_LIBFUNCS ix86_init_libfuncs
+ 
  #undef TARGET_ASM_FUNCTION_EPILOGUE
  #define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue
  
*************** const struct attribute_spec ix86_attribu
*** 1653,1658 ****
--- 1658,1666 ----
    /* Regparm attribute specifies how many integer arguments are to be
       passed in registers.  */
    { "regparm",   1, 1, false, true,  true,  ix86_handle_regparm_attribute },
+   /* Fpregparm attribute says we are using x86_64 calling conventions
+      for FP arguments.  */
+   { "fpregparm", 0, 0, false, true, true, ix86_handle_fpregparm_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
*** 1818,1823 ****
--- 1826,1859 ----
    return NULL_TREE;
  }
  
+ /* Handle a "fpregparm" attribute;
+    arguments as in struct attribute_spec.handler.  */
+ static tree
+ ix86_handle_fpregparm_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_SSE2)
+     {
+       error ("%qs attribute only can be used with -msse2",
+ 	     IDENTIFIER_POINTER (name));
+       *no_add_attrs = true;
+     }
+ 
+   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).  */
*************** init_cumulative_args (CUMULATIVE_ARGS *c
*** 2077,2086 ****
        || (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)
      {
--- 2113,2130 ----
        || (fntype && !TYPE_ARG_TYPES (fntype)))
      cum->maybe_vaarg = true;
  
+   /* Use SSE registers to pass SFmode and DFmode arguments if requested
+      by the fpregparm attribute.  */
+   if (fntype && lookup_attribute ("fpregparm", TYPE_ATTRIBUTES (fntype)))
+     {
+       cum->sse_nregs = 8;
+       cum->float_in_sse = 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.  */
!   else 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)
      {
*************** ix86_value_regno (enum machine_mode mode
*** 3237,3242 ****
--- 3281,3294 ----
    if (GET_MODE_CLASS (mode) != MODE_FLOAT || !TARGET_FLOAT_RETURNS_IN_80387)
      return 0;
  
+   /* Floating point return values with fpregparm marked functions go
+      in SSE registers.  */
+   if (func && SSE_FLOAT_MODE_P (mode)
+       && lookup_attribute ("fpregparm", 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
*************** ix86_init_builtins (void)
*** 13547,13552 ****
--- 13599,13624 ----
  {
    if (TARGET_MMX)
      ix86_init_mmx_sse_builtins ();
+ 
+   if (ix86_fpmath == FPMATH_SSE)
+     {
+       /* "Patch" some builtins with fpregparm attribute.  */
+       tree fn;
+ #define PATCH_BUILTIN_WITH_FPREGPARM(f) \
+       fn = mathfn_built_in (double_type_node, (f)); \
+       TYPE_ATTRIBUTES (TREE_TYPE (fn)) \
+ 	= tree_cons (get_identifier ("fpregparm"), \
+ 		     NULL_TREE, \
+ 		     TYPE_ATTRIBUTES (TREE_TYPE (fn))); \
+       fn = mathfn_built_in (float_type_node, (f)); \
+       TYPE_ATTRIBUTES (TREE_TYPE (fn)) \
+ 	= tree_cons (get_identifier ("fpregparm"), \
+ 		     NULL_TREE, \
+ 		     TYPE_ATTRIBUTES (TREE_TYPE (fn)))
+       PATCH_BUILTIN_WITH_FPREGPARM (BUILT_IN_SIN);
+       PATCH_BUILTIN_WITH_FPREGPARM (BUILT_IN_COS);
+ #undef PATCH_BUILTIN_WITH_FPREGPARM
+     }
  }
  
  /* Set up all the MMX/SSE builtins.  This is not called if TARGET_MMX
*************** i386_solaris_elf_named_section (const ch
*** 17357,17360 ****
--- 17429,17447 ----
    default_elf_asm_named_section (name, flags, decl);
  }
  
+ /* Patch math builtin libfunctions with fpregparm attribute and
+    a different name if fpmath=sse.  */
+ 
+ static void
+ ix86_init_libfuncs (void)
+ {
+   if (! ix86_fpmath == FPMATH_SSE)
+     return;
+ 
+   set_optab_libfunc (sin_optab, DFmode, "__libm_sse2_sin");
+   set_optab_libfunc (sin_optab, SFmode, "__libm_sse2_sinf");
+   set_optab_libfunc (cos_optab, DFmode, "__libm_sse2_cos");
+   set_optab_libfunc (cos_optab, SFmode, "__libm_sse2_cosf");
+ }
+ 
  #include "gt-i386.h"

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