From 7e4fb06a5182286640bf73410d09ab324c5e73ad Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 27 Jun 2003 10:52:03 -0700 Subject: [PATCH] alpha.c (function_arg): Don't pass small aggregates in floating point registers. * config/alpha/alpha.c (function_arg): Don't pass small aggregates in floating point registers. Validate that we don't receive complex values here. Use #elif. (return_in_memory, function_value): New. (alpha_va_arg): Handle complex values as two arguments. * config/alpha/alpha.h (RETURN_IN_MEMORY): Use return_in_memory. (FUNCTION_VALUE, LIBCALL_VALUE): Use function_value. (SPLIT_COMPLEX_ARGS): New. * config/alpha/alpha-protos.h: Update. From-SVN: r68591 --- gcc/ChangeLog | 14 ++- gcc/config/alpha/alpha-protos.h | 3 + gcc/config/alpha/alpha.c | 163 +++++++++++++++++++++++++++++--- gcc/config/alpha/alpha.h | 27 ++---- 4 files changed, 174 insertions(+), 33 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a86f0a83d6a..9d71ea635e6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,4 +1,16 @@ -2003-06-13 Ulrich Weigand +2003-06-27 Richard Henderson + + * config/alpha/alpha.c (function_arg): Don't pass small aggregates + in floating point registers. Validate that we don't receive complex + values here. Use #elif. + (return_in_memory, function_value): New. + (alpha_va_arg): Handle complex values as two arguments. + * config/alpha/alpha.h (RETURN_IN_MEMORY): Use return_in_memory. + (FUNCTION_VALUE, LIBCALL_VALUE): Use function_value. + (SPLIT_COMPLEX_ARGS): New. + * config/alpha/alpha-protos.h: Update. + +2003-06-27 Ulrich Weigand * ggc-page.c (inverse_table): Change type of mult to size_t. (compute_inverse): Compute inverse using size_t, not unsigned int. diff --git a/gcc/config/alpha/alpha-protos.h b/gcc/config/alpha/alpha-protos.h index 3a342eb3f84..0e14e6b2da3 100644 --- a/gcc/config/alpha/alpha-protos.h +++ b/gcc/config/alpha/alpha-protos.h @@ -135,6 +135,9 @@ extern void alpha_setup_incoming_varargs (CUMULATIVE_ARGS, enum machine_mode, extern void alpha_va_start (tree, rtx); extern rtx alpha_va_arg (tree, tree); extern rtx function_arg (CUMULATIVE_ARGS, enum machine_mode, tree, int); +extern rtx function_value (tree, tree, enum machine_mode); +extern bool return_in_memory (tree, enum machine_mode); + extern void alpha_start_function (FILE *, const char *, tree); extern void alpha_end_function (FILE *, const char *, tree); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 1d1be31db95..d1b884fa780 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -5864,14 +5864,25 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, int basereg; int num_args; - /* Set up defaults for FP operands passed in FP registers, and - integral operands passed in integer registers. */ - if (TARGET_FPREGS - && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT - || GET_MODE_CLASS (mode) == MODE_FLOAT)) - basereg = 32 + 16; - else + /* Don't get confused and pass small structures in FP registers. */ + if (type && AGGREGATE_TYPE_P (type)) basereg = 16; + else + { +#ifdef ENABLE_CHECKING + /* With SPLIT_COMPLEX_ARGS, we shouldn't see any raw complex + values here. */ + if (COMPLEX_MODE_P (mode)) + abort (); +#endif + + /* Set up defaults for FP operands passed in FP registers, and + integral operands passed in integer registers. */ + if (TARGET_FPREGS && GET_MODE_CLASS (mode) == MODE_FLOAT) + basereg = 32 + 16; + else + basereg = 16; + } /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for the three platforms, so we can't avoid conditional compilation. */ @@ -5884,8 +5895,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type)) return NULL_RTX; } -#else -#if TARGET_ABI_UNICOSMK +#elif TARGET_ABI_UNICOSMK { int size; @@ -5949,7 +5959,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, } } } -#else +#elif TARGET_ABI_OSF { if (cum >= 6) return NULL_RTX; @@ -5963,12 +5973,119 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named)) basereg = 16; } -#endif /* TARGET_ABI_UNICOSMK */ -#endif /* TARGET_ABI_OPEN_VMS */ +#else +#error Unhandled ABI +#endif return gen_rtx_REG (mode, num_args + basereg); } +/* Return true if TYPE must be returned in memory, instead of in registers. */ + +bool +return_in_memory (tree type, enum machine_mode mode) +{ + int size; + + if (type) + { + mode = TYPE_MODE (type); + + /* All aggregates are returned in memory. */ + if (AGGREGATE_TYPE_P (type)) + return true; + } + + size = GET_MODE_SIZE (mode); + switch (GET_MODE_CLASS (mode)) + { + case MODE_VECTOR_FLOAT: + /* Pass all float vectors in memory, like an aggregate. */ + return true; + + case MODE_COMPLEX_FLOAT: + /* We judge complex floats on the size of their element, + not the size of the whole type. */ + size = GET_MODE_UNIT_SIZE (mode); + break; + + case MODE_INT: + case MODE_FLOAT: + case MODE_COMPLEX_INT: + case MODE_VECTOR_INT: + break; + + default: + /* ??? We get called on all sorts of random stuff from + aggregate_value_p. We can't abort, but it's not clear + what's safe to return. Pretend it's a struct I guess. */ + return true; + } + + /* Otherwise types must fit in one register. */ + return size > UNITS_PER_WORD; +} + +/* 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; otherwise, FUNC is 0. + MODE is set instead of VALTYPE for libcalls. + + On Alpha the value is found in $0 for integer functions and + $f0 for floating-point functions. */ + +rtx +function_value (tree valtype, tree func ATTRIBUTE_UNUSED, + enum machine_mode mode) +{ + unsigned int regnum; + enum mode_class class; + +#ifdef ENABLE_CHECKING + if (return_in_memory (valtype, mode)) + abort (); +#endif + + if (valtype) + mode = TYPE_MODE (valtype); + + class = GET_MODE_CLASS (mode); + switch (class) + { + case MODE_INT: + /* Do the same thing as PROMOTE_MODE. */ + mode = DImode; + /* FALLTHRU */ + + case MODE_COMPLEX_INT: + case MODE_VECTOR_INT: + regnum = 0; + break; + + case MODE_FLOAT: + regnum = 32; + break; + + case MODE_COMPLEX_FLOAT: + { + enum machine_mode cmode = GET_MODE_INNER (mode); + + return gen_rtx_PARALLEL + (VOIDmode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32), + GEN_INT (0)), + gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33), + GEN_INT (GET_MODE_SIZE (cmode))))); + } + + default: + abort (); + } + + return gen_rtx_REG (mode, regnum); +} + tree alpha_build_va_list (void) { @@ -6162,7 +6279,27 @@ alpha_va_arg (tree valist, tree type) indirect = 1; rounded_size = size_int (UNITS_PER_WORD); } - else if (FLOAT_TYPE_P (type)) + else if (TREE_CODE (type) == COMPLEX_TYPE) + { + rtx real_part, imag_part, value, tmp; + + real_part = alpha_va_arg (valist, TREE_TYPE (type)); + imag_part = alpha_va_arg (valist, TREE_TYPE (type)); + + /* ??? Most irritatingly, we're not returning the value here, + but the address. Since real_part and imag_part are not + necessarily contiguous, we must copy to local storage. */ + + real_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), real_part); + imag_part = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (type)), imag_part); + value = gen_rtx_CONCAT (TYPE_MODE (type), real_part, imag_part); + + tmp = assign_temp (type, 0, 1, 0); + emit_move_insn (tmp, value); + + return XEXP (tmp, 0); + } + else if (TREE_CODE (type) == REAL_TYPE) { tree fpaddend, cond; diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 7ba7b15483f..267d292a17d 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -994,25 +994,14 @@ extern int alpha_memory_latency; On Alpha the value is found in $0 for integer functions and $f0 for floating-point functions. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \ - && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \ - || POINTER_TYPE_P (VALTYPE)) \ - ? word_mode : TYPE_MODE (VALTYPE), \ - ((TARGET_FPREGS \ - && (TREE_CODE (VALTYPE) == REAL_TYPE \ - || TREE_CODE (VALTYPE) == COMPLEX_TYPE)) \ - ? 32 : 0)) +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + function_value (VALTYPE, FUNC, VOIDmode) /* 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, \ - (TARGET_FPREGS \ - && (GET_MODE_CLASS (MODE) == MODE_FLOAT \ - || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ - ? 32 : 0)) +#define LIBCALL_VALUE(MODE) \ + function_value (NULL, NULL, MODE) /* The definition of this macro implies that there are cases where a scalar value cannot be returned in registers. @@ -1021,10 +1010,7 @@ extern int alpha_memory_latency; are integers whose size is larger than 64 bits. */ #define RETURN_IN_MEMORY(TYPE) \ - (TYPE_MODE (TYPE) == BLKmode \ - || TYPE_MODE (TYPE) == TFmode \ - || TYPE_MODE (TYPE) == TCmode \ - || (TREE_CODE (TYPE) == INTEGER_TYPE && TYPE_PRECISION (TYPE) > 64)) + return_in_memory (TYPE, VOIDmode) /* 1 if N is a possible register number for a function value as seen by the caller. */ @@ -1889,3 +1875,6 @@ do { \ /* Generate calls to memcpy, etc., not bcopy, etc. */ #define TARGET_MEM_FUNCTIONS 1 + +/* Pass complex arguments independently. */ +#define SPLIT_COMPLEX_ARGS 1