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> 2006-12-20 Zdenek Dvorak <dvorakz@suse.cz>
* loop-unswitch.c (unswitch_loop): Update arguments of * 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) if (!REG_P (inner) || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
return; return;
regno = subreg_regno (reg); regno = subreg_regno (reg);
endregno = regno + subreg_nregs (reg);
} }
else if (REG_P (reg) else if (REG_P (reg)
&& REGNO (reg) < FIRST_PSEUDO_REGISTER) && REGNO (reg) < FIRST_PSEUDO_REGISTER)
regno = REGNO (reg); {
regno = REGNO (reg);
endregno = regno + hard_regno_nregs[regno][mode];
}
else else
return; return;
endregno = regno + hard_regno_nregs[regno][mode];
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
SET_HARD_REG_BIT (*this_insn_sets, 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), SUBREG_BYTE (reg),
GET_MODE (reg)); GET_MODE (reg));
reg = SUBREG_REG (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) regno = REGNO (reg) + offset;
return; endregno = regno + hard_regno_nregs[regno][mode];
}
regno = REGNO (reg) + offset;
endregno = regno + hard_regno_nregs[regno][mode];
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
SET_REGNO_REG_SET ((regset) data, 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)) if (!(dflow->flags & DF_HARD_REGS))
return; 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) 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; endregno += regno;
/* If this is a multiword hardreg, we create some extra datastructures that /* 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. nonzero.
This macros only needs to be defined if there are cases where 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 would otherwise wrongly determine that a @code{subreg} can be
represented by an offset to the register number, when in fact such a represented by an offset to the register number, when in fact such a
@code{subreg} would contain some of the padding not stored in @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, regno_first += subreg_regno_offset (regno_first, inner_mode,
SUBREG_BYTE (reg), SUBREG_BYTE (reg),
outer_mode); outer_mode);
regno_last = (regno_first regno_last = regno_first + subreg_nregs (reg) - 1;
+ hard_regno_nregs[regno_first][outer_mode] - 1);
/* Since we've just adjusted the register number ranges, make /* Since we've just adjusted the register number ranges, make
sure REG matches. Otherwise some_was_live will be clear 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) move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
{ {
unsigned int regno = 0; unsigned int regno = 0;
unsigned int nregs = 0;
unsigned int i; unsigned int i;
enum machine_mode mode = GET_MODE (dst); 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)), GET_MODE (SUBREG_REG (dst)),
SUBREG_BYTE (dst), SUBREG_BYTE (dst),
GET_MODE (dst)); GET_MODE (dst));
nregs = subreg_nregs (dst);
dst = SUBREG_REG (dst); dst = SUBREG_REG (dst);
} }
@ -1455,9 +1457,11 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
return; return;
regno += REGNO (dst); regno += REGNO (dst);
if (!nregs)
nregs = hard_regno_nregs[regno][mode];
if (SCALAR_INT_MODE_P (GET_MODE (dst)) 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)) != ZERO_EXTRACT
&& GET_CODE (SET_DEST (set)) != STRICT_LOW_PART) && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
{ {
@ -1557,7 +1561,7 @@ move2add_note_store (rtx dst, rtx set, void *data ATTRIBUTE_UNUSED)
} }
else else
{ {
unsigned int endregno = regno + hard_regno_nregs[regno][mode]; unsigned int endregno = regno + nregs;
for (i = regno; i < endregno; i++) for (i = regno; i < endregno; i++)
/* Reset the information about this register. */ /* Reset the information about this register. */

View File

@ -2414,7 +2414,7 @@ decompose (rtx x)
return decompose (SUBREG_REG (x)); return decompose (SUBREG_REG (x));
else else
/* A hard reg. */ /* A hard reg. */
val.end = val.start + hard_regno_nregs[val.start][GET_MODE (x)]; val.end = val.start + subreg_nregs (x);
break; break;
case SCRATCH: 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_regno = subreg_regno (x);
unsigned int inner_endregno unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER = 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; 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)), GET_MODE (SUBREG_REG (x)),
SUBREG_BYTE (x), SUBREG_BYTE (x),
GET_MODE (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)) 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]); gcc_assert (reg_equiv_constant[regno]);
return 0; 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)) else if (MEM_P (x))
return refers_to_mem_for_reload_p (in); 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)); || reg_overlap_mentioned_for_reload_p (XEXP (x, 1), in));
} }
endregno = regno + (regno < FIRST_PSEUDO_REGISTER gcc_unreachable ();
? hard_regno_nregs[regno][GET_MODE (x)] : 1);
return refers_to_regno_for_reload_p (regno, endregno, in, (rtx*) 0);
} }
/* Return nonzero if anything in X contains a MEM. Look also for pseudo /* 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; return;
if (GET_CODE (dest) == SUBREG) if (GET_CODE (dest) == SUBREG)
first_regno = subreg_regno (dest); {
else first_regno = subreg_regno (dest);
first_regno = 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) if (GET_CODE (x) == CLOBBER)
for (i = first_regno; i < last_regno; i++) for (i = first_regno; i < last_regno; i++)
@ -229,8 +235,7 @@ mark_referenced_resources (rtx x, struct resources *res,
else else
{ {
unsigned int regno = subreg_regno (x); unsigned int regno = subreg_regno (x);
unsigned int last_regno unsigned int last_regno = regno + subreg_nregs (x);
= regno + hard_regno_nregs[regno][GET_MODE (x)];
gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
for (r = regno; r < last_regno; r++) for (r = regno; r < last_regno; r++)
@ -763,8 +768,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest,
else else
{ {
unsigned int regno = subreg_regno (x); unsigned int regno = subreg_regno (x);
unsigned int last_regno unsigned int last_regno = regno + subreg_nregs (x);
= regno + hard_regno_nregs[regno][GET_MODE (x)];
gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER); gcc_assert (last_regno <= FIRST_PSEUDO_REGISTER);
for (r = regno; r < last_regno; r++) 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, extern bool subreg_offset_representable_p (unsigned int, enum machine_mode,
unsigned int, enum machine_mode); unsigned int, enum machine_mode);
extern unsigned int subreg_regno (rtx); 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 HOST_WIDE_INT nonzero_bits (rtx, enum machine_mode);
extern unsigned int num_sign_bit_copies (rtx, enum machine_mode); extern unsigned int num_sign_bit_copies (rtx, enum machine_mode);
extern bool constant_pool_constant_p (rtx); 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 "regs.h"
#include "function.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 */ /* Forward declarations */
static void set_of_1 (rtx, rtx, void *); static void set_of_1 (rtx, rtx, void *);
static bool covers_regno_p (rtx, unsigned int); 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 rtx_referenced_p_1 (rtx *, void *);
static int computed_jump_p_1 (rtx); static int computed_jump_p_1 (rtx);
static void parms_set (rtx, rtx, void *); 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, static unsigned HOST_WIDE_INT cached_nonzero_bits (rtx, enum machine_mode,
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_regno = subreg_regno (x);
unsigned int inner_endregno unsigned int inner_endregno
= inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER = 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; return endregno > inner_regno && regno < inner_endregno;
} }
@ -1266,13 +1281,15 @@ reg_overlap_mentioned_p (rtx x, rtx in)
regno = REGNO (SUBREG_REG (x)); regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
regno = subreg_regno (x); regno = subreg_regno (x);
endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? subreg_nregs (x) : 1);
goto do_reg; goto do_reg;
case REG: case REG:
regno = REGNO (x); regno = REGNO (x);
do_reg:
endregno = regno + (regno < FIRST_PSEUDO_REGISTER endregno = regno + (regno < FIRST_PSEUDO_REGISTER
? hard_regno_nregs[regno][GET_MODE (x)] : 1); ? hard_regno_nregs[regno][GET_MODE (x)] : 1);
do_reg:
return refers_to_regno_p (regno, endregno, in, (rtx*) 0); return refers_to_regno_p (regno, endregno, in, (rtx*) 0);
case MEM: case MEM:
@ -2926,69 +2943,27 @@ subreg_lsb (rtx x)
SUBREG_BYTE (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). xregno - A regno of an inner hard subreg_reg (or what will become one).
xmode - The mode of xregno. xmode - The mode of xregno.
offset - The byte offset. offset - The byte offset.
ymode - The mode of a top level SUBREG (or what may become one). ymode - The mode of a top level SUBREG (or what may become one).
RETURN - The regno offset which would be used. */ info - Pointer to structure to fill in. */
unsigned int static void
subreg_regno_offset (unsigned int xregno, enum machine_mode xmode, subreg_get_info (unsigned int xregno, enum machine_mode xmode,
unsigned int offset, enum machine_mode ymode) unsigned int offset, enum machine_mode ymode,
struct subreg_info *info)
{ {
int nregs_xmode, nregs_ymode; int nregs_xmode, nregs_ymode;
int mode_multiple, nregs_multiple; int mode_multiple, nregs_multiple;
int y_offset; int offset_adj, y_offset, y_offset_adj;
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 regsize_xmode, regsize_ymode; int regsize_xmode, regsize_ymode;
bool rknown;
gcc_assert (xregno < FIRST_PSEUDO_REGISTER); gcc_assert (xregno < FIRST_PSEUDO_REGISTER);
rknown = false;
/* If there are holes in a non-scalar mode in registers, we expect /* If there are holes in a non-scalar mode in registers, we expect
that it is made up of its units concatenated together. */ that it is made up of its units concatenated together. */
if (HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)) 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 (xmode_unit)
!= ((offset + GET_MODE_SIZE (ymode) - 1) != ((offset + GET_MODE_SIZE (ymode) - 1)
/ GET_MODE_SIZE (xmode_unit)))) / GET_MODE_SIZE (xmode_unit))))
return false; {
info->representable_p = false;
rknown = true;
}
} }
else else
nregs_xmode = hard_regno_nregs[xregno][xmode]; 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]; nregs_ymode = hard_regno_nregs[xregno][ymode];
/* Paradoxical subregs are otherwise valid. */ /* Paradoxical subregs are otherwise valid. */
if (offset == 0 if (!rknown
&& nregs_ymode > nregs_xmode && offset == 0
&& (GET_MODE_SIZE (ymode) > UNITS_PER_WORD && GET_MODE_SIZE (ymode) > GET_MODE_SIZE (xmode))
? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN)) {
return true; 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 /* If registers store different numbers of bits in the different
modes, we cannot generally form this subreg. */ modes, we cannot generally form this subreg. */
regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode; if (!HARD_REGNO_NREGS_HAS_PADDING (xregno, xmode)
regsize_ymode = GET_MODE_SIZE (ymode) / nregs_ymode; && !HARD_REGNO_NREGS_HAS_PADDING (xregno, ymode))
if (regsize_xmode > regsize_ymode && nregs_ymode > 1) {
return false; regsize_xmode = GET_MODE_SIZE (xmode) / nregs_xmode;
if (regsize_ymode > regsize_xmode && nregs_xmode > 1) gcc_assert (regsize_xmode * nregs_xmode == GET_MODE_SIZE (xmode));
return false; 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. */ /* Lowpart subregs are otherwise valid. */
if (offset == subreg_lowpart_offset (ymode, xmode)) if (!rknown && offset == subreg_lowpart_offset (ymode, xmode))
return true; {
info->representable_p = true;
rknown = true;
}
/* This should always pass, otherwise we don't know how to verify /* This should always pass, otherwise we don't know how to verify
the constraint. These conditions may be relaxed but 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 /* The XMODE value can be seen as a vector of NREGS_XMODE
values. The subreg must represent a lowpart of given field. values. The subreg must represent a lowpart of given field.
Compute what field it is. */ Compute what field it is. */
offset -= subreg_lowpart_offset (ymode, offset_adj = offset;
mode_for_size (GET_MODE_BITSIZE (xmode) offset_adj -= subreg_lowpart_offset (ymode,
/ nregs_xmode, mode_for_size (GET_MODE_BITSIZE (xmode)
MODE_INT, 0)); / 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); mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode);
gcc_assert (mode_multiple != 0); gcc_assert (mode_multiple != 0);
y_offset = offset / GET_MODE_SIZE (ymode); 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); 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. */ /* Return the final regno that a subreg expression refers to. */
@ -3090,6 +3140,21 @@ subreg_regno (rtx x)
return ret; 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 struct parms_set_data
{ {
int nregs; int nregs;