summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/caller-save.c22
-rw-r--r--gcc/df-scan.c15
-rw-r--r--gcc/doc/tm.texi2
-rw-r--r--gcc/flow.c3
-rw-r--r--gcc/postreload.c8
-rw-r--r--gcc/reload.c17
-rw-r--r--gcc/resource.c20
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/rtlanal.c215
10 files changed, 213 insertions, 110 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f991a4d066d..4f145939528 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2006-12-20 Joseph Myers <joseph@codesourcery.com>
+
+ * 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.
+
2006-12-20 Zdenek Dvorak <dvorakz@suse.cz>
* loop-unswitch.c (unswitch_loop): Update arguments of
diff --git a/gcc/caller-save.c b/gcc/caller-save.c
index c81c72c49b6..86d74ee1726 100644
--- a/gcc/caller-save.c
+++ b/gcc/caller-save.c
@@ -508,15 +508,17 @@ mark_set_regs (rtx reg, rtx setter ATTRIBUTE_UNUSED, void *data)
if (!REG_P (inner) || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
return;
regno = subreg_regno (reg);
+ endregno = regno + subreg_nregs (reg);
}
else if (REG_P (reg)
&& REGNO (reg) < FIRST_PSEUDO_REGISTER)
- regno = REGNO (reg);
+ {
+ regno = REGNO (reg);
+ endregno = regno + hard_regno_nregs[regno][mode];
+ }
else
return;
- endregno = regno + hard_regno_nregs[regno][mode];
-
for (i = regno; i < endregno; i++)
SET_HARD_REG_BIT (*this_insn_sets, i);
}
@@ -542,13 +544,17 @@ add_stored_regs (rtx reg, rtx setter, void *data)
SUBREG_BYTE (reg),
GET_MODE (reg));
reg = SUBREG_REG (reg);
+ regno = REGNO (reg) + offset;
+ endregno = regno + subreg_nregs (reg);
}
+ else
+ {
+ if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
+ return;
- if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
- return;
-
- regno = REGNO (reg) + offset;
- endregno = regno + hard_regno_nregs[regno][mode];
+ regno = REGNO (reg) + offset;
+ endregno = regno + hard_regno_nregs[regno][mode];
+ }
for (i = regno; i < endregno; i++)
SET_REGNO_REG_SET ((regset) data, i);
diff --git a/gcc/df-scan.c b/gcc/df-scan.c
index 46dfb072cce..fea786c0196 100644
--- a/gcc/df-scan.c
+++ b/gcc/df-scan.c
@@ -1083,15 +1083,14 @@ df_ref_record (struct dataflow *dflow, rtx reg, rtx *loc,
if (!(dflow->flags & DF_HARD_REGS))
return;
- /* GET_MODE (reg) is correct here. We do not want to go into a SUBREG
- for the mode, because we only want to add references to regs, which
- are really referenced. E.g., a (subreg:SI (reg:DI 0) 0) does _not_
- reference the whole reg 0 in DI mode (which would also include
- reg 1, at least, if 0 and 1 are SImode registers). */
- endregno = hard_regno_nregs[regno][GET_MODE (reg)];
if (GET_CODE (reg) == SUBREG)
- regno += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)),
- SUBREG_BYTE (reg), GET_MODE (reg));
+ {
+ regno += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)),
+ SUBREG_BYTE (reg), GET_MODE (reg));
+ endregno = subreg_nregs (reg);
+ }
+ else
+ endregno = hard_regno_nregs[regno][GET_MODE (reg)];
endregno += regno;
/* If this is a multiword hardreg, we create some extra datastructures that
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index f209593f0c9..0896ab8db17 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1991,7 +1991,7 @@ registers but takes up 128 bits in memory, then this would be
nonzero.
This macros only needs to be defined if there are cases where
-@code{subreg_regno_offset} and @code{subreg_offset_representable_p}
+@code{subreg_get_info}
would otherwise wrongly determine that a @code{subreg} can be
represented by an offset to the register number, when in fact such a
@code{subreg} would contain some of the padding not stored in
diff --git a/gcc/flow.c b/gcc/flow.c
index 2b5d3032bf7..1da935bda31 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -2791,8 +2791,7 @@ mark_set_1 (struct propagate_block_info *pbi, enum rtx_code code, rtx reg, rtx c
regno_first += subreg_regno_offset (regno_first, inner_mode,
SUBREG_BYTE (reg),
outer_mode);
- regno_last = (regno_first
- + hard_regno_nregs[regno_first][outer_mode] - 1);
+ regno_last = regno_first + subreg_nregs (reg) - 1;
/* Since we've just adjusted the register number ranges, make
sure REG matches. Otherwise some_was_live will be clear
diff --git a/gcc/postreload.c b/gcc/postreload.c
index 5f4ae4f5b18..d1e58ab944d 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -1429,6 +1429,7 @@ static void
move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
{
unsigned int regno = 0;
+ unsigned int nregs = 0;
unsigned int i;
enum machine_mode mode = GET_MODE (dst);
@@ -1438,6 +1439,7 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
GET_MODE (SUBREG_REG (dst)),
SUBREG_BYTE (dst),
GET_MODE (dst));
+ nregs = subreg_nregs (dst);
dst = SUBREG_REG (dst);
}
@@ -1455,9 +1457,11 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
return;
regno += REGNO (dst);
+ if (!nregs)
+ nregs = hard_regno_nregs[regno][mode];
if (SCALAR_INT_MODE_P (GET_MODE (dst))
- && hard_regno_nregs[regno][mode] == 1 && GET_CODE (set) == SET
+ && nregs == 1 && GET_CODE (set) == SET
&& GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
{
@@ -1557,7 +1561,7 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
}
else
{
- unsigned int endregno = regno + hard_regno_nregs[regno][mode];
+ unsigned int endregno = regno + nregs;
for (i = regno; i < endregno; i++)
/* Reset the information about this register. */
diff --git a/gcc/reload.c b/gcc/reload.c
index 1f1bc23020b..50af5d5e366 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -2414,7 +2414,7 @@ decompose (rtx x)
return decompose (SUBREG_REG (x));
else
/* A hard reg. */
- val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)];
+ val.end = val.start + subreg_nregs (x);
break;
case SCRATCH:
@@ -6381,7 +6381,7 @@ refers_to_regno_for_reload_p (unsigned int regno, unsigned int endregno,
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;
}
@@ -6479,6 +6479,10 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x),
GET_MODE (x));
+ endregno = regno + (regno < FIRST_PSEUDO_REGISTER
+ ? subreg_nregs (x) : 1);
+
+ return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
else if (REG_P (x))
{
@@ -6494,6 +6498,10 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
gcc_assert (reg_equiv_constant[regno]);
return 0;
}
+
+ endregno = regno + hard_regno_nregs[regno][GET_MODE (x)];
+
+ return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
}
else if (MEM_P (x))
return refers_to_mem_for_reload_p (in);
@@ -6520,10 +6528,7 @@ reg_overlap_mentioned_for_reload_p (rtx x, rtx in)
|| reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in));
}
- endregno = regno + (regno < FIRST_PSEUDO_REGISTER
- ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
-
- return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
+ gcc_unreachable ();
}
/* Return nonzero if anything in X contains a MEM. Look also for pseudo
diff --git a/gcc/resource.c b/gcc/resource.c
index cd4eb10628c..398db5c9c40 100644
--- a/gcc/resource.c
+++ b/gcc/resource.c
@@ -99,11 +99,17 @@ update_live_status (rtx dest, rtx x, void *data ATTRIBUTE_UNUSED)
return;
if (GET_CODE (dest) == SUBREG)
- first_regno = subreg_regno (dest);
- else
- first_regno = REGNO (dest);
+ {
+ first_regno = subreg_regno (dest);
+ last_regno = first_regno + subreg_nregs (dest);
- last_regno = first_regno + hard_regno_nregs[first_regno][GET_MODE (dest)];
+ }
+ else
+ {
+ first_regno = REGNO (dest);
+ last_regno
+ = first_regno + hard_regno_nregs[first_regno][GET_MODE (dest)];
+ }
if (GET_CODE (x) == CLOBBER)
for (i = first_regno; i < last_regno; i++)
@@ -229,8 +235,7 @@ mark_referenced_resources (rtx x, struct resources *res,
else
{
unsigned int regno = subreg_regno (x);
- unsigned int last_regno
- = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int last_regno = regno + subreg_nregs (x);
gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
for (r = regno; r < last_regno; r++)
@@ -763,8 +768,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
else
{
unsigned int regno = subreg_regno (x);
- unsigned int last_regno
- = regno + hard_regno_nregs[regno][GET_MODE (x)];
+ unsigned int last_regno = regno + subreg_nregs (x);
gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
for (r = regno; r < last_regno; r++)
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 54dad700087..16de3bbe4b0 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1041,6 +1041,7 @@ extern unsigned int subreg_regno_offset (unsigned int, enum machine_mode,
extern bool subreg_offset_representable_p (unsigned int, enum machine_mode,
unsigned int, enum machine_mode);
extern unsigned int subreg_regno (rtx);
+extern unsigned int subreg_nregs (rtx);
extern unsigned HOST_WIDE_INT nonzero_bits (rtx, enum machine_mode);
extern unsigned int num_sign_bit_copies (rtx, enum machine_mode);
extern bool constant_pool_constant_p (rtx);
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;