diff options
author | Dale Johannesen <dalej@apple.com> | 2005-03-01 02:56:35 +0000 |
---|---|---|
committer | Stan Shebs <shebs@gcc.gnu.org> | 2005-03-01 02:56:35 +0000 |
commit | 0b5383eba096fa2bec2d62242ea0f1bc5350ebc3 (patch) | |
tree | 46b25cc4e0cf6fdd8d58b935495c31cf0e99bfff /gcc | |
parent | 1a9dddada346b812bafc8918d082c993c7f0a82d (diff) | |
download | gcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.zip gcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.tar.gz gcc-0b5383eba096fa2bec2d62242ea0f1bc5350ebc3.tar.bz2 |
Rewrite of 64-bit Darwin structure-by-value pass/return.
2005-02-28 Dale Johannesen <dalej@apple.com>
Stan Shebs <shebs@apple.com>
Rewrite of 64-bit Darwin structure-by-value pass/return.
* config/rs6000/rs6000.h (CUMULATIVE_ARGS): New fields
intoffset, use_stack, named.
* config/rs6000/rs6000.c (rs6000_darwin64_function_arg): Remove.
(rs6000_darwin64_record_arg_advance_flush): New.
(rs6000_darwin64_record_arg_advance_recurse): New.
(rs6000_darwin64_record_arg_flush): New.
(rs6000_darwin64_record_arg_recurse): New.
(rs6000_darwin64_record_arg): New.
(rs6000_return_in_memory): Remove AGGREGATE_TYPE_P check.
(function_arg_boundary): Handle 128-bit aligned structs.
(function_arg_advance): Rewrite darwin64 struct handling.
(function_arg): Call rs6000_darwin64_record_arg.
(function_arg_partial_nregs): Handle darwin64 structs.
(rs6000_darwin64_function_value): Remove.
(rs6000_function_value): Call rs6000_darwin64_record_arg.
Co-Authored-By: Stan Shebs <shebs@apple.com>
From-SVN: r95723
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 20 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 603 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 3 |
3 files changed, 332 insertions, 294 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7eed832..18a3070 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2005-02-28 Dale Johannesen <dalej@apple.com> + Stan Shebs <shebs@apple.com> + + Rewrite of 64-bit Darwin structure-by-value pass/return. + * config/rs6000/rs6000.h (CUMULATIVE_ARGS): New fields + intoffset, use_stack, named. + * config/rs6000/rs6000.c (rs6000_darwin64_function_arg): Remove. + (rs6000_darwin64_record_arg_advance_flush): New. + (rs6000_darwin64_record_arg_advance_recurse): New. + (rs6000_darwin64_record_arg_flush): New. + (rs6000_darwin64_record_arg_recurse): New. + (rs6000_darwin64_record_arg): New. + (rs6000_return_in_memory): Remove AGGREGATE_TYPE_P check. + (function_arg_boundary): Handle 128-bit aligned structs. + (function_arg_advance): Rewrite darwin64 struct handling. + (function_arg): Call rs6000_darwin64_record_arg. + (function_arg_partial_nregs): Handle darwin64 structs. + (rs6000_darwin64_function_value): Remove. + (rs6000_function_value): Call rs6000_darwin64_record_arg. + 2005-02-28 Roger Sayle <roger@eyesopen.com> PR tree-optimization/20216 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index f0b7c18..ff6d09d 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -737,8 +737,17 @@ static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *); static rtx rs6000_complex_function_value (enum machine_mode); static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree); -static rtx rs6000_darwin64_function_arg (CUMULATIVE_ARGS *, - enum machine_mode, tree, int); +static void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *, + HOST_WIDE_INT); +static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *, + tree, HOST_WIDE_INT); +static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *, + HOST_WIDE_INT, + rtx[], int *); +static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *, + tree, HOST_WIDE_INT, + rtx[], int *); +static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool); static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int); static void rs6000_move_block_from_reg (int regno, rtx x, int nregs); static void setup_incoming_varargs (CUMULATIVE_ARGS *, @@ -3833,12 +3842,23 @@ rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) { /* In the darwin64 abi, try to use registers for larger structs if possible. */ - if (AGGREGATE_TYPE_P (type) - && rs6000_darwin64_abi + if (rs6000_darwin64_abi && TREE_CODE (type) == RECORD_TYPE - && ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) <= 32) - && ((unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 0)) - return false; + && int_size_in_bytes (type) > 0) + { + CUMULATIVE_ARGS valcum; + rtx valret; + + valcum.words = 0; + valcum.fregno = FP_ARG_MIN_REG; + valcum.vregno = ALTIVEC_ARG_MIN_REG; + /* Do a trial code generation as if this were going to be passed + as an argument; if any part goes in memory, we return NULL. */ + valret = rs6000_darwin64_record_arg (&valcum, type, 1, true); + if (valret) + return false; + /* Otherwise fall through to more conventional ABI rules. */ + } if (AGGREGATE_TYPE_P (type) && (TARGET_AIX_STRUCT_RET @@ -4029,6 +4049,9 @@ function_arg_boundary (enum machine_mode mode, tree type) || (type && TREE_CODE (type) == VECTOR_TYPE && int_size_in_bytes (type) >= 16)) return 128; + else if (rs6000_darwin64_abi && mode == BLKmode + && type && TYPE_ALIGN (type) > 64) + return 128; else return PARM_BOUNDARY; } @@ -4051,46 +4074,84 @@ rs6000_arg_size (enum machine_mode mode, tree type) return (size + 7) >> 3; } -/* The darwin64 ABI calls for us to recurse down through structs, - applying the same rules to struct elements as if a reference to - each were being passed directly. */ +/* Use this to flush pending int fields. */ static void -darwin64_function_arg_advance (CUMULATIVE_ARGS *cum, tree type, - int named, int depth) +rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum, + HOST_WIDE_INT bitpos) { - tree f, ftype; - int i, tot; + unsigned int startbit, endbit; + int intregs, intoffset; + enum machine_mode mode; - switch (TREE_CODE (type)) - { - case RECORD_TYPE: - for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) - if (TREE_CODE (f) == FIELD_DECL) - { - ftype = TREE_TYPE (f); - function_arg_advance (cum, TYPE_MODE (ftype), ftype, - named, depth + 1); - } - break; + if (cum->intoffset == -1) + return; - case ARRAY_TYPE: - tot = int_size_in_bytes (type); - if (tot <= 0) - return; - ftype = TREE_TYPE (type); - tot /= int_size_in_bytes (ftype); - - for (i = 0; i < tot; ++i) + intoffset = cum->intoffset; + cum->intoffset = -1; + + if (intoffset % BITS_PER_WORD != 0) + { + mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD, + MODE_INT, 0); + if (mode == BLKmode) { - function_arg_advance (cum, TYPE_MODE (ftype), ftype, - named, depth + 1); + /* We couldn't find an appropriate mode, which happens, + e.g., in packed structs when there are 3 bytes to load. + Back intoffset back to the beginning of the word in this + case. */ + intoffset = intoffset & -BITS_PER_WORD; } - break; - - default: - abort (); } + + startbit = intoffset & -BITS_PER_WORD; + endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD; + intregs = (endbit - startbit) / BITS_PER_WORD; + cum->words += intregs; +} + +/* The darwin64 ABI calls for us to recurse down through structs, + looking for elements passed in registers. Unfortunately, we have + to track int register count here also because of misalignments + in powerpc alignment mode. */ + +static void +rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum, + tree type, + HOST_WIDE_INT startbitpos) +{ + tree f; + + for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + HOST_WIDE_INT bitpos = startbitpos; + tree ftype = TREE_TYPE (f); + enum machine_mode mode = TYPE_MODE (ftype); + + if (DECL_SIZE (f) != 0 + && host_integerp (bit_position (f), 1)) + bitpos += int_bit_position (f); + + /* ??? FIXME: else assume zero offset. */ + + if (TREE_CODE (ftype) == RECORD_TYPE) + rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos); + else if (USE_FP_FOR_ARG_P (cum, mode, ftype)) + { + rs6000_darwin64_record_arg_advance_flush (cum, bitpos); + cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3; + cum->words += (GET_MODE_SIZE (mode) + 7) >> 3; + } + else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1)) + { + rs6000_darwin64_record_arg_advance_flush (cum, bitpos); + cum->vregno++; + cum->words += 2; + } + else if (cum->intoffset == -1) + cum->intoffset = bitpos; + } } /* Update the data in CUM to advance over an argument @@ -4105,6 +4166,8 @@ void function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, int named, int depth) { + int size; + /* Only tick off an argument if we're not recursing. */ if (depth == 0) cum->nargs_prototype--; @@ -4168,10 +4231,30 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, else if (rs6000_darwin64_abi && mode == BLKmode - && (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == ARRAY_TYPE)) - darwin64_function_arg_advance (cum, type, named, depth); - + && TREE_CODE (type) == RECORD_TYPE + && (size = int_size_in_bytes (type)) > 0) + { + /* Variable sized types have size == -1 and are + treated as if consisting entirely of ints. + Pad to 16 byte boundary if needed. */ + if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD + && (cum->words % 2) != 0) + cum->words++; + /* For varargs, we can just go up by the size of the struct. */ + if (!named) + cum->words += (size + 7) / 8; + else + { + /* It is tempting to say int register count just goes up by + sizeof(type)/8, but this is wrong in a case such as + { int; double; int; } [powerpc alignment]. We have to + grovel through the fields for these too. */ + cum->intoffset = 0; + rs6000_darwin64_record_arg_advance_recurse (cum, type, 0); + rs6000_darwin64_record_arg_advance_flush (cum, + size * BITS_PER_UNIT); + } + } else if (DEFAULT_ABI == ABI_V4) { if (TARGET_HARD_FLOAT && TARGET_FPRS @@ -4330,136 +4413,184 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, } } -/* For the darwin64 ABI, we want to construct a PARALLEL consisting of - the register(s) to be used for each field and subfield of a struct - being passed by value, along with the offset of where the - register's value may be found in the block. */ +/* A subroutine of rs6000_darwin64_record_arg. Assign the bits of the + structure between cum->intoffset and bitpos to integer registers. */ -static rtx -rs6000_darwin64_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, - tree type, int named) +static void +rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum, + HOST_WIDE_INT bitpos, rtx rvec[], int *k) { - tree f, ftype, offset; - rtx rvec[FIRST_PSEUDO_REGISTER], sub, suboff, roffset; - int k = 0, i, j, bytepos, subbytepos, tot; - CUMULATIVE_ARGS saved_cum = *cum; - enum machine_mode submode; + enum machine_mode mode; + unsigned int regno; + unsigned int startbit, endbit; + int this_regno, intregs, intoffset; + rtx reg; - switch (TREE_CODE (type)) + if (cum->intoffset == -1) + return; + + intoffset = cum->intoffset; + cum->intoffset = -1; + + /* If this is the trailing part of a word, try to only load that + much into the register. Otherwise load the whole register. Note + that in the latter case we may pick up unwanted bits. It's not a + problem at the moment but may wish to revisit. */ + + if (intoffset % BITS_PER_WORD != 0) { - case RECORD_TYPE: - for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) - if (TREE_CODE (f) == FIELD_DECL) + mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD, + MODE_INT, 0); + if (mode == BLKmode) + { + /* We couldn't find an appropriate mode, which happens, + e.g., in packed structs when there are 3 bytes to load. + Back intoffset back to the beginning of the word in this + case. */ + intoffset = intoffset & -BITS_PER_WORD; + mode = word_mode; + } + } + else + mode = word_mode; + + startbit = intoffset & -BITS_PER_WORD; + endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD; + intregs = (endbit - startbit) / BITS_PER_WORD; + this_regno = cum->words + intoffset / BITS_PER_WORD; + + if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno) + cum->use_stack = 1; + + intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno); + if (intregs <= 0) + return; + + intoffset /= BITS_PER_UNIT; + do + { + regno = GP_ARG_MIN_REG + this_regno; + reg = gen_rtx_REG (mode, regno); + rvec[(*k)++] = + gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset)); + + this_regno += 1; + intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1; + mode = word_mode; + intregs -= 1; + } + while (intregs > 0); +} + +/* Recursive workhorse for the following. */ + +static void +rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type, + HOST_WIDE_INT startbitpos, rtx rvec[], + int *k) +{ + tree f; + + for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f)) + if (TREE_CODE (f) == FIELD_DECL) + { + HOST_WIDE_INT bitpos = startbitpos; + tree ftype = TREE_TYPE (f); + enum machine_mode mode = TYPE_MODE (ftype); + + if (DECL_SIZE (f) != 0 + && host_integerp (bit_position (f), 1)) + bitpos += int_bit_position (f); + + /* ??? FIXME: else assume zero offset. */ + + if (TREE_CODE (ftype) == RECORD_TYPE) + rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k); + else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype)) { - ftype = TREE_TYPE (f); - offset = DECL_FIELD_OFFSET (f); - bytepos = int_bit_position (f) / BITS_PER_UNIT; - /* Force substructs to be handled as BLKmode even if - they're small enough to be recorded as DImode, so we - drill through to non-record fields. */ - submode = TYPE_MODE (ftype); - if (TREE_CODE (ftype) == RECORD_TYPE) - submode = BLKmode; - sub = function_arg (cum, submode, ftype, named); - if (sub == NULL_RTX) - return NULL_RTX; - if (GET_CODE (sub) == PARALLEL) - { - for (i = 0; i < XVECLEN (sub, 0); i++) - { - rtx subsub = XVECEXP (sub, 0, i); - suboff = XEXP (subsub, 1); - subbytepos = INTVAL (suboff); - subbytepos += bytepos; - roffset = gen_rtx_CONST_INT (SImode, subbytepos); - subsub = XEXP (subsub, 0); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset); - } - } - else +#if 0 + switch (mode) { - roffset = gen_rtx_CONST_INT (SImode, bytepos); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset); + case SCmode: mode = SFmode; break; + case DCmode: mode = DFmode; break; + case TCmode: mode = TFmode; break; + default: break; } - /* Now do an arg advance to get all the cumulative arg - stuff set correctly for the next subfield. Note that it - has no lasting effect, because it is being done on a - temporary copy of the cumulative arg data. */ - function_arg_advance (cum, submode, ftype, named, 1); +#endif + rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k); + rvec[(*k)++] + = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (mode, cum->fregno++), + GEN_INT (bitpos / BITS_PER_UNIT)); + if (mode == TFmode) + cum->fregno++; } - break; + else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1)) + { + rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k); + rvec[(*k)++] + = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (mode, cum->vregno++), + GEN_INT (bitpos / BITS_PER_UNIT)); + } + else if (cum->intoffset == -1) + cum->intoffset = bitpos; + } +} - case UNION_TYPE: - tot = rs6000_arg_size (mode, type); - if (tot <= 0) - return NULL_RTX; - bytepos = 0; +/* For the darwin64 ABI, we want to construct a PARALLEL consisting of + the register(s) to be used for each field and subfield of a struct + being passed by value, along with the offset of where the + register's value may be found in the block. FP fields go in FP + register, vector fields go in vector registers, and everything + else goes in int registers, packed as in memory. - for (j = 0; j < tot; ++j) - { - sub = gen_rtx_REG ((TARGET_64BIT ? DImode : SImode), GP_ARG_MIN_REG + cum->words++); - roffset = gen_rtx_CONST_INT (SImode, bytepos); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset); - if (cum->words >= GP_ARG_NUM_REG) - break; - bytepos += (TARGET_64BIT ? 8 : 4); - } - break; + This code is also used for function return values. RETVAL indicates + whether this is the case. - case ARRAY_TYPE: - tot = int_size_in_bytes (type); - if (tot <= 0) - return NULL_RTX; - ftype = TREE_TYPE (type); - tot /= int_size_in_bytes (ftype); - bytepos = 0; + Much of this is taken from the Sparc V9 port, which has a similar + calling convention. */ - for (j = 0; j < tot; ++j) - { - /* Force substructs to be handled as BLKmode even if - they're small enough to be recorded as DImode, so we - drill through to non-record fields. */ - submode = TYPE_MODE (ftype); - if (TREE_CODE (ftype) == RECORD_TYPE) - submode = BLKmode; - sub = function_arg (cum, submode, ftype, named); - if (sub == NULL_RTX) - return NULL_RTX; - if (GET_CODE (sub) == PARALLEL) - { - for (i = 0; i < XVECLEN (sub, 0); i++) - { - rtx subsub = XVECEXP (sub, 0, i); - - suboff = XEXP (subsub, 1); - subbytepos = INTVAL (suboff); - subbytepos += bytepos; - roffset = gen_rtx_CONST_INT (SImode, subbytepos); - subsub = XEXP (subsub, 0); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset); - } - } - else - { - roffset = gen_rtx_CONST_INT (SImode, bytepos); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset); - } - /* Now do an arg advance to get all the cumulative arg - stuff set correctly for the next subfield. Note that it - has no lasting effect, because it is being done on a - temporary copy of the cumulative arg data. */ - function_arg_advance (cum, submode, ftype, named, 1); - bytepos += int_size_in_bytes (ftype); - } - break; - - default: - abort (); - } - - *cum = saved_cum; - if (k > 0) - return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec)); +static rtx +rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type, + int named, bool retval) +{ + rtx rvec[FIRST_PSEUDO_REGISTER]; + int k = 1, kbase = 1; + HOST_WIDE_INT typesize = int_size_in_bytes (type); + /* This is a copy; modifications are not visible to our caller. */ + CUMULATIVE_ARGS copy_cum = *orig_cum; + CUMULATIVE_ARGS *cum = ©_cum; + + /* Pad to 16 byte boundary if needed. */ + if (!retval && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD + && (cum->words % 2) != 0) + cum->words++; + + cum->intoffset = 0; + cum->use_stack = 0; + cum->named = named; + + /* Put entries into rvec[] for individual FP and vector fields, and + for the chunks of memory that go in int regs. Note we start at + element 1; 0 is reserved for an indication of using memory, and + may or may not be filled in below. */ + rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k); + rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k); + + /* If any part of the struct went on the stack put all of it there. + This hack is because the generic code for + FUNCTION_ARG_PARTIAL_NREGS cannot handle cases where the register + parts of the struct are not at the beginning. */ + if (cum->use_stack) + { + if (retval) + return NULL_RTX; /* doesn't go in registers at all */ + kbase = 0; + rvec[0] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx); + } + if (k > 1 || cum->use_stack) + return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k - kbase, &rvec[kbase])); else return NULL_RTX; } @@ -4523,7 +4654,8 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words) This is null for libcalls where that information may not be available. CUM is a variable of type CUMULATIVE_ARGS which gives info about - the preceding args and about the function being called. + the preceding args and about the function being called. It is + not modified in this routine. NAMED is nonzero if this argument is a named parameter (otherwise it is an extra parameter matching an ellipsis). @@ -4571,13 +4703,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, return GEN_INT (cum->call_cookie); } - if (mode == BLKmode - && rs6000_darwin64_abi - && (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == ARRAY_TYPE)) + if (rs6000_darwin64_abi && mode == BLKmode + && TREE_CODE (type) == RECORD_TYPE) { - rtx rslt = rs6000_darwin64_function_arg (cum, mode, type, named); + rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false); if (rslt != NULL_RTX) return rslt; /* Else fall through to usual handling. */ @@ -4818,6 +4947,12 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, && cum->nargs_prototype >= 0) return 0; + /* In this complicated case we just disable the partial_nregs code. */ + if (rs6000_darwin64_abi && mode == BLKmode + && TREE_CODE (type) == RECORD_TYPE + && int_size_in_bytes (type) > 0) + return 0; + align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1; parm_offset = TARGET_32BIT ? 2 : 0; align_words = cum->words + ((parm_offset - cum->words) & align); @@ -17147,128 +17282,6 @@ rs6000_complex_function_value (enum machine_mode mode) return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2)); } -/* Compose a PARALLEL for a darwin64 struct being returned by - value. */ - -static rtx -rs6000_darwin64_function_value (CUMULATIVE_ARGS *cum, tree valtype) -{ - tree f, ftype; - rtx rvec[FIRST_PSEUDO_REGISTER], sub, roffset, suboff; - int k = 0, bytepos, tot, elt, i, subbytepos; - enum machine_mode fmode; - - switch (TREE_CODE (valtype)) - { - case RECORD_TYPE: - for (f = TYPE_FIELDS (valtype); f ; f = TREE_CHAIN (f)) - if (TREE_CODE (f) == FIELD_DECL) - { - ftype = TREE_TYPE (f); - fmode = TYPE_MODE (ftype); - bytepos = int_bit_position (f) / BITS_PER_UNIT; - if (USE_FP_FOR_ARG_P (cum, fmode, ftype)) - { - sub = gen_rtx_REG (fmode, cum->fregno++); - cum->sysv_gregno++; - } - else if (USE_ALTIVEC_FOR_ARG_P (cum, fmode, ftype, 1)) - { - sub = gen_rtx_REG (fmode, cum->vregno++); - cum->sysv_gregno++; - } - else if (fmode == BLKmode - && (TREE_CODE (ftype) == RECORD_TYPE - || TREE_CODE (ftype) == ARRAY_TYPE)) - sub = rs6000_darwin64_function_value (cum, ftype); - else - sub = gen_rtx_REG (fmode, cum->sysv_gregno++); - if (sub == NULL_RTX) - return sub; - else if (GET_CODE (sub) == PARALLEL) - { - for (i = 0; i < XVECLEN (sub, 0); i++) - { - rtx subsub = XVECEXP (sub, 0, i); - - suboff = XEXP (subsub, 1); - subbytepos = INTVAL (suboff); - subbytepos += bytepos; - roffset = gen_rtx_CONST_INT (SImode, subbytepos); - subsub = XEXP (subsub, 0); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset); - } - } - else - { - roffset = gen_rtx_CONST_INT (SImode, bytepos); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset); - } - } - if (k > 0) - return gen_rtx_PARALLEL (TYPE_MODE (valtype), gen_rtvec_v (k, rvec)); - else - return NULL_RTX; - - case ARRAY_TYPE: - /* If passing by value won't work, give up. */ - if (int_size_in_bytes (valtype) <= 0) - return NULL_RTX; - ftype = TREE_TYPE (valtype); - fmode = TYPE_MODE (ftype); - tot = int_size_in_bytes (valtype) / int_size_in_bytes (ftype); - bytepos = 0; - for (elt = 0; elt < tot; ++elt) - { - if (USE_FP_FOR_ARG_P (cum, fmode, ftype)) - { - sub = gen_rtx_REG (fmode, cum->fregno++); - cum->sysv_gregno++; - } - else if (USE_ALTIVEC_FOR_ARG_P (cum, fmode, ftype, 1)) - { - sub = gen_rtx_REG (fmode, cum->vregno++); - cum->sysv_gregno++; - } - else if (fmode == BLKmode - && (TREE_CODE (ftype) == RECORD_TYPE - || TREE_CODE (ftype) == ARRAY_TYPE)) - sub = rs6000_darwin64_function_value (cum, ftype); - else - sub = gen_rtx_REG (fmode, cum->sysv_gregno++); - if (sub == NULL_RTX) - return sub; - else if (GET_CODE (sub) == PARALLEL) - { - for (i = 0; i < XVECLEN (sub, 0); i++) - { - rtx subsub = XVECEXP (sub, 0, i); - - suboff = XEXP (subsub, 1); - subbytepos = INTVAL (suboff); - subbytepos += bytepos; - roffset = gen_rtx_CONST_INT (SImode, subbytepos); - subsub = XEXP (subsub, 0); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, subsub, roffset); - } - } - else - { - roffset = gen_rtx_CONST_INT (SImode, bytepos); - rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, sub, roffset); - } - bytepos += int_size_in_bytes (ftype); - } - if (k > 0) - return gen_rtx_PARALLEL (TYPE_MODE (valtype), gen_rtvec_v (k, rvec)); - else - return NULL_RTX; - - default: - abort (); - } -} - /* 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; @@ -17288,16 +17301,18 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED) /* Special handling for structs in darwin64. */ if (rs6000_darwin64_abi && TYPE_MODE (valtype) == BLKmode - && (TREE_CODE (valtype) == RECORD_TYPE - || TREE_CODE (valtype) == ARRAY_TYPE)) + && TREE_CODE (valtype) == RECORD_TYPE + && int_size_in_bytes (valtype) > 0) { CUMULATIVE_ARGS valcum; rtx valret; - valcum.sysv_gregno = GP_ARG_RETURN; + valcum.words = 0; valcum.fregno = FP_ARG_MIN_REG; valcum.vregno = ALTIVEC_ARG_MIN_REG; - valret = rs6000_darwin64_function_value (&valcum, valtype); + /* Do a trial code generation as if this were going to be passed as + an argument; if any part goes in memory, we return NULL. */ + valret = rs6000_darwin64_record_arg (&valcum, valtype, 1, true); if (valret) return valret; /* Otherwise fall through to standard ABI rules. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 9b8f1fd..d9c2e8e 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1700,6 +1700,9 @@ typedef struct rs6000_args int stdarg; /* Whether function is a stdarg function. */ int call_cookie; /* Do special things for this call */ int sysv_gregno; /* next available GP register */ + int intoffset; /* running offset in struct (darwin64) */ + int use_stack; /* any part of struct on stack (darwin64) */ + int named; /* false for varargs params */ } CUMULATIVE_ARGS; /* Initialize a variable CUM of type CUMULATIVE_ARGS |