参照元†
- machine_mode omode
- machine_mode imode
- const_rtx reg
- poly_uint64 offset
返り値†
/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if
this construct would be valid, and false otherwise. */
bool
validate_subreg (machine_mode omode, machine_mode imode,
const_rtx reg, poly_uint64 offset)
{
poly_uint64 isize = GET_MODE_SIZE (imode);
poly_uint64 osize = GET_MODE_SIZE (omode);
/* The sizes must be ordered, so that we know whether the subreg
is partial, paradoxical or complete. */
if (!ordered_p (isize, osize))
return false;
/* All subregs must be aligned. */
if (!multiple_p (offset, osize))
return false;
/* The subreg offset cannot be outside the inner object. */
if (maybe_ge (offset, isize))
return false;
poly_uint64 regsize = REGMODE_NATURAL_SIZE (imode);
/* ??? This should not be here. Temporarily continue to allow word_mode
subregs of anything. The most common offender is (subreg:SI (reg:DF)).
Generally, backends are doing something sketchy but it'll take time to
fix them all. */
if (omode == word_mode)
;
/* ??? Similarly, e.g. with (subreg:DF (reg:TI)). Though store_bit_field
is the culprit here, and not the backends. */
else if (known_ge (osize, regsize) && known_ge (isize, osize))
;
/* Allow component subregs of complex and vector. Though given the below
extraction rules, it's not always clear what that means. */
else if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
&& GET_MODE_INNER (imode) == omode)
;
/* ??? x86 sse code makes heavy use of *paradoxical* vector subregs,
i.e. (subreg:V4SF (reg:SF) 0). This surely isn't the cleanest way to
represent this. It's questionable if this ought to be represented at
all -- why can't this all be hidden in post-reload splitters that make
arbitrarily mode changes to the registers themselves. */
else if (VECTOR_MODE_P (omode) && GET_MODE_INNER (omode) == imode)
;
/* Subregs involving floating point modes are not allowed to
change size. Therefore (subreg:DI (reg:DF) 0) is fine, but
(subreg:SI (reg:DF) 0) isn't. */
else if (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))
{
if (! (known_eq (isize, osize)
/* LRA can use subreg to store a floating point value in
an integer mode. Although the floating point and the
integer modes need the same number of hard registers,
the size of floating point mode can be less than the
integer mode. LRA also uses subregs for a register
should be used in different mode in on insn. */
|| lra_in_progress))
return false;
}
/* Paradoxical subregs must have offset zero. */
if (maybe_gt (osize, isize))
return known_eq (offset, 0U);
/* This is a normal subreg. Verify that the offset is representable. */
/* For hard registers, we already have most of these rules collected in
subreg_offset_representable_p. */
if (reg && REG_P (reg) && HARD_REGISTER_P (reg))
{
unsigned int regno = REGNO (reg);
if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
&& GET_MODE_INNER (imode) == omode)
;
else if (!REG_CAN_CHANGE_MODE_P (regno, imode, omode))
return false;
return subreg_offset_representable_p (regno, imode, offset, omode);
}
/* The outer size must be ordered wrt the register size, otherwise
we wouldn't know at compile time how many registers the outer
mode occupies. */
if (!ordered_p (osize, regsize))
return false;
/* For pseudo registers, we want most of the same checks. Namely:
Assume that the pseudo register will be allocated to hard registers
that can hold REGSIZE bytes each. If OSIZE is not a multiple of REGSIZE,
the remainder must correspond to the lowpart of the containing hard
register. If BYTES_BIG_ENDIAN, the lowpart is at the highest offset,
otherwise it is at the lowest offset.
Given that we've already checked the mode and offset alignment,
we only have to check subblock subregs here. */
if (maybe_lt (osize, regsize)
&& ! (lra_in_progress && (FLOAT_MODE_P (imode) || FLOAT_MODE_P (omode))))
{
/* It is invalid for the target to pick a register size for a mode
that isn't ordered wrt to the size of that mode. */
poly_uint64 block_size = ordered_min (isize, regsize);
unsigned int start_reg;
poly_uint64 offset_within_reg;
if (!can_div_trunc_p (offset, block_size, &start_reg, &offset_within_reg)
|| (BYTES_BIG_ENDIAN
? maybe_ne (offset_within_reg, block_size - osize)
: maybe_ne (offset_within_reg, 0U)))
return false;
}
return true;
}
コメント†