diff options
Diffstat (limited to 'gcc/rtlanal.c')
-rw-r--r-- | gcc/rtlanal.c | 116 |
1 files changed, 99 insertions, 17 deletions
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 94e8d4c8033..35e2b67f4d1 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3025,6 +3025,7 @@ subreg_lsb (rtx x) SUBREG_BYTE (x)); } +/* APPLE LOCAL begin assert failure 4087079 */ /* This function returns the regno offset of a subreg expression. xregno - A regno of an inner hard subreg_reg (or what will become one). xmode - The mode of xregno. @@ -3035,13 +3036,37 @@ unsigned int subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode; + int nregs_xmode, nregs_ymode, nregs_xmode_unit_int; int mode_multiple, nregs_multiple; int y_offset; + enum machine_mode xmode_unit, xmode_unit_int; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - nregs_xmode = hard_regno_nregs[xregno][xmode]; + if (GET_MODE_INNER (xmode) == VOIDmode) + xmode_unit = xmode; + else + xmode_unit = GET_MODE_INNER (xmode); + + if (FLOAT_MODE_P (xmode_unit)) + { + xmode_unit_int = int_mode_for_mode (xmode_unit); + if (xmode_unit_int == BLKmode) + /* It's probably bad to be here; a port should have an integer mode + that's the same size as anything of which it takes a SUBREG. */ + xmode_unit_int = xmode_unit; + } + else + xmode_unit_int = xmode_unit; + + nregs_xmode_unit_int = hard_regno_nregs[xregno][xmode_unit_int]; + + /* Adjust nregs_xmode to allow for 'holes'. */ + if (nregs_xmode_unit_int != hard_regno_nregs[xregno][xmode_unit]) + nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); + else + nregs_xmode = hard_regno_nregs[xregno][xmode]; + nregs_ymode = hard_regno_nregs[xregno][ymode]; /* If this is a big endian paradoxical subreg, which uses more actual @@ -3056,7 +3081,7 @@ subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, if (offset == 0 || nregs_xmode == nregs_ymode) return 0; - /* size of ymode must not be greater than the size of xmode. */ + /* Size of ymode must not be greater than the size of xmode. */ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); gcc_assert (mode_multiple != 0); @@ -3071,36 +3096,82 @@ subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, xmode - The mode of xregno. offset - The byte offset. ymode - The mode of a top level SUBREG (or what may become one). - RETURN - The regno offset which would be used. */ + RETURN - Whether the offset is representable. */ bool subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, unsigned int offset, enum machine_mode ymode) { - int nregs_xmode, nregs_ymode; + int nregs_xmode, nregs_ymode, nregs_xmode_unit, nregs_xmode_unit_int; int mode_multiple, nregs_multiple; int y_offset; + enum machine_mode xmode_unit, xmode_unit_int; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - nregs_xmode = hard_regno_nregs[xregno][xmode]; + if (GET_MODE_INNER (xmode) == VOIDmode) + xmode_unit = xmode; + else + xmode_unit = GET_MODE_INNER (xmode); + + if (FLOAT_MODE_P (xmode_unit)) + { + xmode_unit_int = int_mode_for_mode (xmode_unit); + if (xmode_unit_int == BLKmode) + /* It's probably bad to be here; a port should have an integer mode + that's the same size as anything of which it takes a SUBREG. */ + xmode_unit_int = xmode_unit; + } + else + xmode_unit_int = xmode_unit; + + nregs_xmode_unit = hard_regno_nregs[xregno][xmode_unit]; + nregs_xmode_unit_int = hard_regno_nregs[xregno][xmode_unit_int]; + + /* If there are holes in a non-scalar mode in registers, we expect + that it is made up of its units concatenated together. */ + if (nregs_xmode_unit != nregs_xmode_unit_int) + { + gcc_assert (nregs_xmode_unit * GET_MODE_NUNITS (xmode) + == hard_regno_nregs[xregno][xmode]); + + /* You can only ask for a SUBREG of a value with holes in the middle + if you don't cross the holes. (Such a SUBREG should be done by + picking a different register class, or doing it in memory if + necessary.) An example of a value with holes is XCmode on 32-bit + x86 with -m128bit-long-double; it's represented in 6 32-bit registers, + 3 for each part, but in memory it's two 128-bit parts. + Padding is assumed to be at the end (not necessarily the 'high part') + of each unit. */ + if (nregs_xmode_unit != nregs_xmode_unit_int + && (offset / GET_MODE_SIZE (xmode_unit_int) + 1 + < GET_MODE_NUNITS (xmode)) + && (offset / GET_MODE_SIZE (xmode_unit_int) + != ((offset + GET_MODE_SIZE (ymode) - 1) + / GET_MODE_SIZE (xmode_unit_int)))) + return false; + + nregs_xmode = nregs_xmode_unit_int * GET_MODE_NUNITS (xmode); + } + else + nregs_xmode = hard_regno_nregs[xregno][xmode]; + nregs_ymode = hard_regno_nregs[xregno][ymode]; - /* Paradoxical subregs are always valid. */ + /* Paradoxical subregs are otherwise valid. */ if (offset == 0 && nregs_ymode > nregs_xmode && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) return true; - /* Lowpart subregs are always valid. */ + /* Lowpart subregs are otherwise valid. */ if (offset == subreg_lowpart_offset (ymode, xmode)) return true; - /* This should always pass, otherwise we don't know how to verify the - constraint. These conditions may be relaxed but subreg_offset would - need to be redesigned. */ + /* This should always pass, otherwise we don't know how to verify + the constraint. These conditions may be relaxed but + subreg_regno_offset would need to be redesigned. */ gcc_assert ((GET_MODE_SIZE (xmode) % GET_MODE_SIZE (ymode)) == 0); - gcc_assert ((GET_MODE_SIZE (ymode) % nregs_ymode) == 0); gcc_assert ((nregs_xmode % nregs_ymode) == 0); /* The XMODE value can be seen as a vector of NREGS_XMODE @@ -3111,7 +3182,7 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, / nregs_xmode, MODE_INT, 0)); - /* size of ymode must not be greater than the size of xmode. */ + /* Size of ymode must not be greater than the size of xmode. */ mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); gcc_assert (mode_multiple != 0); @@ -3123,6 +3194,7 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, return (!(y_offset % (mode_multiple / nregs_multiple))); } +/* APPLE LOCAL end assert failure 4087079 */ /* Return the final regno that a subreg expression refers to. */ unsigned int @@ -3158,13 +3230,17 @@ parms_set (rtx x, rtx pat ATTRIBUTE_UNUSED, void *data) } } +/* APPLE LOCAL begin 4045984 */ /* Look backward for first parameter to be loaded. + Note that loads of all parameters will not necessarily be + found if CSE has eliminated some of them (e.g., an argument + to the outer function is passed down as a parameter). Do not skip BOUNDARY. */ rtx find_first_parameter_load (rtx call_insn, rtx boundary) { struct parms_set_data parm; - rtx p, before; + rtx p, before, first_set; /* Since different machines initialize their parameter registers in different orders, assume nothing. Collect the set of all @@ -3186,6 +3262,7 @@ find_first_parameter_load (rtx call_insn, rtx boundary) parm.nregs++; } before = call_insn; + first_set = call_insn; /* Search backward for the first set of a register in this set. */ while (parm.nregs && before != boundary) @@ -3208,11 +3285,16 @@ find_first_parameter_load (rtx call_insn, rtx boundary) } if (INSN_P (before)) - note_stores (PATTERN (before), parms_set, &parm); + { + int nregs_old = parm.nregs; + note_stores (PATTERN (before), parms_set, &parm); + if (nregs_old != parm.nregs) + first_set = before; + } } - return before; + return first_set; } - +/* APPLE LOCAL end 4045984 */ /* Return true if we should avoid inserting code between INSN and preceding call instruction. */ |