summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authoraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2003-06-03 11:14:07 +0000
committeraldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4>2003-06-03 11:14:07 +0000
commit915e81b8b3ab82d559c65434587a01ae746d9035 (patch)
tree20dae8c49de7b0cfdf57e381abee0961ed2ef0d6 /gcc
parentc3ce66b01e47e99e429d17fb6df311852d2d5fc5 (diff)
downloadgcc-915e81b8b3ab82d559c65434587a01ae746d9035.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@67367 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/calls.c91
-rw-r--r--gcc/config/rs6000/rs6000-protos.h1
-rw-r--r--gcc/config/rs6000/rs6000.c52
-rw-r--r--gcc/config/rs6000/rs6000.h13
-rw-r--r--gcc/doc/tm.texi11
-rw-r--r--gcc/expr.h8
-rw-r--r--gcc/function.c67
8 files changed, 259 insertions, 8 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 30b502ddb3a..28fad05757a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/calls.c b/gcc/calls.c
index 9d7899c8bce..4e95735376c 100644
--- a/gcc/calls.c
+++ b/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
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index da75516de37..f088a045858 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -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
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index f851e95af6a..2b9a76124e3 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -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
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index d40626f5846..3edf959a511 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -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.
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 839cf108c22..7215705eb80 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -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
diff --git a/gcc/expr.h b/gcc/expr.h
index 8cf5a8e5a6c..594df73a0d2 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -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
diff --git a/gcc/function.c b/gcc/function.c
index 76184b9b659..c090d4aa869 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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