re PR target/30120 (silent miscompilation of argument passing)

PR target/30120
	Revert:
	2006-11-15  Uros Bizjak  <ubizjak@gmail.com>

	* config/i386/i386.opt: New target option -mx87regparm.

	* config/i386/i386.h (struct ix86_args): Add x87_nregs, x87_regno,
	float_in_x87: Add new variables. mmx_words, sse_words: Remove.
	(X87_REGPARM_MAX): Define.

	* config/i386/i386.c (override_options): Error out for
	-mx87regparm but no 80387 support.
	(ix86_attribute_table): Add x87regparm.
	(ix86_handle_cconv_attribute): Update comments for x87regparm.
	(ix86_comp_type_attributes): Check for mismatched x87regparm types.
	(ix86_function_x87regparm): New function.
	(ix86_function_arg_regno_p): Add X87_REGPARM_MAX 80387 floating
	point registers.
	(init_cumulative_args): Initialize x87_nregs and float_in_x87
	variables.
	(function_arg_advance): Process x87_nregs and x87_regno when
	floating point argument is to be passed in 80387 register.
	(function_arg): Pass XFmode arguments in 80387 registers for local
	functions.  Pass SFmode and DFmode arguments to local functions
	in 80387 registers when flag_unsafe_math_optimizations is set.

	* reg-stack.c (convert_regs_entry): Disable NaN load for
	stack registers that are used for argument passing.

	* doc/extend.texi: Document x87regparm function attribute.
	* doc/invoke.texi: Document -mx87regparm.

testsuite/ChangeLog:

	PR target/30120
	* gcc.target/i386/pr30120.c: New test.

	Revert:
	2006-11-15  Uros Bizjak  <ubizjak@gmail.com>

	* gcc.target/i386/x87regparm-1.c: New test.
	* gcc.target/i386/x87regparm-2.c: New test.
	* gcc.target/i386/x87regparm-3.c: New test.
	* gcc.target/i386/x87regparm-4.c: New test.

From-SVN: r119734
This commit is contained in:
Uros Bizjak 2006-12-11 15:06:07 +01:00 committed by Uros Bizjak
parent c3f824ce13
commit fa283935de
13 changed files with 104 additions and 282 deletions

View File

@ -1,3 +1,37 @@
2006-12-11 Uros Bizjak <ubizjak@gmail.com>
PR target/30120
Revert:
2006-11-15 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.opt: New target option -mx87regparm.
* config/i386/i386.h (struct ix86_args): Add x87_nregs, x87_regno,
float_in_x87: Add new variables. mmx_words, sse_words: Remove.
(X87_REGPARM_MAX): Define.
* config/i386/i386.c (override_options): Error out for
-mx87regparm but no 80387 support.
(ix86_attribute_table): Add x87regparm.
(ix86_handle_cconv_attribute): Update comments for x87regparm.
(ix86_comp_type_attributes): Check for mismatched x87regparm types.
(ix86_function_x87regparm): New function.
(ix86_function_arg_regno_p): Add X87_REGPARM_MAX 80387 floating
point registers.
(init_cumulative_args): Initialize x87_nregs and float_in_x87
variables.
(function_arg_advance): Process x87_nregs and x87_regno when
floating point argument is to be passed in 80387 register.
(function_arg): Pass XFmode arguments in 80387 registers for local
functions. Pass SFmode and DFmode arguments to local functions
in 80387 registers when flag_unsafe_math_optimizations is set.
* reg-stack.c (convert_regs_entry): Disable NaN load for
stack registers that are used for argument passing.
* doc/extend.texi: Document x87regparm function attribute.
* doc/invoke.texi: Document -mx87regparm.
2006-12-11 Jan Hubicka <jh@suse.cz>
Move all varpool routines out of cgraph/cgraphunit to varpool.c

View File

@ -2149,11 +2149,6 @@ override_options (void)
ix86_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
}
/* Accept -mx87regparm only if 80387 support is enabled. */
if (TARGET_X87REGPARM
&& ! TARGET_80387)
error ("-mx87regparm used without 80387 enabled");
/* Accept -msseregparm only if at least SSE support is enabled. */
if (TARGET_SSEREGPARM
&& ! TARGET_SSE)
@ -2460,9 +2455,6 @@ const struct attribute_spec ix86_attribute_table[] =
/* Regparm attribute specifies how many integer arguments are to be
passed in registers. */
{ "regparm", 1, 1, false, true, true, ix86_handle_cconv_attribute },
/* X87regparm attribute says we are passing floating point arguments
in 80387 registers. */
{ "x87regparm", 0, 0, 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 },
@ -2565,8 +2557,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
return true;
}
/* Handle "cdecl", "stdcall", "fastcall", "regparm", "x87regparm"
and "sseregparm" calling convention attributes;
/* Handle "cdecl", "stdcall", "fastcall", "regparm" and "sseregparm"
calling convention attributes;
arguments as in struct attribute_spec.handler. */
static tree
@ -2631,8 +2623,7 @@ ix86_handle_cconv_attribute (tree *node, tree name,
return NULL_TREE;
}
/* Can combine fastcall with stdcall (redundant), x87regparm
and sseregparm. */
/* Can combine fastcall with stdcall (redundant) and sseregparm. */
if (is_attribute_p ("fastcall", name))
{
if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
@ -2649,8 +2640,8 @@ ix86_handle_cconv_attribute (tree *node, tree name,
}
}
/* Can combine stdcall with fastcall (redundant), regparm,
x87regparm and sseregparm. */
/* Can combine stdcall with fastcall (redundant), regparm and
sseregparm. */
else if (is_attribute_p ("stdcall", name))
{
if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (*node)))
@ -2663,7 +2654,7 @@ ix86_handle_cconv_attribute (tree *node, tree name,
}
}
/* Can combine cdecl with regparm, x87regparm and sseregparm. */
/* Can combine cdecl with regparm and sseregparm. */
else if (is_attribute_p ("cdecl", name))
{
if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (*node)))
@ -2676,7 +2667,7 @@ ix86_handle_cconv_attribute (tree *node, tree name,
}
}
/* Can combine x87regparm or sseregparm with all attributes. */
/* Can combine sseregparm with all attributes. */
return NULL_TREE;
}
@ -2701,11 +2692,6 @@ ix86_comp_type_attributes (tree type1, tree type2)
!= ix86_function_regparm (type2, NULL)))
return 0;
/* Check for mismatched x87regparm types. */
if (!lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type1))
!= !lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type2)))
return 0;
/* Check for mismatched sseregparm types. */
if (!lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type1))
!= !lookup_attribute ("sseregparm", TYPE_ATTRIBUTES (type2)))
@ -2794,48 +2780,6 @@ ix86_function_regparm (tree type, tree decl)
return regparm;
}
/* Return 1 if we can pass up to X87_REGPARM_MAX floating point
arguments in x87 registers for a function with the indicated
TYPE and DECL. DECL may be NULL when calling function indirectly
or considering a libcall. For local functions, return 2.
Otherwise return 0. */
static int
ix86_function_x87regparm (tree type, tree decl)
{
/* Use x87 registers to pass floating point arguments if requested
by the x87regparm attribute. */
if (TARGET_X87REGPARM
|| (type
&& lookup_attribute ("x87regparm", TYPE_ATTRIBUTES (type))))
{
if (!TARGET_80387)
{
if (decl)
error ("Calling %qD with attribute x87regparm without "
"80387 enabled", decl);
else
error ("Calling %qT with attribute x87regparm without "
"80387 enabled", type);
return 0;
}
return 1;
}
/* For local functions, pass up to X87_REGPARM_MAX floating point
arguments in x87 registers. */
if (!TARGET_64BIT && decl
&& flag_unit_at_a_time && !profile_flag)
{
struct cgraph_local_info *i = cgraph_local_info (decl);
if (i && i->local)
return 2;
}
return 0;
}
/* Return 1 or 2, if we can pass up to SSE_REGPARM_MAX 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
@ -2955,8 +2899,6 @@ ix86_function_arg_regno_p (int regno)
int i;
if (!TARGET_64BIT)
return (regno < REGPARM_MAX
|| (TARGET_80387 && FP_REGNO_P (regno)
&& (regno < FIRST_FLOAT_REG + X87_REGPARM_MAX))
|| (TARGET_MMX && MMX_REGNO_P (regno)
&& (regno < FIRST_MMX_REG + MMX_REGPARM_MAX))
|| (TARGET_SSE && SSE_REGNO_P (regno)
@ -3020,8 +2962,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
/* Set up the number of registers to use for passing arguments. */
cum->nregs = ix86_regparm;
if (TARGET_80387)
cum->x87_nregs = X87_REGPARM_MAX;
if (TARGET_SSE)
cum->sse_nregs = SSE_REGPARM_MAX;
if (TARGET_MMX)
@ -3043,10 +2983,6 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
cum->nregs = ix86_function_regparm (fntype, fndecl);
}
/* Set up the number of 80387 registers used for passing
floating point arguments. Warn for mismatching ABI. */
cum->float_in_x87 = ix86_function_x87regparm (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);
@ -3056,8 +2992,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
are no variable arguments. If there are variable arguments, then
we won't pass anything in registers in 32-bit mode. */
if (cum->nregs || cum->mmx_nregs
|| cum->x87_nregs || cum->sse_nregs)
if (cum->nregs || cum->mmx_nregs || cum->sse_nregs)
{
for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
param != 0; param = next_param)
@ -3068,13 +3003,11 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, /* Argument info to initialize */
if (!TARGET_64BIT)
{
cum->nregs = 0;
cum->x87_nregs = 0;
cum->sse_nregs = 0;
cum->mmx_nregs = 0;
cum->warn_sse = 0;
cum->warn_mmx = 0;
cum->fastcall = 0;
cum->float_in_x87 = 0;
cum->float_in_sse = 0;
}
cum->maybe_vaarg = true;
@ -3771,40 +3704,13 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
break;
case SFmode:
if (cum->float_in_sse > 0)
goto skip_80387;
case DFmode:
if (cum->float_in_sse > 1)
goto skip_80387;
/* Because no inherent XFmode->DFmode and XFmode->SFmode
rounding takes place when values are passed in x87
registers, pass DFmode and SFmode types to local functions
only when flag_unsafe_math_optimizations is set. */
if (!cum->float_in_x87
|| (cum->float_in_x87 == 2
&& !flag_unsafe_math_optimizations))
if (cum->float_in_sse < 2)
break;
case XFmode:
if (!cum->float_in_x87)
case SFmode:
if (cum->float_in_sse < 1)
break;
if (!type || !AGGREGATE_TYPE_P (type))
{
cum->x87_nregs -= 1;
cum->x87_regno += 1;
if (cum->x87_nregs <= 0)
{
cum->x87_nregs = 0;
cum->x87_regno = 0;
}
}
break;
skip_80387:
/* FALLTHRU */
case TImode:
case V16QImode:
@ -3815,6 +3721,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
case V2DFmode:
if (!type || !AGGREGATE_TYPE_P (type))
{
cum->sse_words += words;
cum->sse_nregs -= 1;
cum->sse_regno += 1;
if (cum->sse_nregs <= 0)
@ -3831,6 +3738,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
case V2SFmode:
if (!type || !AGGREGATE_TYPE_P (type))
{
cum->mmx_words += words;
cum->mmx_nregs -= 1;
cum->mmx_regno += 1;
if (cum->mmx_nregs <= 0)
@ -3895,6 +3803,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
else
switch (mode)
{
/* For now, pass fp/complex values on the stack. */
default:
break;
@ -3924,35 +3833,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode orig_mode,
ret = gen_rtx_REG (mode, regno);
}
break;
case SFmode:
if (cum->float_in_sse > 0)
goto skip_80387;
case DFmode:
if (cum->float_in_sse > 1)
goto skip_80387;
/* Because no inherent XFmode->DFmode and XFmode->SFmode
rounding takes place when values are passed in x87
registers, pass DFmode and SFmode types to local functions
only when flag_unsafe_math_optimizations is set. */
if (!cum->float_in_x87
|| (cum->float_in_x87 == 2
&& !flag_unsafe_math_optimizations))
break;
case XFmode:
if (!cum->float_in_x87)
break;
if (!type || !AGGREGATE_TYPE_P (type))
if (cum->x87_nregs)
ret = gen_rtx_REG (mode, cum->x87_regno + FIRST_FLOAT_REG);
case DFmode:
if (cum->float_in_sse < 2)
break;
skip_80387:
case SFmode:
if (cum->float_in_sse < 1)
break;
/* FALLTHRU */
case TImode:
case V16QImode:
case V8HImode:

View File

@ -1481,21 +1481,19 @@ enum reg_class
such as FUNCTION_ARG to determine where the next arg should go. */
typedef struct ix86_args {
int words; /* # words passed so far */
int nregs; /* # registers available for passing */
int regno; /* next available register number */
int words; /* # words passed so far */
int fastcall; /* fastcall calling convention is used */
int x87_nregs; /* # x87 registers available for passing */
int x87_regno; /* # next available x87 register number */
int sse_words; /* # sse words passed so far */
int sse_nregs; /* # sse registers available for passing */
int sse_regno; /* next available sse register number */
int warn_sse; /* True when we want to warn about SSE ABI. */
int warn_mmx; /* True when we want to warn about MMX ABI. */
int sse_regno; /* next available sse register number */
int mmx_words; /* # mmx words passed so far */
int mmx_nregs; /* # mmx registers available for passing */
int mmx_regno; /* next available mmx register number */
int warn_mmx; /* True when we want to warn about MMX ABI. */
int maybe_vaarg; /* true for calls to possibly vardic fncts. */
int float_in_x87; /* 1 if floating point arguments should
be passed in 80387 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;
@ -1778,10 +1776,6 @@ do { \
#define REGPARM_MAX (TARGET_64BIT ? 6 : 3)
/* ??? Currently disabled, as reg-stack.c does not know how to
rearrange input registers if some arguments are left unused. */
#define X87_REGPARM_MAX 0
#define SSE_REGPARM_MAX (TARGET_64BIT ? 8 : (TARGET_SSE ? 3 : 0))
#define MMX_REGPARM_MAX (TARGET_64BIT ? 0 : (TARGET_MMX ? 3 : 0))

View File

@ -205,10 +205,6 @@ mssse3
Target Report Mask(SSSE3)
Support MMX, SSE, SSE2, SSE3 and SSSE3 built-in functions and code generation
mx87regparm
Target RejectNegative Mask(X87REGPARM)
Use x87 register passing conventions to pass floating point arguments
msseregparm
Target RejectNegative Mask(SSEREGPARM)
Use SSE register passing conventions for SF and DF mode

View File

@ -2221,14 +2221,6 @@ 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 x87regparm
@cindex @code{x87regparm} attribute
On the Intel x86 with 80387 @code{x87regparm} attribute causes the
compiler to pass up to 3 floating point arguments in 80387 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 sseregparm
@cindex @code{sseregparm} attribute
On the Intel 386 with SSE support, the @code{sseregparm} attribute

View File

@ -536,8 +536,8 @@ Objective-C and Objective-C++ Dialects}.
-mmmx -msse -msse2 -msse3 -mssse3 -m3dnow @gol
-mthreads -mno-align-stringops -minline-all-stringops @gol
-mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol
-m96bit-long-double -mregparm=@var{num} -mx87regparm @gol
-msseregparm @gol -mstackrealign @gol
-m96bit-long-double -mregparm=@var{num} -msseregparm @gol
-mstackrealign @gol
-momit-leaf-frame-pointer -mno-red-zone -mno-tls-direct-seg-refs @gol
-mcmodel=@var{code-model} @gol
-m32 -m64 -mlarge-data-threshold=@var{num}}
@ -9597,17 +9597,6 @@ function by using the function attribute @samp{regparm}.
value, including any libraries. This includes the system libraries and
startup modules.
@item -mx87regparm
@opindex mx87regparm
Use 80387 register passing conventions for floating point arguments.
You can control this behavior for a specific function by using the
function attribute @samp{x87regparm}.
@xref{Function Attributes}.
@strong{Warning:} if you use this switch then you must build all
modules with the same value, including any libraries. This includes
the system libraries and startup modules.
@item -msseregparm
@opindex msseregparm
Use SSE register passing conventions for float and double arguments

View File

@ -2558,28 +2558,11 @@ print_stack (FILE *file, stack s)
static int
convert_regs_entry (void)
{
tree params = DECL_ARGUMENTS (current_function_decl);
tree p;
HARD_REG_SET incoming_regs;
rtx inc_rtx;
int inserted = 0;
edge e;
edge_iterator ei;
/* Find out which registers were used as argument passing registers. */
CLEAR_HARD_REG_SET (incoming_regs);
for (p = params; p; p = TREE_CHAIN (p))
{
inc_rtx = DECL_INCOMING_RTL (p);
if (REG_P (inc_rtx)
&& IN_RANGE (REGNO (inc_rtx), FIRST_STACK_REG, LAST_STACK_REG))
SET_HARD_REG_BIT (incoming_regs, REGNO (inc_rtx));
}
/* Load something into remaining stack register live at function entry.
/* Load something into each stack register live at function entry.
Such live registers can be caused by uninitialized variables or
functions not returning values on all paths. In order to keep
the push/pop code happy, and to not scrog the register stack, we
@ -2595,17 +2578,12 @@ convert_regs_entry (void)
int reg, top = -1;
for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg)
if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg)
|| TEST_HARD_REG_BIT (incoming_regs, reg))
if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg))
{
rtx init;
bi->stack_in.reg[++top] = reg;
/* Skip argument passing registers. */
if (TEST_HARD_REG_BIT (incoming_regs, reg))
continue;
init = gen_rtx_SET (VOIDmode,
FP_MODE_REG (FIRST_STACK_REG, SFmode),
not_a_num);

View File

@ -1,3 +1,16 @@
2006-12-11 Uros Bizjak <ubizjak@gmail.com>
PR target/30120
* gcc.target/i386/pr30120.c: New test.
Revert:
2006-11-15 Uros Bizjak <ubizjak@gmail.com>
* gcc.target/i386/x87regparm-1.c: New test.
* gcc.target/i386/x87regparm-2.c: New test.
* gcc.target/i386/x87regparm-3.c: New test.
* gcc.target/i386/x87regparm-4.c: New test.
2006-12-10 Zdenek Dvorak <dvorakz@suse.cz>
* gcc.dg/tree-ssa/loop-17.c: Update outcome.

View File

@ -0,0 +1,27 @@
/* { dg-do run } */
/* { dg-options "-O2 -ffast-math" } */
extern void abort (void);
static void
foo (double a, double weight, const double *ring, double *phase)
{
*phase = *ring * weight;
}
void
foo2 (void)
{
foo (0, 1, (double *) 0, (double *) 0);
}
int
main (void)
{
double t1 = 1, c1;
foo (0, 1, &t1, &c1);
if (c1 < 0.5)
abort();
return 0;
}

View File

@ -1,22 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fomit-frame-pointer" } */
/* { dg-require-effective-target ilp32 } */
float foo_f(float) __attribute__((x87regparm));
double foo_d(double) __attribute__((x87regparm));
long double foo_ld(long double) __attribute__((x87regparm));
volatile float f;
volatile double d;
volatile long double ld;
void test()
{
f = foo_f(f);
d = foo_d(d);
ld = foo_ld(ld);
}
/* Check that no memory is used to pass arguments. */
/* { dg-final { scan-assembler-not "\\(%esp\\)" { xfail *-*-* } } } */

View File

@ -1,22 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fomit-frame-pointer -mx87regparm" } */
/* { dg-require-effective-target ilp32 } */
float efoo_f(float);
double efoo_d(double);
long double efoo_ld(long double);
volatile float f;
volatile double d;
volatile long double ld;
void test()
{
f = efoo_f(f);
d = efoo_d(d);
ld = efoo_ld(ld);
}
/* Check that no memory is used to pass arguments. */
/* { dg-final { scan-assembler-not "\\(%esp\\)" { xfail *-*-* } } } */

View File

@ -1,22 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fomit-frame-pointer" } */
/* { dg-require-effective-target ilp32 } */
static float __attribute__((noinline)) foo_f(float f) { return f; }
static double __attribute__((noinline)) foo_d(double d) { return d; }
static long double __attribute__((noinline)) foo_ld(long double ld) { return ld; }
volatile float f;
volatile double d;
volatile long double ld;
void test()
{
f = foo_f(f);
d = foo_d(d);
ld = foo_ld(ld);
}
/* Check that float and double arguments are passed through memory. */
/* { dg-final { scan-assembler-times "\\(%esp\\)" 4 { xfail *-*-* } } } */

View File

@ -1,22 +0,0 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fomit-frame-pointer -ffast-math" } */
/* { dg-require-effective-target ilp32 } */
static float __attribute__((noinline)) foo_f(float f) { return f; }
static double __attribute__((noinline)) foo_d(double d) { return d; }
static long double __attribute__((noinline)) foo_ld(long double ld) { return ld; }
volatile float f;
volatile double d;
volatile long double ld;
void test()
{
f = foo_f(f);
d = foo_d(d);
ld = foo_ld(ld);
}
/* Check that no memory is used to pass arguments. */
/* { dg-final { scan-assembler-not "\\(%esp\\)" { xfail *-*-* } } } */