rtlanal.c (struct subreg_info, [...]): New.

* 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.

From-SVN: r120076
This commit is contained in:
Joseph Myers 2006-12-20 16:25:00 +00:00 committed by Joseph Myers
parent ee8c1b05d5
commit f1f4e530a5
10 changed files with 213 additions and 110 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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. */

View File

@ -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

View File

@ -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++)

View File

@ -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);

View File

@ -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.
/* 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 - 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)
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;
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.
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)
{
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;