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:
Aldy Hernandez 2003-06-03 11:14:07 +00:00 committed by Aldy Hernandez
parent 24a4dd31f8
commit ded9bf77e3
8 changed files with 259 additions and 8 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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