re PR target/14547 (Passing _Complex long double does not follow the ABI)
PR target/14547 * target.h (struct gcc_target): Move calls substructure before booleans. Add split_complex_arg. * function.c (assign_parms, split_complex_args): Use it. * calls.c (expand_call): Likewise. (split_complex_values): Likewise. Check for splittable types before allocating memory. (split_complex_types): Likewise. * system.h (SPLIT_COMPLEX_ARGS): Poison. * expr.h (SPLIT_COMPLEX_ARGS): Remove. * target-def.h (TARGET_SPLIT_COMPLEX_ARG): New. * config/alpha/alpha.c (alpha_split_complex_arg): New. (TARGET_SPLIT_COMPLEX_ARG): New. * config/alpha/alpha.h (SPLIT_COMPLEX_ARGS): Remove. * config/rs6000/rs6000.c (TARGET_SPLIT_COMPLEX_ARG): New. (rs6000_override_options): Zap it for non-AIX. (rs6000_function_value): Use targetm.calls.split_complex_arg. * config/rs6000/rs6000.h (SPLIT_COMPLEX_ARGS): Remove. * config/xtensa/xtensa.c (TARGET_SPLIT_COMPLEX_ARG): New. * config/xtensa/xtensa.h (SPLIT_COMPLEX_ARGS): Remove. * doc/tm.texi (TARGET_SPLIT_COMPLEX_ARG): Modify from old SPLIT_COMPLEX_ARGS entry. From-SVN: r79376
This commit is contained in:
parent
ac011d28bb
commit
42ba513004
@ -1,3 +1,28 @@
|
||||
2004-03-12 Richard Henderson <rth@redhat.com>
|
||||
|
||||
PR target/14547
|
||||
* target.h (struct gcc_target): Move calls substructure before
|
||||
booleans. Add split_complex_arg.
|
||||
* function.c (assign_parms, split_complex_args): Use it.
|
||||
* calls.c (expand_call): Likewise.
|
||||
(split_complex_values): Likewise. Check for splittable types
|
||||
before allocating memory.
|
||||
(split_complex_types): Likewise.
|
||||
* system.h (SPLIT_COMPLEX_ARGS): Poison.
|
||||
* expr.h (SPLIT_COMPLEX_ARGS): Remove.
|
||||
* target-def.h (TARGET_SPLIT_COMPLEX_ARG): New.
|
||||
* config/alpha/alpha.c (alpha_split_complex_arg): New.
|
||||
(TARGET_SPLIT_COMPLEX_ARG): New.
|
||||
* config/alpha/alpha.h (SPLIT_COMPLEX_ARGS): Remove.
|
||||
* config/rs6000/rs6000.c (TARGET_SPLIT_COMPLEX_ARG): New.
|
||||
(rs6000_override_options): Zap it for non-AIX.
|
||||
(rs6000_function_value): Use targetm.calls.split_complex_arg.
|
||||
* config/rs6000/rs6000.h (SPLIT_COMPLEX_ARGS): Remove.
|
||||
* config/xtensa/xtensa.c (TARGET_SPLIT_COMPLEX_ARG): New.
|
||||
* config/xtensa/xtensa.h (SPLIT_COMPLEX_ARGS): Remove.
|
||||
* doc/tm.texi (TARGET_SPLIT_COMPLEX_ARG): Modify from old
|
||||
SPLIT_COMPLEX_ARGS entry.
|
||||
|
||||
2004-03-11 Richard Henderson <rth@redhat.com>
|
||||
|
||||
* config/alpha/alpha.c (xfloating_ops, vax_cvt_ops): New.
|
||||
|
30
gcc/calls.c
30
gcc/calls.c
@ -2347,7 +2347,7 @@ expand_call (tree exp, rtx target, int ignore)
|
||||
|
||||
/* Munge the tree to split complex arguments into their imaginary
|
||||
and real parts. */
|
||||
if (SPLIT_COMPLEX_ARGS)
|
||||
if (targetm.calls.split_complex_arg)
|
||||
{
|
||||
type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype));
|
||||
actparms = split_complex_values (actparms);
|
||||
@ -3557,6 +3557,17 @@ split_complex_values (tree values)
|
||||
{
|
||||
tree p;
|
||||
|
||||
/* Before allocating memory, check for the common case of no complex. */
|
||||
for (p = values; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree type = TREE_TYPE (TREE_VALUE (p));
|
||||
if (type && TREE_CODE (type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (type))
|
||||
goto found;
|
||||
}
|
||||
return values;
|
||||
|
||||
found:
|
||||
values = copy_list (values);
|
||||
|
||||
for (p = values; p; p = TREE_CHAIN (p))
|
||||
@ -3568,7 +3579,8 @@ split_complex_values (tree values)
|
||||
if (!complex_type)
|
||||
continue;
|
||||
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE)
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (complex_type))
|
||||
{
|
||||
tree subtype;
|
||||
tree real, imag, next;
|
||||
@ -3599,13 +3611,25 @@ split_complex_types (tree types)
|
||||
{
|
||||
tree p;
|
||||
|
||||
/* Before allocating memory, check for the common case of no complex. */
|
||||
for (p = types; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree type = TREE_VALUE (p);
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (type))
|
||||
goto found;
|
||||
}
|
||||
return types;
|
||||
|
||||
found:
|
||||
types = copy_list (types);
|
||||
|
||||
for (p = types; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree complex_type = TREE_VALUE (p);
|
||||
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE)
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (complex_type))
|
||||
{
|
||||
tree next, imag;
|
||||
|
||||
|
@ -5889,7 +5889,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
|
||||
else
|
||||
{
|
||||
#ifdef ENABLE_CHECKING
|
||||
/* With SPLIT_COMPLEX_ARGS, we shouldn't see any raw complex
|
||||
/* With alpha_split_complex_arg, we shouldn't see any raw complex
|
||||
values here. */
|
||||
if (COMPLEX_MODE_P (mode))
|
||||
abort ();
|
||||
@ -6106,6 +6106,15 @@ function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
|
||||
return gen_rtx_REG (mode, regnum);
|
||||
}
|
||||
|
||||
/* TCmode complex values are passed by invisible reference. We
|
||||
should not split these values. */
|
||||
|
||||
static bool
|
||||
alpha_split_complex_arg (tree type)
|
||||
{
|
||||
return TYPE_MODE (type) != TCmode;
|
||||
}
|
||||
|
||||
static tree
|
||||
alpha_build_builtin_va_list (void)
|
||||
{
|
||||
@ -10223,6 +10232,8 @@ alpha_init_libfuncs (void)
|
||||
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
|
||||
#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
|
||||
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
|
||||
#undef TARGET_SPLIT_COMPLEX_ARG
|
||||
#define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg
|
||||
|
||||
#undef TARGET_BUILD_BUILTIN_VA_LIST
|
||||
#define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list
|
||||
|
@ -1839,6 +1839,3 @@ do { \
|
||||
|
||||
/* Generate calls to memcpy, etc., not bcopy, etc. */
|
||||
#define TARGET_MEM_FUNCTIONS 1
|
||||
|
||||
/* Pass complex arguments independently. */
|
||||
#define SPLIT_COMPLEX_ARGS 1
|
||||
|
@ -621,6 +621,8 @@ static const char alt_reg_names[][8] =
|
||||
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
|
||||
#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
|
||||
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
|
||||
#undef TARGET_SPLIT_COMPLEX_ARG
|
||||
#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
|
||||
|
||||
#undef TARGET_BUILD_BUILTIN_VA_LIST
|
||||
#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
|
||||
@ -1006,6 +1008,11 @@ rs6000_override_options (const char *default_cpu)
|
||||
|
||||
/* Arrange to save and restore machine status around nested functions. */
|
||||
init_machine_status = rs6000_init_machine_status;
|
||||
|
||||
/* We should always be splitting complex arguments, but we can't break
|
||||
Linux and Darwin ABIs at the moment. For now, only AIX is fixed. */
|
||||
if (DEFAULT_ABI != ABI_AIX)
|
||||
targetm.calls.split_complex_arg = NULL;
|
||||
}
|
||||
|
||||
/* Handle generic options of the form -mfoo=yes/no.
|
||||
@ -15970,7 +15977,7 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
|
||||
regno = FP_ARG_RETURN;
|
||||
else if (TREE_CODE (valtype) == COMPLEX_TYPE
|
||||
&& TARGET_HARD_FLOAT
|
||||
&& SPLIT_COMPLEX_ARGS)
|
||||
&& targetm.calls.split_complex_arg)
|
||||
return rs6000_complex_function_value (mode);
|
||||
else if (TREE_CODE (valtype) == VECTOR_TYPE && TARGET_ALTIVEC)
|
||||
regno = ALTIVEC_ARG_RETURN;
|
||||
@ -15992,7 +15999,7 @@ rs6000_libcall_value (enum machine_mode mode)
|
||||
regno = FP_ARG_RETURN;
|
||||
else if (ALTIVEC_VECTOR_MODE (mode))
|
||||
regno = ALTIVEC_ARG_RETURN;
|
||||
else if (COMPLEX_MODE_P (mode) && SPLIT_COMPLEX_ARGS)
|
||||
else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
|
||||
return rs6000_complex_function_value (mode);
|
||||
else
|
||||
regno = GP_ARG_RETURN;
|
||||
|
@ -1846,13 +1846,6 @@ typedef struct rs6000_args
|
||||
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
|
||||
function_arg_boundary (MODE, TYPE)
|
||||
|
||||
/* Define to nonzero if complex arguments should be split into their
|
||||
corresponding components.
|
||||
|
||||
This should be set for Linux and Darwin as well, but we can't break
|
||||
the ABIs at the moment. For now, only AIX gets fixed. */
|
||||
#define SPLIT_COMPLEX_ARGS (DEFAULT_ABI == ABI_AIX)
|
||||
|
||||
/* Implement `va_start' for varargs and stdarg. */
|
||||
#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
|
||||
rs6000_va_start (valist, nextarg)
|
||||
|
@ -251,6 +251,8 @@ static const int reg_nonleaf_alloc_order[FIRST_PSEUDO_REGISTER] =
|
||||
|
||||
#undef TARGET_RETURN_IN_MEMORY
|
||||
#define TARGET_RETURN_IN_MEMORY xtensa_return_in_memory
|
||||
#undef TARGET_SPLIT_COMPLEX_ARG
|
||||
#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
|
||||
|
||||
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
|
||||
#define TARGET_EXPAND_BUILTIN_SAVEREGS xtensa_builtin_saveregs
|
||||
|
@ -794,9 +794,6 @@ typedef struct xtensa_args
|
||||
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
|
||||
|| TREE_ADDRESSABLE (TYPE)))
|
||||
|
||||
/* Pass complex arguments independently. */
|
||||
#define SPLIT_COMPLEX_ARGS 1
|
||||
|
||||
/* Profiling Xtensa code is typically done with the built-in profiling
|
||||
feature of Tensilica's instruction set simulator, which does not
|
||||
require any compiler support. Profiling code on a real (i.e.,
|
||||
|
@ -3794,16 +3794,18 @@ used for this purpose since all function arguments are pushed on the
|
||||
stack.
|
||||
@end defmac
|
||||
|
||||
@defmac SPLIT_COMPLEX_ARGS
|
||||
@deftypefn {Target Hook} bool TARGET_SPLIT_COMPLEX_ARG (tree @var{type})
|
||||
This hook should return true if parameter of type @var{type} are passed
|
||||
as two scalar parameters. By default, GCC will attempt to pack complex
|
||||
arguments into the target's word size. Some ABIs require complex arguments
|
||||
to be split and treated as their individual components. For example, on
|
||||
AIX64, complex floats should be passed in a pair of floating point
|
||||
registers, even though a complex float would fit in one 64-bit floating
|
||||
point register.
|
||||
|
||||
Define this macro to a nonzero value if complex function arguments
|
||||
should be split into their corresponding components. By default, GCC
|
||||
will attempt to pack complex arguments into the target's word size.
|
||||
Some ABIs require complex arguments to be split and treated as their
|
||||
individual components. For example, on AIX64, complex floats should
|
||||
be passed in a pair of floating point registers, even though a complex
|
||||
float would fit in one 64-bit floating point register.
|
||||
@end defmac
|
||||
The default value of this hook is @code{NULL}, which is treated as always
|
||||
false.
|
||||
@end deftypefn
|
||||
|
||||
@node Scalar Return
|
||||
@subsection How Scalar Function Values Are Returned
|
||||
|
@ -188,11 +188,6 @@ do { \
|
||||
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) PARM_BOUNDARY
|
||||
#endif
|
||||
|
||||
/* Define to nonzero if complex arguments should be split into their
|
||||
corresponding components. */
|
||||
#ifndef SPLIT_COMPLEX_ARGS
|
||||
#define SPLIT_COMPLEX_ARGS 0
|
||||
#endif
|
||||
tree split_complex_types (tree);
|
||||
tree split_complex_values (tree);
|
||||
|
||||
|
@ -4349,7 +4349,8 @@ assign_parms (tree fndecl)
|
||||
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
|
||||
parm_reg_stack_loc = ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
|
||||
|
||||
if (SPLIT_COMPLEX_ARGS)
|
||||
/* If the target wants to split complex arguments into scalars, do so. */
|
||||
if (targetm.calls.split_complex_arg)
|
||||
fnargs = split_complex_args (fnargs);
|
||||
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
@ -5225,11 +5226,12 @@ assign_parms (tree fndecl)
|
||||
}
|
||||
}
|
||||
|
||||
if (SPLIT_COMPLEX_ARGS && fnargs != orig_fnargs)
|
||||
if (targetm.calls.split_complex_arg && fnargs != orig_fnargs)
|
||||
{
|
||||
for (parm = orig_fnargs; parm; parm = TREE_CHAIN (parm))
|
||||
{
|
||||
if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE)
|
||||
if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (TREE_TYPE (parm)))
|
||||
{
|
||||
rtx tmp, real, imag;
|
||||
enum machine_mode inner = GET_MODE_INNER (DECL_MODE (parm));
|
||||
@ -5373,8 +5375,12 @@ split_complex_args (tree args)
|
||||
|
||||
/* Before allocating memory, check for the common case of no complex. */
|
||||
for (p = args; p; p = TREE_CHAIN (p))
|
||||
if (TREE_CODE (TREE_TYPE (p)) == COMPLEX_TYPE)
|
||||
goto found;
|
||||
{
|
||||
tree type = TREE_TYPE (p);
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (type))
|
||||
goto found;
|
||||
}
|
||||
return args;
|
||||
|
||||
found:
|
||||
@ -5383,7 +5389,8 @@ split_complex_args (tree args)
|
||||
for (p = args; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree type = TREE_TYPE (p);
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE)
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE
|
||||
&& targetm.calls.split_complex_arg (type))
|
||||
{
|
||||
tree decl;
|
||||
tree subtype = TREE_TYPE (type);
|
||||
|
@ -606,7 +606,7 @@ typedef char _Bool;
|
||||
STRUCT_VALUE_INCOMING STRICT_ARGUMENT_NAMING \
|
||||
PROMOTE_FUNCTION_RETURN PROMOTE_PROTOTYPES STRUCT_VALUE_REGNUM \
|
||||
SETUP_INCOMING_VARARGS EXPAND_BUILTIN_SAVEREGS \
|
||||
DEFAULT_SHORT_ENUMS
|
||||
DEFAULT_SHORT_ENUMS SPLIT_COMPLEX_ARGS
|
||||
|
||||
/* Other obsolete target macros, or macros that used to be in target
|
||||
headers and were not used, and may be obsolete or may never have
|
||||
|
@ -346,7 +346,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#define TARGET_EXPAND_BUILTIN_SAVEREGS default_expand_builtin_saveregs
|
||||
#define TARGET_SETUP_INCOMING_VARARGS default_setup_incoming_varargs
|
||||
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_false
|
||||
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED default_pretend_outgoing_varargs_named
|
||||
#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED \
|
||||
default_pretend_outgoing_varargs_named
|
||||
#define TARGET_SPLIT_COMPLEX_ARG NULL
|
||||
|
||||
#define TARGET_CALLS { \
|
||||
TARGET_PROMOTE_FUNCTION_ARGS, \
|
||||
@ -359,6 +361,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
TARGET_SETUP_INCOMING_VARARGS, \
|
||||
TARGET_STRICT_ARGUMENT_NAMING, \
|
||||
TARGET_PRETEND_OUTGOING_VARARGS_NAMED, \
|
||||
TARGET_SPLIT_COMPLEX_ARG, \
|
||||
}
|
||||
|
||||
/* The whole shebang. */
|
||||
@ -403,6 +406,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
TARGET_DEFAULT_SHORT_ENUMS, \
|
||||
TARGET_BUILTIN_SETJMP_FRAME_VALUE, \
|
||||
TARGET_MD_ASM_CLOBBERS, \
|
||||
TARGET_CALLS, \
|
||||
TARGET_HAVE_NAMED_SECTIONS, \
|
||||
TARGET_HAVE_CTORS_DTORS, \
|
||||
TARGET_HAVE_TLS, \
|
||||
@ -410,7 +414,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
TARGET_TERMINATE_DW2_EH_FRAME_INFO, \
|
||||
TARGET_ASM_FILE_START_APP_OFF, \
|
||||
TARGET_ASM_FILE_START_FILE_DIRECTIVE, \
|
||||
TARGET_CALLS, \
|
||||
}
|
||||
|
||||
#include "hooks.h"
|
||||
|
43
gcc/target.h
43
gcc/target.h
@ -429,6 +429,30 @@ struct gcc_target
|
||||
the port wishes to automatically clobber for all asms. */
|
||||
tree (* md_asm_clobbers) (tree);
|
||||
|
||||
/* Functions relating to calls - argument passing, returns, etc. */
|
||||
struct calls {
|
||||
bool (*promote_function_args) (tree fntype);
|
||||
bool (*promote_function_return) (tree fntype);
|
||||
bool (*promote_prototypes) (tree fntype);
|
||||
rtx (*struct_value_rtx) (tree fndecl, int incoming);
|
||||
bool (*return_in_memory) (tree type, tree fndecl);
|
||||
bool (*return_in_msb) (tree type);
|
||||
rtx (*expand_builtin_saveregs) (void);
|
||||
/* Returns pretend_argument_size. */
|
||||
void (*setup_incoming_varargs) (CUMULATIVE_ARGS *ca, enum machine_mode mode,
|
||||
tree type, int *pretend_arg_size,
|
||||
int second_time);
|
||||
bool (*strict_argument_naming) (CUMULATIVE_ARGS *ca);
|
||||
/* Returns true if we should use
|
||||
targetm.calls.setup_incoming_varargs() and/or
|
||||
targetm.calls.strict_argument_naming(). */
|
||||
bool (*pretend_outgoing_varargs_named) (CUMULATIVE_ARGS *ca);
|
||||
|
||||
/* Given a complex type T, return true if a parameter of type T
|
||||
should be passed as two scalars. */
|
||||
bool (* split_complex_arg) (tree type);
|
||||
} calls;
|
||||
|
||||
/* Leave the boolean fields at the end. */
|
||||
|
||||
/* True if arbitrary sections are supported. */
|
||||
@ -455,24 +479,7 @@ struct gcc_target
|
||||
at the beginning of assembly output. */
|
||||
bool file_start_file_directive;
|
||||
|
||||
/* Functions relating to calls - argument passing, returns, etc. */
|
||||
struct calls {
|
||||
bool (*promote_function_args) (tree fntype);
|
||||
bool (*promote_function_return) (tree fntype);
|
||||
bool (*promote_prototypes) (tree fntype);
|
||||
rtx (*struct_value_rtx) (tree fndecl, int incoming);
|
||||
bool (*return_in_memory) (tree type, tree fndecl);
|
||||
bool (*return_in_msb) (tree type);
|
||||
rtx (*expand_builtin_saveregs) (void);
|
||||
/* Returns pretend_argument_size. */
|
||||
void (*setup_incoming_varargs) (CUMULATIVE_ARGS *ca, enum machine_mode mode,
|
||||
tree type, int *pretend_arg_size, int second_time);
|
||||
bool (*strict_argument_naming) (CUMULATIVE_ARGS *ca);
|
||||
/* Returns true if we should use
|
||||
targetm.calls.setup_incoming_varargs() and/or
|
||||
targetm.calls.strict_argument_naming(). */
|
||||
bool (*pretend_outgoing_varargs_named) (CUMULATIVE_ARGS *ca);
|
||||
} calls;
|
||||
/* Leave the boolean fields at the end. */
|
||||
};
|
||||
|
||||
extern struct gcc_target targetm;
|
||||
|
Loading…
Reference in New Issue
Block a user