extend.texi: Document sseregparm target attribute.
2005-06-16 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. From-SVN: r101085
This commit is contained in:
parent
9f18db39e6
commit
2f84b963e9
10 changed files with 279 additions and 103 deletions
|
@ -1,3 +1,22 @@
|
|||
2005-06-16 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.
|
||||
|
||||
2005-06-16 Paolo Bonzini <bonzini@gnu.org>
|
||||
Daniel Jacobowitz <dan@codesourcery.com>
|
||||
Alan Modra <amodra.bigpond.net.au>
|
||||
|
|
|
@ -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,12 +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)
|
||||
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
|
||||
|
@ -1758,58 +1763,19 @@ ix86_handle_cdecl_attribute (tree *node, tree name,
|
|||
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");
|
||||
}
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
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
|
||||
&& 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
|
||||
/* 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2005-06-16 Richard Guenther <rguenth@gcc.gnu.org>
|
||||
|
||||
* 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 <nathan@codesourcery.com>
|
||||
|
||||
* g++.dg/rtti/crash2.C: New.
|
||||
|
|
11
gcc/testsuite/gcc.target/i386/attributes-error.c
Normal file
11
gcc/testsuite/gcc.target/i386/attributes-error.c
Normal file
|
@ -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" } */
|
||||
|
21
gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c
Normal file
21
gcc/testsuite/gcc.target/i386/fastcall-sseregparm.c
Normal file
|
@ -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;
|
||||
}
|
21
gcc/testsuite/gcc.target/i386/regparm-stdcall.c
Normal file
21
gcc/testsuite/gcc.target/i386/regparm-stdcall.c
Normal file
|
@ -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;
|
||||
}
|
18
gcc/testsuite/gcc.target/i386/sseregparm-1.c
Normal file
18
gcc/testsuite/gcc.target/i386/sseregparm-1.c
Normal file
|
@ -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" } } */
|
16
gcc/testsuite/gcc.target/i386/sseregparm-2.c
Normal file
16
gcc/testsuite/gcc.target/i386/sseregparm-2.c
Normal file
|
@ -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" } */
|
||||
}
|
Loading…
Add table
Reference in a new issue