diff options
author | aldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-06-03 11:14:07 +0000 |
---|---|---|
committer | aldyh <aldyh@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-06-03 11:14:07 +0000 |
commit | 915e81b8b3ab82d559c65434587a01ae746d9035 (patch) | |
tree | 20dae8c49de7b0cfdf57e381abee0961ed2ef0d6 /gcc | |
parent | c3ce66b01e47e99e429d17fb6df311852d2d5fc5 (diff) | |
download | gcc-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/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/calls.c | 91 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 52 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 13 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 11 | ||||
-rw-r--r-- | gcc/expr.h | 8 | ||||
-rw-r--r-- | gcc/function.c | 67 |
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 |