summaryrefslogtreecommitdiff
path: root/gcc/rtlanal.c
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2006-12-20 16:25:00 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2006-12-20 16:25:00 +0000
commitfe2ebfc850445a2622434cff7771bab38233fbd6 (patch)
treee5723b345a12a4d1072befdb9b246a6a0ddc5270 /gcc/rtlanal.c
parentf3c40e6dbeefd9efe87c6919805b669e3eb8b223 (diff)
downloadgcc-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.c215
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;