Commit cb1119b7 by Richard Guenther Committed by Richard Biener

re PR middle-end/22347 (Return value register not correctly computed for indirect function call)

2005-07-14  Richard Guenther  <rguenther@suse.de>

	PR middle-end/22347
	* config/i386/i386-protos.h (ix86_function_value): Change
	prototype to match new target hook.
	* config/i386/i386.c (ix86_value_regno): Change prototype
	to take extra type argument.
	(TARGET_FUNCTION_VALUE): Define.
	(ix86_function_ok_for_sibcall): Pass extra argument to
	ix86_value_regno, check return slot rtx for exact match.
	(ix86_function_value): Take extra parameter.  Dispatch to
	ix86_value_regno with fndecl/fntype as provided.
	(ix86_value_regno): Handle extra type argument.
	* config/i386/i386.h (FUNCTION_VALUE): No longer define.

	* testsuite/gcc.target/i386/sseregparm-3.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-4.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-5.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-6.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-7.c: New testcase.

From-SVN: r102014
parent 1d636cc6
2005-07-14 Richard Guenther <rguenther@suse.de> 2005-07-14 Richard Guenther <rguenther@suse.de>
PR middle-end/22347
* config/i386/i386-protos.h (ix86_function_value): Change
prototype to match new target hook.
* config/i386/i386.c (ix86_value_regno): Change prototype
to take extra type argument.
(TARGET_FUNCTION_VALUE): Define.
(ix86_function_ok_for_sibcall): Pass extra argument to
ix86_value_regno, check return slot rtx for exact match.
(ix86_function_value): Take extra parameter. Dispatch to
ix86_value_regno with fndecl/fntype as provided.
(ix86_value_regno): Handle extra type argument.
* config/i386/i386.h (FUNCTION_VALUE): No longer define.
* testsuite/gcc.target/i386/sseregparm-3.c: New testcase.
* testsuite/gcc.target/i386/sseregparm-4.c: New testcase.
* testsuite/gcc.target/i386/sseregparm-5.c: New testcase.
* testsuite/gcc.target/i386/sseregparm-6.c: New testcase.
* testsuite/gcc.target/i386/sseregparm-7.c: New testcase.
2005-07-14 Richard Guenther <rguenther@suse.de>
* Makefile.in (explow.o, reg-stack.o): Depend on target.h. * Makefile.in (explow.o, reg-stack.o): Depend on target.h.
* calls.c (expand_call): Pass fntype to hard_function_value. * calls.c (expand_call): Pass fntype to hard_function_value.
(emit_library_call_value_1): Likewise. (emit_library_call_value_1): Likewise.
......
...@@ -206,7 +206,7 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree); ...@@ -206,7 +206,7 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int); extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
tree, int); tree, int);
extern rtx ix86_function_value (tree, tree); extern rtx ix86_function_value (tree, tree, bool);
#endif #endif
#endif #endif
......
...@@ -891,7 +891,7 @@ static int ix86_function_regparm (tree, tree); ...@@ -891,7 +891,7 @@ static int ix86_function_regparm (tree, tree);
const struct attribute_spec ix86_attribute_table[]; const struct attribute_spec ix86_attribute_table[];
static bool ix86_function_ok_for_sibcall (tree, tree); static bool ix86_function_ok_for_sibcall (tree, tree);
static tree ix86_handle_cconv_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 int ix86_value_regno (enum machine_mode, tree, tree);
static bool contains_128bit_aligned_vector_p (tree); static bool contains_128bit_aligned_vector_p (tree);
static rtx ix86_struct_value_rtx (tree, int); static rtx ix86_struct_value_rtx (tree, int);
static bool ix86_ms_bitfield_layout_p (tree); static bool ix86_ms_bitfield_layout_p (tree);
...@@ -1085,6 +1085,9 @@ static void init_ext_80387_constants (void); ...@@ -1085,6 +1085,9 @@ static void init_ext_80387_constants (void);
#undef TARGET_STACK_PROTECT_FAIL #undef TARGET_STACK_PROTECT_FAIL
#define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail #define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail
#undef TARGET_FUNCTION_VALUE
#define TARGET_FUNCTION_VALUE ix86_function_value
struct gcc_target targetm = TARGET_INITIALIZER; struct gcc_target targetm = TARGET_INITIALIZER;
...@@ -1705,6 +1708,7 @@ static bool ...@@ -1705,6 +1708,7 @@ static bool
ix86_function_ok_for_sibcall (tree decl, tree exp) ix86_function_ok_for_sibcall (tree decl, tree exp)
{ {
tree func; tree func;
rtx a, b;
/* If we are generating position-independent code, we cannot sibcall /* If we are generating position-independent code, we cannot sibcall
optimize any indirect call, or a direct call to a global function, optimize any indirect call, or a direct call to a global function,
...@@ -1715,16 +1719,23 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) ...@@ -1715,16 +1719,23 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
if (decl) if (decl)
func = decl; func = decl;
else else
func = NULL; {
func = TREE_TYPE (TREE_OPERAND (exp, 0));
if (POINTER_TYPE_P (func))
func = TREE_TYPE (func);
}
/* If we are returning floats on the 80387 register stack, we cannot /* Check that the return value locations are the same. Like
if we are returning floats on the 80387 register stack, we cannot
make a sibcall from a function that doesn't return a float to a make a sibcall from a function that doesn't return a float to a
function that does or, conversely, from a function that does return function that does or, conversely, from a function that does return
a float to a function that doesn't; the necessary stack adjustment a float to a function that doesn't; the necessary stack adjustment
would not be executed. */ would not be executed. This is also the place we notice
if (STACK_REG_P (ix86_function_value (TREE_TYPE (exp), func)) differences in the return value ABI. */
!= STACK_REG_P (ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)), a = ix86_function_value (TREE_TYPE (exp), func, false);
cfun->decl))) b = ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)),
cfun->decl, false);
if (! rtx_equal_p (a, b))
return false; return false;
/* If this call is indirect, we'll need to be able to use a call-clobbered /* If this call is indirect, we'll need to be able to use a call-clobbered
...@@ -3189,7 +3200,8 @@ ix86_function_value_regno_p (int regno) ...@@ -3189,7 +3200,8 @@ ix86_function_value_regno_p (int regno)
If the precise function being called is known, FUNC is its FUNCTION_DECL; If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */ otherwise, FUNC is 0. */
rtx rtx
ix86_function_value (tree valtype, tree func) ix86_function_value (tree valtype, tree fntype_or_decl,
bool outgoing ATTRIBUTE_UNUSED)
{ {
enum machine_mode natmode = type_natural_mode (valtype); enum machine_mode natmode = type_natural_mode (valtype);
...@@ -3205,7 +3217,15 @@ ix86_function_value (tree valtype, tree func) ...@@ -3205,7 +3217,15 @@ ix86_function_value (tree valtype, tree func)
return ret; return ret;
} }
else else
return gen_rtx_REG (TYPE_MODE (valtype), ix86_value_regno (natmode, func)); {
tree fn = NULL_TREE, fntype;
if (fntype_or_decl
&& DECL_P (fntype_or_decl))
fn = fntype_or_decl;
fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
return gen_rtx_REG (TYPE_MODE (valtype),
ix86_value_regno (natmode, fn, fntype));
}
} }
/* Return false iff type is returned in memory. */ /* Return false iff type is returned in memory. */
...@@ -3321,13 +3341,13 @@ ix86_libcall_value (enum machine_mode mode) ...@@ -3321,13 +3341,13 @@ ix86_libcall_value (enum machine_mode mode)
} }
} }
else else
return gen_rtx_REG (mode, ix86_value_regno (mode, NULL)); return gen_rtx_REG (mode, ix86_value_regno (mode, NULL, NULL));
} }
/* Given a mode, return the register to use for a return value. */ /* Given a mode, return the register to use for a return value. */
static int static int
ix86_value_regno (enum machine_mode mode, tree func) ix86_value_regno (enum machine_mode mode, tree func, tree fntype)
{ {
gcc_assert (!TARGET_64BIT); gcc_assert (!TARGET_64BIT);
...@@ -3347,9 +3367,10 @@ ix86_value_regno (enum machine_mode mode, tree func) ...@@ -3347,9 +3367,10 @@ ix86_value_regno (enum machine_mode mode, tree func)
/* Floating point return values in %st(0), except for local functions when /* Floating point return values in %st(0), except for local functions when
SSE math is enabled or for functions with sseregparm attribute. */ SSE math is enabled or for functions with sseregparm attribute. */
if (func && (mode == SFmode || mode == DFmode)) if ((func || fntype)
&& (mode == SFmode || mode == DFmode))
{ {
int sse_level = ix86_function_sseregparm (TREE_TYPE (func), func); int sse_level = ix86_function_sseregparm (fntype, func);
if ((sse_level >= 1 && mode == SFmode) if ((sse_level >= 1 && mode == SFmode)
|| (sse_level == 2 && mode == DFmode)) || (sse_level == 2 && mode == DFmode))
return FIRST_SSE_REG; return FIRST_SSE_REG;
......
...@@ -1433,13 +1433,6 @@ enum reg_class ...@@ -1433,13 +1433,6 @@ enum reg_class
#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \ #define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \
ix86_return_pops_args ((FUNDECL), (FUNTYPE), (SIZE)) ix86_return_pops_args ((FUNDECL), (FUNTYPE), (SIZE))
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
ix86_function_value (VALTYPE, FUNC)
#define FUNCTION_VALUE_REGNO_P(N) \ #define FUNCTION_VALUE_REGNO_P(N) \
ix86_function_value_regno_p (N) ix86_function_value_regno_p (N)
......
/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */
/* Make sure we know that mysinfp returns in %xmm0. */
double __attribute__((sseregparm)) mysin(double x);
double __attribute__((sseregparm)) (*mysinfp)(double) = mysin;
double bar(double x)
{
return 1.0+mysinfp(x);
}
/* { dg-final { scan-assembler "fldl" } } */
/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */
/* Make sure we know that mysinfp returns in %xmm0. */
double __attribute__((sseregparm)) mysin(double x);
double __attribute__((sseregparm)) (*mysinfp)(double) = mysin;
double bar(double x)
{
return mysinfp(x);
}
/* { dg-final { scan-assembler "fldl" } } */
/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */
/* Make sure we know that mysinfp returns in %xmm0. */
double __attribute__((sseregparm)) mysin(void);
double __attribute__((sseregparm)) (*mysinfp)(void) = mysin;
double bar(double x)
{
return mysinfp();
}
/* { dg-final { scan-assembler "fldl" } } */
/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */
/* Make sure we know that mysinfp returns in %xmm0. */
double __attribute__((sseregparm)) mysin(double x);
double bar(double x)
{
return mysin(x);
}
/* { dg-final { scan-assembler "fldl" } } */
/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */
/* Make sure we know that mysinfp returns in %xmm0. */
double __attribute__((sseregparm)) mysin(void);
double bar(double x)
{
return mysin();
}
/* { dg-final { scan-assembler "fldl" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment