diff options
author | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-12-20 16:25:00 +0000 |
---|---|---|
committer | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2006-12-20 16:25:00 +0000 |
commit | fe2ebfc850445a2622434cff7771bab38233fbd6 (patch) | |
tree | e5723b345a12a4d1072befdb9b246a6a0ddc5270 /gcc/rtlanal.c | |
parent | f3c40e6dbeefd9efe87c6919805b669e3eb8b223 (diff) | |
download | gcc-fe2ebfc850445a2622434cff7771bab38233fbd6.tar.gz |
* rtlanal.c (struct subreg_info, subreg_get_info, subreg_nregs):
New.
(subreg_regno_offset, subreg_offset_representable_p): Change to
wrappers about subreg_get_info.
(refers_to_regno_p, reg_overlap_mentioned_p): Use subreg_nregs.
* rtl.h (subreg_nregs): Declare.
* doc/tm.texi (HARD_REGNO_NREGS_HAS_PADDING): Update to refer to
subreg_get_info.
* caller-save.c (mark_set_regs, add_stored_regs): Use
subreg_nregs.
* df-scan.c (df_ref_record): Use subreg_nregs.
* flow.c (mark_set_1): Use subreg_nregs.
* postreload.c (move2add_note_store): Use subreg_nregs.
* reload.c (decompose, refers_to_regno_for_reload_p,
reg_overlap_mentioned_for_reload_p): Use subreg_nregs.
* resource.c (update_live_status, mark_referenced_resources,
mark_set_resources): Use subreg_nregs.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@120076 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/rtlanal.c')
-rw-r--r-- | gcc/rtlanal.c | 215 |
1 files changed, 140 insertions, 75 deletions
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 4b965f8ca1c..c45a020709f 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -38,6 +38,18 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "regs.h" #include "function.h" +/* Information about a subreg of a hard register. */ +struct subreg_info +{ + /* Offset of first hard register involved in the subreg. */ + int offset; + /* Number of hard registers involved in the subreg. */ + int nregs; + /* Whether this subreg can be represented as a hard reg with the new + mode. */ + bool representable_p; +}; + /* Forward declarations */ static void set_of_1 (rtx, rtx, void *); static bool covers_regno_p (rtx, unsigned int); @@ -45,6 +57,9 @@ static bool covers_regno_no_parallel_p (rtx, unsigned int); static int rtx_referenced_p_1 (rtx *, void *); static int computed_jump_p_1 (rtx); static void parms_set (rtx, rtx, void *); +static void subreg_get_info (unsigned int, enum machine_mode, + unsigned int, enum machine_mode, + struct subreg_info *); static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode, rtx, enum machine_mode, @@ -1176,7 +1191,7 @@ refers_to_regno_p (unsigned int regno, unsigned int endregno, rtx x, unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER - ? hard_regno_nregs[inner_regno][GET_MODE (x)] : 1); + ? subreg_nregs (x) : 1); return endregno > inner_regno && regno < inner_endregno; } @@ -1266,13 +1281,15 @@ reg_overlap_mentioned_p (rtx x, rtx in) regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) regno = subreg_regno (x); + endregno = regno + (regno < FIRST_PSEUDO_REGISTER + ? subreg_nregs (x) : 1); goto do_reg; case REG: regno = REGNO (x); - do_reg: endregno = regno + (regno < FIRST_PSEUDO_REGISTER ? hard_regno_nregs[regno][GET_MODE (x)] : 1); + do_reg: return refers_to_regno_p (regno, endregno, in, (rtx*) 0); case MEM: @@ -2926,69 +2943,27 @@ subreg_lsb (rtx x) SUBREG_BYTE (x)); } -/* 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. - 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. */ -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 mode_multiple, nregs_multiple; - int y_offset; - - gcc_assert (xregno < FIRST_PSEUDO_REGISTER); - - /* Adjust nregs_xmode to allow for 'holes'. */ - if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) - nregs_xmode = HARD_REGNO_NREGS_WITH_PADDING (xregno, 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 - hard registers than the original register, we must return a negative - offset so that we find the proper highpart of the register. */ - if (offset == 0 - && nregs_ymode > nregs_xmode - && (GET_MODE_SIZE (ymode) > UNITS_PER_WORD - ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) - return nregs_xmode - nregs_ymode; - - if (offset == 0 || nregs_xmode == nregs_ymode) - return 0; - - /* 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); - - y_offset = offset / GET_MODE_SIZE (ymode); - nregs_multiple = nregs_xmode / nregs_ymode; - return (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; -} - -/* This function returns true when the offset is representable via - subreg_offset in the given regno. +/* Fill in information about a subreg of a hard register. xregno - A regno of an inner hard subreg_reg (or what will become one). xmode - The mode of xregno. offset - The byte offset. ymode - The mode of a top level SUBREG (or what may become one). - 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) + info - Pointer to structure to fill in. */ +static void +subreg_get_info (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode, + struct subreg_info *info) { int nregs_xmode, nregs_ymode; int mode_multiple, nregs_multiple; - int y_offset; + int offset_adj, y_offset, y_offset_adj; int regsize_xmode, regsize_ymode; + bool rknown; gcc_assert (xregno < FIRST_PSEUDO_REGISTER); + rknown = false; + /* If there are holes in a non-scalar mode in registers, we expect that it is made up of its units concatenated together. */ if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) @@ -3021,7 +2996,10 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, && (offset / GET_MODE_SIZE (xmode_unit) != ((offset + GET_MODE_SIZE (ymode) - 1) / GET_MODE_SIZE (xmode_unit)))) - return false; + { + info->representable_p = false; + rknown = true; + } } else nregs_xmode = hard_regno_nregs[xregno][xmode]; @@ -3029,24 +3007,57 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, nregs_ymode = hard_regno_nregs[xregno][ymode]; /* 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; + if (!rknown + && offset == 0 + && GET_MODE_SIZE (ymode) > GET_MODE_SIZE (xmode)) + { + info->representable_p = true; + /* If this is a big endian paradoxical subreg, which uses more + actual hard registers than the original register, we must + return a negative offset so that we find the proper highpart + of the register. */ + if (GET_MODE_SIZE (ymode) > UNITS_PER_WORD + ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN) + info->offset = nregs_xmode - nregs_ymode; + else + info->offset = 0; + info->nregs = nregs_ymode; + return; + } /* If registers store different numbers of bits in the different modes, we cannot generally form this subreg. */ - regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; - regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; - if (regsize_xmode > regsize_ymode && nregs_ymode > 1) - return false; - if (regsize_ymode > regsize_xmode && nregs_xmode > 1) - return false; + if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode) + && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode)) + { + regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; + gcc_assert (regsize_xmode * nregs_xmode == GET_MODE_SIZE (xmode)); + regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; + gcc_assert (regsize_ymode * nregs_ymode == GET_MODE_SIZE (ymode)); + if (!rknown && regsize_xmode > regsize_ymode && nregs_ymode > 1) + { + info->representable_p = false; + info->nregs + = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; + info->offset = offset / regsize_xmode; + return; + } + if (!rknown && regsize_ymode > regsize_xmode && nregs_xmode > 1) + { + info->representable_p = false; + info->nregs + = (GET_MODE_SIZE (ymode) + regsize_xmode - 1) / regsize_xmode; + info->offset = offset / regsize_xmode; + return; + } + } /* Lowpart subregs are otherwise valid. */ - if (offset == subreg_lowpart_offset (ymode, xmode)) - return true; + if (!rknown && offset == subreg_lowpart_offset (ymode, xmode)) + { + info->representable_p = true; + rknown = true; + } /* This should always pass, otherwise we don't know how to verify the constraint. These conditions may be relaxed but @@ -3057,22 +3068,61 @@ subreg_offset_representable_p (unsigned int xregno, enum machine_mode xmode, /* The XMODE value can be seen as a vector of NREGS_XMODE values. The subreg must represent a lowpart of given field. Compute what field it is. */ - offset -= subreg_lowpart_offset (ymode, - mode_for_size (GET_MODE_BITSIZE (xmode) - / nregs_xmode, - MODE_INT, 0)); + offset_adj = offset; + offset_adj -= subreg_lowpart_offset (ymode, + mode_for_size (GET_MODE_BITSIZE (xmode) + / nregs_xmode, + MODE_INT, 0)); /* 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); y_offset = offset / GET_MODE_SIZE (ymode); - nregs_multiple = nregs_xmode / nregs_ymode; + y_offset_adj = offset_adj / GET_MODE_SIZE (ymode); + nregs_multiple = nregs_xmode / nregs_ymode; - gcc_assert ((offset % GET_MODE_SIZE (ymode)) == 0); + gcc_assert ((offset_adj % GET_MODE_SIZE (ymode)) == 0); gcc_assert ((mode_multiple % nregs_multiple) == 0); - return (!(y_offset % (mode_multiple / nregs_multiple))); + if (!rknown) + { + info->representable_p = (!(y_offset_adj % (mode_multiple / nregs_multiple))); + rknown = true; + } + info->offset = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; + info->nregs = nregs_ymode; +} + +/* 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. + 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. */ +unsigned int +subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, + unsigned int offset, enum machine_mode ymode) +{ + struct subreg_info info; + subreg_get_info (xregno, xmode, offset, ymode, &info); + return info.offset; +} + +/* This function returns true when the offset is representable via + subreg_offset in the given regno. + xregno - A regno of an inner hard subreg_reg (or what will become one). + xmode - The mode of xregno. + offset - The byte offset. + ymode - The mode of a top level SUBREG (or what may become one). + 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) +{ + struct subreg_info info; + subreg_get_info (xregno, xmode, offset, ymode, &info); + return info.representable_p; } /* Return the final regno that a subreg expression refers to. */ @@ -3090,6 +3140,21 @@ subreg_regno (rtx x) return ret; } + +/* Return the number of registers that a subreg expression refers + to. */ +unsigned int +subreg_nregs (rtx x) +{ + struct subreg_info info; + rtx subreg = SUBREG_REG (x); + int regno = REGNO (subreg); + + subreg_get_info (regno, GET_MODE (subreg), SUBREG_BYTE (x), GET_MODE (x), + &info); + return info.nregs; +} + struct parms_set_data { int nregs; |