From 2f84b963e9556be5bc0219aec23941ea15b61596 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Thu, 16 Jun 2005 16:39:51 +0000 Subject: [PATCH] extend.texi: Document sseregparm target attribute. 2005-06-16 Richard Guenther * 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. From-SVN: r101085 --- gcc/ChangeLog | 19 ++ gcc/config/i386/i386.c | 243 +++++++++++++-------- gcc/config/i386/i386.h | 4 +- gcc/doc/extend.texi | 21 +- gcc/testsuite/ChangeLog | 8 + gcc/testsuite/gcc.target/i386/attributes-error.c | 11 + .../gcc.target/i386/fastcall-sseregparm.c | 21 ++ gcc/testsuite/gcc.target/i386/regparm-stdcall.c | 21 ++ gcc/testsuite/gcc.target/i386/sseregparm-1.c | 18 ++ gcc/testsuite/gcc.target/i386/sseregparm-2.c | 16 ++ 10 files changed, 279 insertions(+), 103 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/attributes-error.c create mode 100644 gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c create mode 100644 gcc/testsuite/gcc.target/i386/regparm-stdcall.c create mode 100644 gcc/testsuite/gcc.target/i386/sseregparm-1.c create mode 100644 gcc/testsuite/gcc.target/i386/sseregparm-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4a6bae3..40e204c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2005-06-16 Richard Guenther + + * 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. + 2005-06-16 Paolo Bonzini Daniel Jacobowitz Alan Modra diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9ced831..781daee 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -890,8 +890,7 @@ static int ix86_comp_type_attributes (tree, tree); 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 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); @@ -1660,15 +1659,18 @@ const struct attribute_spec ix86_attribute_table[] = /* { 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 }, + { "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_cdecl_attribute }, + { "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_cdecl_attribute }, + { "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_regparm_attribute }, + { "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 }, @@ -1743,59 +1745,15 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) return true; } -/* Handle a "cdecl", "stdcall", or "fastcall" attribute; +/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm" + calling convention attributes; 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) +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 @@ -1805,11 +1763,19 @@ ix86_handle_regparm_attribute (tree *node, tree name, tree args, warning (OPT_Wattributes, "%qs attribute only applies to functions", IDENTIFIER_POINTER (name)); *no_add_attrs = true; + return NULL_TREE; } - else + + /* 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) { @@ -1825,12 +1791,63 @@ ix86_handle_regparm_attribute (tree *node, tree name, tree args, *no_add_attrs = true; } - if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (*node))) - { + 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; } @@ -1847,18 +1864,23 @@ ix86_comp_type_attributes (tree type1, tree type2) 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))) + /* 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; - if (ix86_function_regparm (type1, NULL) - != ix86_function_regparm (type2, NULL)) - return 0; + return 1; } @@ -1907,6 +1929,47 @@ ix86_function_regparm (tree type, tree decl) 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. */ @@ -2041,10 +2104,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ *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; + cum->nregs = ix86_regparm; if (TARGET_SSE) cum->sse_nregs = SSE_REGPARM_MAX; if (TARGET_MMX) @@ -2053,7 +2113,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ cum->warn_mmx = true; cum->maybe_vaarg = false; - /* Use ecx and edx registers if function has fastcall attribute */ + /* 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))) @@ -2061,8 +2122,14 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ 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 @@ -2084,6 +2151,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ cum->warn_sse = 0; cum->warn_mmx = 0; cum->fastcall = 0; + cum->float_in_sse = 0; } cum->maybe_vaarg = true; } @@ -2093,21 +2161,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */ || (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); @@ -2785,10 +2838,10 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, break; case DFmode: - if (!TARGET_SSE2) + if (cum->float_in_sse < 2) break; case SFmode: - if (!cum->float_in_sse) + if (cum->float_in_sse < 1) break; /* FALLTHRU */ @@ -2914,10 +2967,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode, } break; case DFmode: - if (!TARGET_SSE2) + if (cum->float_in_sse < 2) break; case SFmode: - if (!cum->float_in_sse) + if (cum->float_in_sse < 1) break; /* FALLTHRU */ case TImode: @@ -3274,13 +3327,13 @@ ix86_value_regno (enum machine_mode mode, tree func) 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) + SSE math is enabled or for functions with sseregparm attribute. */ + if (func && (mode == SFmode || mode == DFmode)) { - struct cgraph_local_info *i = cgraph_local_info (func); - if (i && i->local) - return FIRST_SSE_REG; + 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; diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index c9c4cfc..3358948 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1478,8 +1478,8 @@ typedef struct ix86_args { 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. */ + 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 diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 7d83c2b..6a31e9c 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -1752,9 +1752,10 @@ the @code{rtc}. @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 +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}) @@ -2126,9 +2127,9 @@ than 2.96. @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 +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 @@ -2141,6 +2142,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 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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 34f4fe5..09f9d71 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2005-06-16 Richard Guenther + + * 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. + 2005-06-16 Nathan Sidwell * g++.dg/rtti/crash2.C: New. diff --git a/gcc/testsuite/gcc.target/i386/attributes-error.c b/gcc/testsuite/gcc.target/i386/attributes-error.c new file mode 100644 index 0000000..05c2129 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/attributes-error.c @@ -0,0 +1,11 @@ +/* { 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" } */ + diff --git a/gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c b/gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c new file mode 100644 index 0000000..e711411 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c @@ -0,0 +1,21 @@ +/* { 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; +} diff --git a/gcc/testsuite/gcc.target/i386/regparm-stdcall.c b/gcc/testsuite/gcc.target/i386/regparm-stdcall.c new file mode 100644 index 0000000..6605e79 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/regparm-stdcall.c @@ -0,0 +1,21 @@ +/* { 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; +} diff --git a/gcc/testsuite/gcc.target/i386/sseregparm-1.c b/gcc/testsuite/gcc.target/i386/sseregparm-1.c new file mode 100644 index 0000000..afe012b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sseregparm-1.c @@ -0,0 +1,18 @@ +/* { 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" } } */ diff --git a/gcc/testsuite/gcc.target/i386/sseregparm-2.c b/gcc/testsuite/gcc.target/i386/sseregparm-2.c new file mode 100644 index 0000000..32510b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sseregparm-2.c @@ -0,0 +1,16 @@ +/* { 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" } */ +} -- 2.7.4