diff options
author | Geoffrey Keating <geoffk@apple.com> | 2005-06-07 08:18:15 +0000 |
---|---|---|
committer | Geoffrey Keating <geoffk@gcc.gnu.org> | 2005-06-07 08:18:15 +0000 |
commit | dd79bb7eb719382481a2750eb803acea044b867f (patch) | |
tree | e66ecc876326d432072b4f5ec6681ed9fe84bfde /gcc | |
parent | bd127a751553d5b4a97784a2e6d903415366bcdd (diff) | |
download | gcc-dd79bb7eb719382481a2750eb803acea044b867f.zip gcc-dd79bb7eb719382481a2750eb803acea044b867f.tar.gz gcc-dd79bb7eb719382481a2750eb803acea044b867f.tar.bz2 |
rtlanal.c (subreg_offset_representable_p): Handle objects with holes.
* rtlanal.c (subreg_offset_representable_p): Handle objects
with holes.
From-SVN: r100700
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/rtlanal.c | 96 |
2 files changed, 88 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a4ec6e7..c5d60e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2005-06-07 Geoffrey Keating <geoffk@apple.com> + + * rtlanal.c (subreg_offset_representable_p): Handle objects + with holes. + 2005-06-06 Uros Bizjak <uros@kss-loka.si> * mode-switching.c (optimize_mode_switching): Fix n_exprs parameter diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index da9774e..0bdcbba 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3033,13 +3033,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 @@ -3054,7 +3078,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); @@ -3069,36 +3093,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 @@ -3109,7 +3179,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); |