This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[RFC] Prototype for SSE2 calling convention libm on ia32
- From: Richard Guenther <rguenth at tat dot physik dot uni-tuebingen dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 07 Jun 2005 19:21:18 +0200
- Subject: [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"