diff options
| author | rsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-11-16 19:10:09 +0000 |
|---|---|---|
| committer | rsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-11-16 19:10:09 +0000 |
| commit | 2c8ff1ed92619c18ef59ae4d66a3cb7ef62de1ac (patch) | |
| tree | 9ef329c0c8bbcf96f5ead9aa89d71751793d4122 /gcc/config/mips/mips.c | |
| parent | 07a40807d48bc44e008c55461f10e35a65e855d1 (diff) | |
| download | ppe42-gcc-2c8ff1ed92619c18ef59ae4d66a3cb7ef62de1ac.tar.gz ppe42-gcc-2c8ff1ed92619c18ef59ae4d66a3cb7ef62de1ac.zip | |
* Makefile.in (expr.o): Depend on $(TARGET_H).
* target.h (return_in_msb): New target hook.
* target-def.h (TARGET_RETURN_IN_MSB): New macro.
(TARGET_CALLS): Include it.
* calls.c (shift_returned_value): New function.
(expand_call): Use it.
* expr.c: Include target.h.
(copy_blkmode_from_reg): Check targetm.calls.return_in_msb when
deciding what padding is needed. Change the name of the local
padding variable from big_endian_correction to padding_correction.
* stmt.c (shift_return_value): New function.
(expand_return): Use it. Adjust memory->register copy in the same
way as copy_blkmode_from_reg. Only change the return register's
mode if it was originally BLKmode.
* doc/tm.texi (TARGET_RETURN_IN_MSB): Document.
* config/mips/mips.c (TARGET_RETURN_IN_MSB): Define.
(mips_fpr_return_fields): New, split out from mips_function_value.
(mips_return_in_msb, mips_return_fpr_pair): New functions.
(mips_function_value): Rework to use the functions above.
* config/mips/irix6-libc-compat.c: Delete.
* config/mips/t-iris6 (LIB2FUNCS_STATIC_EXTRA): Undefine.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@73652 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mips/mips.c')
| -rw-r--r-- | gcc/config/mips/mips.c | 233 |
1 files changed, 136 insertions, 97 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 9b2bc2f257d..6096eddd245 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -255,6 +255,11 @@ static void mips_select_section (tree, int, unsigned HOST_WIDE_INT) ATTRIBUTE_UNUSED; static bool mips_in_small_data_p (tree); static void mips_encode_section_info (tree, rtx, int); +static int mips_fpr_return_fields (tree, tree *); +static bool mips_return_in_msb (tree); +static rtx mips_return_fpr_pair (enum machine_mode mode, + enum machine_mode mode1, HOST_WIDE_INT, + enum machine_mode mode2, HOST_WIDE_INT); static rtx mips16_gp_pseudo_reg (void); static void mips16_fp_args (FILE *, int, int); static void build_mips16_function_stub (FILE *); @@ -787,6 +792,8 @@ const struct mips_cpu_info mips_cpu_info_table[] = { #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST mips_build_builtin_va_list +#undef TARGET_RETURN_IN_MSB +#define TARGET_RETURN_IN_MSB mips_return_in_msb struct gcc_target targetm = TARGET_INITIALIZER; @@ -7120,6 +7127,96 @@ mips_encode_section_info (tree decl, rtx rtl, int first) default_encode_section_info (decl, rtl, first); } +/* See whether VALTYPE is a record whose fields should be returned in + floating-point registers. If so, return the number of fields and + list them in FIELDS (which should have two elements). Return 0 + otherwise. + + For n32 & n64, a structure with one or two fields is returned in + floating-point registers as long as every field has a floating-point + type. */ + +static int +mips_fpr_return_fields (tree valtype, tree *fields) +{ + tree field; + int i; + + if (!TARGET_NEWABI) + return 0; + + if (TREE_CODE (valtype) != RECORD_TYPE) + return 0; + + i = 0; + for (field = TYPE_FIELDS (valtype); field != 0; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + if (TREE_CODE (TREE_TYPE (field)) != REAL_TYPE) + return 0; + + if (i == 2) + return 0; + + fields[i++] = field; + } + return i; +} + + +/* Implement TARGET_RETURN_IN_MSB. For n32 & n64, we should return + a value in the most significant part of $2/$3 if: + + - the target is big-endian; + + - the value has a structure or union type (we generalize this to + cover aggregates from other languages too); and + + - the structure is not returned in floating-point registers. */ + +static bool +mips_return_in_msb (tree valtype) +{ + tree fields[2]; + + return (TARGET_NEWABI + && TARGET_BIG_ENDIAN + && AGGREGATE_TYPE_P (valtype) + && mips_fpr_return_fields (valtype, fields) == 0); +} + + +/* Return a composite value in a pair of floating-point registers. + MODE1 and OFFSET1 are the mode and byte offset for the first value, + likewise MODE2 and OFFSET2 for the second. MODE is the mode of the + complete value. + + For n32 & n64, $f0 always holds the first value and $f2 the second. + Otherwise the values are packed together as closely as possible. */ + +static rtx +mips_return_fpr_pair (enum machine_mode mode, + enum machine_mode mode1, HOST_WIDE_INT offset1, + enum machine_mode mode2, HOST_WIDE_INT offset2) +{ + int inc; + + inc = (TARGET_NEWABI ? 2 : FP_INC); + return gen_rtx_PARALLEL + (mode, + gen_rtvec (2, + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (mode1, FP_RETURN), + GEN_INT (offset1)), + gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (mode2, FP_RETURN + inc), + GEN_INT (offset2)))); + +} + + /* Implement FUNCTION_VALUE and LIBCALL_VALUE. For normal calls, VALTYPE is the return type and MODE is VOIDmode. For libcalls, VALTYPE is null and MODE is the mode of the return value. */ @@ -7128,121 +7225,63 @@ rtx mips_function_value (tree valtype, tree func ATTRIBUTE_UNUSED, enum machine_mode mode) { - int reg = GP_RETURN; - enum mode_class mclass; - int unsignedp = 1; - if (valtype) { + tree fields[2]; + int unsignedp; + mode = TYPE_MODE (valtype); unsignedp = TREE_UNSIGNED (valtype); /* Since we define PROMOTE_FUNCTION_RETURN, we must promote the mode just as PROMOTE_MODE does. */ mode = promote_mode (valtype, mode, &unsignedp, 1); - } - mclass = GET_MODE_CLASS (mode); - - if (mclass == MODE_FLOAT && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) - reg = FP_RETURN; - - else if (mclass == MODE_FLOAT && mode == TFmode) - /* long doubles are really split between f0 and f2, not f1. Eek. - Use DImode for each component, since GCC wants integer modes - for subregs. */ - return gen_rtx_PARALLEL - (VOIDmode, - gen_rtvec (2, - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (DImode, FP_RETURN), - GEN_INT (0)), - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (DImode, FP_RETURN + 2), - GEN_INT (GET_MODE_SIZE (mode) / 2)))); - - - else if (mclass == MODE_COMPLEX_FLOAT - && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2) - { - 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, FP_RETURN), - GEN_INT (0)), - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (cmode, FP_RETURN + FP_INC), - GEN_INT (GET_MODE_SIZE (cmode))))); - } - - else if (valtype && TREE_CODE (valtype) == RECORD_TYPE - && mips_abi != ABI_32 - && mips_abi != ABI_O64 - && mips_abi != ABI_EABI) - { - /* A struct with only one or two floating point fields is returned in - the floating point registers. */ - tree field, fields[2]; - int i; - - for (i = 0, field = TYPE_FIELDS (valtype); field; - field = TREE_CHAIN (field)) - { - if (TREE_CODE (field) != FIELD_DECL) - continue; - if (TREE_CODE (TREE_TYPE (field)) != REAL_TYPE || i >= 2) - break; + /* Handle structures whose fields are returned in $f0/$f2. */ + switch (mips_fpr_return_fields (valtype, fields)) + { + case 1: + return gen_rtx_REG (mode, FP_RETURN); - fields[i++] = field; + case 2: + return mips_return_fpr_pair (mode, + TYPE_MODE (TREE_TYPE (fields[0])), + int_byte_position (fields[0]), + TYPE_MODE (TREE_TYPE (fields[1])), + int_byte_position (fields[1])); } - /* Must check i, so that we reject structures with no elements. */ - if (! field) + /* If a value is passed in the most significant part of a register, see + whether we have to round the mode up to a whole number of words. */ + if (mips_return_in_msb (valtype)) { - if (i == 1) + HOST_WIDE_INT size = int_size_in_bytes (valtype); + if (size % UNITS_PER_WORD != 0) { - /* The structure has DImode, but we don't allow DImode values - in FP registers, so we use a PARALLEL even though it isn't - strictly necessary. */ - enum machine_mode field_mode = TYPE_MODE (TREE_TYPE (fields[0])); - - return gen_rtx_PARALLEL - (mode, - gen_rtvec (1, - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (field_mode, - FP_RETURN), - const0_rtx))); - } - - else if (i == 2) - { - enum machine_mode first_mode - = TYPE_MODE (TREE_TYPE (fields[0])); - enum machine_mode second_mode - = TYPE_MODE (TREE_TYPE (fields[1])); - HOST_WIDE_INT first_offset = int_byte_position (fields[0]); - HOST_WIDE_INT second_offset = int_byte_position (fields[1]); - - return gen_rtx_PARALLEL - (mode, - gen_rtvec (2, - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (first_mode, - FP_RETURN), - GEN_INT (first_offset)), - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (second_mode, - FP_RETURN + 2), - GEN_INT (second_offset)))); + size += UNITS_PER_WORD - size % UNITS_PER_WORD; + mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); } } } - return gen_rtx_REG (mode, reg); + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE) + return gen_rtx_REG (mode, FP_RETURN); + + /* Handle long doubles for n32 & n64. */ + if (mode == TFmode) + return mips_return_fpr_pair (mode, + DImode, 0, + DImode, GET_MODE_SIZE (mode) / 2); + + if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT + && GET_MODE_SIZE (mode) <= UNITS_PER_HWFPVALUE * 2) + return mips_return_fpr_pair (mode, + GET_MODE_INNER (mode), 0, + GET_MODE_INNER (mode), + GET_MODE_SIZE (mode) / 2); + + return gen_rtx_REG (mode, GP_RETURN); } /* The implementation of FUNCTION_ARG_PASS_BY_REFERENCE. Return |

