function.c (assign_parms): Split complex arguments.
2003-06-03 Aldy Hernandez <aldyh@redhat.com> * function.c (assign_parms): Split complex arguments. * doc/tm.texi (SPLIT_COMPLEX_ARGS): Document. * expr.h (SPLIT_COMPLEX_ARGS): Define. (split_complex_types): Protoize. (split_complex_values): Protoize. * calls.c (expand_call): Split complex arguments on architectures that require it. (split_complex_values): New. (split_complex_types): New. * config/rs6000/rs6000.c (rs6000_libcall_value): New. (rs6000_function_value): Handle complex values on AIX. (rs6000_complex_function_value): New. * config/rs6000/rs6000-protos.h (rs6000_libcall_value): Protoize. * config/rs6000/rs6000.h (LIBCALL_VALUE): Call function. (SPLIT_COMPLEX_ARGS): New. From-SVN: r67367
This commit is contained in:
parent
24a4dd31f8
commit
ded9bf77e3
@ -1,3 +1,27 @@
|
||||
2003-06-03 Aldy Hernandez <aldyh@redhat.com>
|
||||
|
||||
* function.c (assign_parms): Split complex arguments.
|
||||
|
||||
* doc/tm.texi (SPLIT_COMPLEX_ARGS): Document.
|
||||
|
||||
* expr.h (SPLIT_COMPLEX_ARGS): Define.
|
||||
(split_complex_types): Protoize.
|
||||
(split_complex_values): Protoize.
|
||||
|
||||
* calls.c (expand_call): Split complex arguments on architectures
|
||||
that require it.
|
||||
(split_complex_values): New.
|
||||
(split_complex_types): New.
|
||||
|
||||
* config/rs6000/rs6000.c (rs6000_libcall_value): New.
|
||||
(rs6000_function_value): Handle complex values on AIX.
|
||||
(rs6000_complex_function_value): New.
|
||||
|
||||
* config/rs6000/rs6000-protos.h (rs6000_libcall_value): Protoize.
|
||||
|
||||
* config/rs6000/rs6000.h (LIBCALL_VALUE): Call function.
|
||||
(SPLIT_COMPLEX_ARGS): New.
|
||||
|
||||
2003-06-03 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* configure.in (HAVE_LD_PIE): Check for ld -pie.
|
||||
|
91
gcc/calls.c
91
gcc/calls.c
@ -2071,6 +2071,7 @@ expand_call (exp, target, ignore)
|
||||
rtx tail_call_insns = NULL_RTX;
|
||||
/* Data type of the function. */
|
||||
tree funtype;
|
||||
tree type_arg_types;
|
||||
/* Declaration of the function being called,
|
||||
or 0 if the function is computed (not known by name). */
|
||||
tree fndecl = 0;
|
||||
@ -2306,6 +2307,16 @@ expand_call (exp, target, ignore)
|
||||
abort ();
|
||||
funtype = TREE_TYPE (funtype);
|
||||
|
||||
/* Munge the tree to split complex arguments into their imaginary
|
||||
and real parts. */
|
||||
if (SPLIT_COMPLEX_ARGS)
|
||||
{
|
||||
type_arg_types = split_complex_types (TYPE_ARG_TYPES (funtype));
|
||||
actparms = split_complex_values (actparms);
|
||||
}
|
||||
else
|
||||
type_arg_types = TYPE_ARG_TYPES (funtype);
|
||||
|
||||
/* See if this is a call to a function that can return more than once
|
||||
or a call to longjmp or malloc. */
|
||||
flags |= special_function_p (fndecl, flags);
|
||||
@ -2359,9 +2370,9 @@ expand_call (exp, target, ignore)
|
||||
|
||||
if ((STRICT_ARGUMENT_NAMING
|
||||
|| ! PRETEND_OUTGOING_VARARGS_NAMED)
|
||||
&& TYPE_ARG_TYPES (funtype) != 0)
|
||||
&& type_arg_types != 0)
|
||||
n_named_args
|
||||
= (list_length (TYPE_ARG_TYPES (funtype))
|
||||
= (list_length (type_arg_types)
|
||||
/* Don't include the last named arg. */
|
||||
- (STRICT_ARGUMENT_NAMING ? 0 : 1)
|
||||
/* Count the struct value address, if it is passed as a parm. */
|
||||
@ -3447,6 +3458,82 @@ expand_call (exp, target, ignore)
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Traverse an argument list in VALUES and expand all complex
|
||||
arguments into their components. */
|
||||
tree
|
||||
split_complex_values (tree values)
|
||||
{
|
||||
tree p;
|
||||
|
||||
values = copy_list (values);
|
||||
|
||||
for (p = values; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree complex_value = TREE_VALUE (p);
|
||||
tree complex_type;
|
||||
|
||||
complex_type = TREE_TYPE (complex_value);
|
||||
if (!complex_type)
|
||||
continue;
|
||||
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE)
|
||||
{
|
||||
tree subtype;
|
||||
tree real, imag, next;
|
||||
|
||||
subtype = TREE_TYPE (complex_type);
|
||||
complex_value = save_expr (complex_value);
|
||||
real = build1 (REALPART_EXPR, subtype, complex_value);
|
||||
imag = build1 (IMAGPART_EXPR, subtype, complex_value);
|
||||
|
||||
TREE_VALUE (p) = real;
|
||||
next = TREE_CHAIN (p);
|
||||
imag = build_tree_list (NULL_TREE, imag);
|
||||
TREE_CHAIN (p) = imag;
|
||||
TREE_CHAIN (imag) = next;
|
||||
|
||||
/* Skip the newly created node. */
|
||||
p = TREE_CHAIN (p);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/* Traverse a list of TYPES and expand all complex types into their
|
||||
components. */
|
||||
tree
|
||||
split_complex_types (tree types)
|
||||
{
|
||||
tree p;
|
||||
|
||||
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)
|
||||
{
|
||||
tree next, imag;
|
||||
|
||||
/* Rewrite complex type with component type. */
|
||||
TREE_VALUE (p) = TREE_TYPE (complex_type);
|
||||
next = TREE_CHAIN (p);
|
||||
|
||||
/* Add another component type for the imaginary part. */
|
||||
imag = build_tree_list (NULL_TREE, TREE_VALUE (p));
|
||||
TREE_CHAIN (p) = imag;
|
||||
TREE_CHAIN (imag) = next;
|
||||
|
||||
/* Skip the newly created node. */
|
||||
p = TREE_CHAIN (p);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/* Output a library call to function FUN (a SYMBOL_REF rtx).
|
||||
The RETVAL parameter specifies whether return value needs to be saved, other
|
||||
|
@ -153,6 +153,7 @@ extern void setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *,
|
||||
enum machine_mode, tree,
|
||||
int *, int));
|
||||
extern rtx rs6000_function_value (tree, tree);
|
||||
extern rtx rs6000_libcall_value (enum machine_mode);
|
||||
extern struct rtx_def *rs6000_va_arg PARAMS ((tree, tree));
|
||||
extern int function_ok_for_sibcall PARAMS ((tree));
|
||||
#ifdef ARGS_SIZE_RTX
|
||||
|
@ -312,6 +312,7 @@ static rtx rs6000_got_sym PARAMS ((void));
|
||||
static inline int rs6000_tls_symbol_ref_1 PARAMS ((rtx *, void *));
|
||||
static const char *rs6000_get_some_local_dynamic_name PARAMS ((void));
|
||||
static int rs6000_get_some_local_dynamic_name_1 PARAMS ((rtx *, void *));
|
||||
static rtx rs6000_complex_function_value (enum machine_mode);
|
||||
|
||||
/* Hash table stuff for keeping track of TOC entries. */
|
||||
|
||||
@ -14361,6 +14362,33 @@ rs6000_memory_move_cost (mode, class, in)
|
||||
return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
|
||||
}
|
||||
|
||||
/* Return an RTX representing where to find the function value of a
|
||||
function returning MODE. */
|
||||
static rtx
|
||||
rs6000_complex_function_value (enum machine_mode mode)
|
||||
{
|
||||
unsigned int regno;
|
||||
rtx r1, r2;
|
||||
enum machine_mode inner = GET_MODE_INNER (mode);
|
||||
|
||||
if (FLOAT_MODE_P (mode))
|
||||
regno = FP_ARG_RETURN;
|
||||
else
|
||||
{
|
||||
regno = GP_ARG_RETURN;
|
||||
|
||||
/* 32-bit is OK since it'll go in r3/r4. */
|
||||
if (TARGET_32BIT)
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
|
||||
r1 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno),
|
||||
const0_rtx);
|
||||
r2 = gen_rtx_EXPR_LIST (inner, gen_rtx_REG (inner, regno + 1),
|
||||
GEN_INT (GET_MODE_UNIT_SIZE (inner)));
|
||||
return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
|
||||
}
|
||||
|
||||
/* 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;
|
||||
@ -14386,6 +14414,10 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
|
||||
|
||||
if (TREE_CODE (valtype) == REAL_TYPE && TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
regno = FP_ARG_RETURN;
|
||||
else if (TREE_CODE (valtype) == COMPLEX_TYPE
|
||||
&& TARGET_HARD_FLOAT
|
||||
&& SPLIT_COMPLEX_ARGS)
|
||||
return rs6000_complex_function_value (mode);
|
||||
else if (TREE_CODE (valtype) == VECTOR_TYPE && TARGET_ALTIVEC)
|
||||
regno = ALTIVEC_ARG_RETURN;
|
||||
else
|
||||
@ -14394,6 +14426,26 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
|
||||
/* Define how to find the value returned by a library function
|
||||
assuming the value has mode MODE. */
|
||||
rtx
|
||||
rs6000_libcall_value (enum machine_mode mode)
|
||||
{
|
||||
unsigned int regno;
|
||||
|
||||
if (GET_MODE_CLASS (mode) == MODE_FLOAT
|
||||
&& TARGET_HARD_FLOAT && TARGET_FPRS)
|
||||
regno = FP_ARG_RETURN;
|
||||
else if (ALTIVEC_VECTOR_MODE (mode))
|
||||
regno = ALTIVEC_ARG_RETURN;
|
||||
else if (COMPLEX_MODE_P (mode) && SPLIT_COMPLEX_ARGS)
|
||||
return rs6000_complex_function_value (mode);
|
||||
else
|
||||
regno = GP_ARG_RETURN;
|
||||
|
||||
return gen_rtx_REG (mode, regno);
|
||||
}
|
||||
|
||||
/* Return true if TYPE is of type __ev64_opaque__. */
|
||||
|
||||
static bool
|
||||
|
@ -1583,11 +1583,7 @@ typedef struct rs6000_stack {
|
||||
/* Define how to find the value returned by a library function
|
||||
assuming the value has mode MODE. */
|
||||
|
||||
#define LIBCALL_VALUE(MODE) \
|
||||
gen_rtx_REG (MODE, ALTIVEC_VECTOR_MODE (MODE) ? ALTIVEC_ARG_RETURN \
|
||||
: GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
||||
&& TARGET_HARD_FLOAT && TARGET_FPRS \
|
||||
? FP_ARG_RETURN : GP_ARG_RETURN)
|
||||
#define LIBCALL_VALUE(MODE) rs6000_libcall_value ((MODE))
|
||||
|
||||
/* The AIX ABI for the RS/6000 specifies that all structures are
|
||||
returned in memory. The Darwin ABI does the same. The SVR4 ABI
|
||||
@ -1815,6 +1811,13 @@ 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)
|
||||
|
||||
/* Perform any needed actions needed for a function that is receiving a
|
||||
variable number of arguments.
|
||||
|
||||
|
@ -3782,6 +3782,17 @@ the structure-value address. On many machines, no registers can be
|
||||
used for this purpose since all function arguments are pushed on the
|
||||
stack.
|
||||
|
||||
@findex SPLIT_COMPLEX_ARGS
|
||||
@item SPLIT_COMPLEX_ARGS
|
||||
|
||||
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.
|
||||
|
||||
@findex LOAD_ARGS_REVERSED
|
||||
@item LOAD_ARGS_REVERSED
|
||||
If defined, the order in which arguments are loaded into their
|
||||
|
@ -158,6 +158,14 @@ 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);
|
||||
|
||||
/* Provide a default value for STRICT_ARGUMENT_NAMING. */
|
||||
#ifndef STRICT_ARGUMENT_NAMING
|
||||
#define STRICT_ARGUMENT_NAMING 0
|
||||
|
@ -296,6 +296,7 @@ static void prepare_function_start PARAMS ((void));
|
||||
static void do_clobber_return_reg PARAMS ((rtx, void *));
|
||||
static void do_use_return_reg PARAMS ((rtx, void *));
|
||||
static void instantiate_virtual_regs_lossage PARAMS ((rtx));
|
||||
static tree split_complex_args (tree);
|
||||
|
||||
/* Pointer to chain of `struct function' for containing functions. */
|
||||
static GTY(()) struct function *outer_function_chain;
|
||||
@ -4346,7 +4347,7 @@ assign_parms (fndecl)
|
||||
given as a constant and a tree-expression. */
|
||||
struct args_size stack_args_size;
|
||||
tree fntype = TREE_TYPE (fndecl);
|
||||
tree fnargs = DECL_ARGUMENTS (fndecl);
|
||||
tree fnargs = DECL_ARGUMENTS (fndecl), orig_fnargs;
|
||||
/* This is used for the arg pointer when referring to stack args. */
|
||||
rtx internal_arg_pointer;
|
||||
/* This is a dummy PARM_DECL that we used for the function result if
|
||||
@ -4400,9 +4401,14 @@ assign_parms (fndecl)
|
||||
fnargs = function_result_decl;
|
||||
}
|
||||
|
||||
orig_fnargs = fnargs;
|
||||
|
||||
max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
|
||||
parm_reg_stack_loc = (rtx *) ggc_alloc_cleared (max_parm_reg * sizeof (rtx));
|
||||
|
||||
if (SPLIT_COMPLEX_ARGS)
|
||||
fnargs = split_complex_args (fnargs);
|
||||
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
#ifdef MAYBE_REG_PARM_STACK_SPACE
|
||||
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
|
||||
@ -5189,6 +5195,35 @@ assign_parms (fndecl)
|
||||
}
|
||||
}
|
||||
|
||||
if (SPLIT_COMPLEX_ARGS)
|
||||
{
|
||||
parm = orig_fnargs;
|
||||
|
||||
for (; parm; parm = TREE_CHAIN (parm))
|
||||
{
|
||||
tree type = TREE_TYPE (parm);
|
||||
|
||||
if (TREE_CODE (type) == COMPLEX_TYPE)
|
||||
{
|
||||
SET_DECL_RTL (parm,
|
||||
gen_rtx_CONCAT (DECL_MODE (parm),
|
||||
DECL_RTL (fnargs),
|
||||
DECL_RTL (TREE_CHAIN (fnargs))));
|
||||
DECL_INCOMING_RTL (parm)
|
||||
= gen_rtx_CONCAT (DECL_MODE (parm),
|
||||
DECL_INCOMING_RTL (fnargs),
|
||||
DECL_INCOMING_RTL (TREE_CHAIN (fnargs)));
|
||||
fnargs = TREE_CHAIN (fnargs);
|
||||
}
|
||||
else
|
||||
{
|
||||
SET_DECL_RTL (parm, DECL_RTL (fnargs));
|
||||
DECL_INCOMING_RTL (parm) = DECL_INCOMING_RTL (fnargs);
|
||||
}
|
||||
fnargs = TREE_CHAIN (fnargs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Output all parameter conversion instructions (possibly including calls)
|
||||
now that all parameters have been copied out of hard registers. */
|
||||
emit_insn (conversion_insns);
|
||||
@ -5292,6 +5327,36 @@ assign_parms (fndecl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static tree
|
||||
split_complex_args (tree args)
|
||||
{
|
||||
tree p;
|
||||
|
||||
args = copy_list (args);
|
||||
|
||||
for (p = args; p; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree complex_type = TREE_TYPE (p);
|
||||
|
||||
if (TREE_CODE (complex_type) == COMPLEX_TYPE)
|
||||
{
|
||||
tree decl;
|
||||
tree subtype = TREE_TYPE (complex_type);
|
||||
|
||||
/* Rewrite the PARM_DECL's type with its component. */
|
||||
TREE_TYPE (p) = subtype;
|
||||
DECL_ARG_TYPE (p) = TREE_TYPE (DECL_ARG_TYPE (p));
|
||||
|
||||
decl = build_decl (PARM_DECL, NULL_TREE, subtype);
|
||||
DECL_ARG_TYPE (decl) = DECL_ARG_TYPE (p);
|
||||
TREE_CHAIN (decl) = TREE_CHAIN (p);
|
||||
TREE_CHAIN (p) = decl;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
/* Indicate whether REGNO is an incoming argument to the current function
|
||||
that was promoted to a wider mode. If so, return the RTX for the
|
||||
|
Loading…
Reference in New Issue
Block a user