rtl.h (validate_subreg): Declare.

* rtl.h (validate_subreg): Declare.
        * emit-rtl.c (validate_subreg): New.
        (gen_rtx_SUBREG): Use it.
        * simplify-rtx.c (simplify_subreg): Likewise.
        (simplify_gen_subreg): Likewise.  Remove duplicate asserts.
        * expr.c (emit_move_insn_1): Tidy complex move code.  Use memory
        fallback whenever gen_realpart/gen_imagpart would not be able to
        create SUBREGs.

From-SVN: r91126
This commit is contained in:
Richard Henderson 2004-11-23 16:09:03 -08:00 committed by Richard Henderson
parent 4e55a16271
commit beb7268481
5 changed files with 147 additions and 74 deletions

View File

@ -1,3 +1,14 @@
2004-11-23 Richard Henderson <rth@redhat.com>
* rtl.h (validate_subreg): Declare.
* emit-rtl.c (validate_subreg): New.
(gen_rtx_SUBREG): Use it.
* simplify-rtx.c (simplify_subreg): Likewise.
(simplify_gen_subreg): Likewise. Remove duplicate asserts.
* expr.c (emit_move_insn_1): Tidy complex move code. Use memory
fallback whenever gen_realpart/gen_imagpart would not be able to
create SUBREGs.
2004-11-23 Richard Henderson <rth@redhat.com>
* expmed.c (extract_bit_field): Use simplify_gen_subreg instead of

View File

@ -607,20 +607,98 @@ gen_const_mem (enum machine_mode mode, rtx addr)
return mem;
}
/* We want to create (subreg:OMODE (obj:IMODE) OFFSET). Return true if
this construct would be valid, and false otherwise. */
bool
validate_subreg (enum machine_mode omode, enum machine_mode imode,
rtx reg, unsigned int offset)
{
unsigned int isize = GET_MODE_SIZE (imode);
unsigned int osize = GET_MODE_SIZE (omode);
/* All subregs must be aligned. */
if (offset % osize != 0)
return false;
/* The subreg offset cannot be outside the inner object. */
if (offset >= isize)
return false;
/* ??? 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 (osize >= UNITS_PER_WORD && 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 (isize != osize)
return false;
}
/* Paradoxical subregs must have offset zero. */
if (osize > isize)
return offset == 0;
/* 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);
#ifdef CANNOT_CHANGE_MODE_CLASS
if ((COMPLEX_MODE_P (imode) || VECTOR_MODE_P (imode))
&& GET_MODE_INNER (imode) == omode)
;
else if (REG_CANNOT_CHANGE_MODE_P (regno, imode, omode))
return false;
#endif
return subreg_offset_representable_p (regno, imode, offset, omode);
}
/* For pseudo registers, we want most of the same checks. Namely:
If the register no larger than a word, the subreg must be lowpart.
If the register is larger than a word, the subreg must be the lowpart
of a subword. A subreg does *not* perform arbitrary bit extraction.
Given that we've already checked mode/offset alignment, we only have
to check subword subregs here. */
if (osize < UNITS_PER_WORD)
{
enum machine_mode wmode = isize > UNITS_PER_WORD ? word_mode : imode;
unsigned int low_off = subreg_lowpart_offset (omode, wmode);
if (offset % UNITS_PER_WORD != low_off)
return false;
}
return true;
}
rtx
gen_rtx_SUBREG (enum machine_mode mode, rtx reg, int offset)
{
/* This is the most common failure type.
Catch it early so we can see who does it. */
gcc_assert (!(offset % GET_MODE_SIZE (mode)));
/* This check isn't usable right now because combine will
throw arbitrary crap like a CALL into a SUBREG in
gen_lowpart_for_combine so we must just eat it. */
#if 0
/* Check for this too. */
gcc_assert (offset < GET_MODE_SIZE (GET_MODE (reg)));
#endif
gcc_assert (validate_subreg (mode, GET_MODE (reg), reg, offset));
return gen_rtx_raw_SUBREG (mode, reg, offset);
}

View File

@ -2647,7 +2647,6 @@ emit_move_insn_1 (rtx x, rtx y)
{
enum machine_mode mode = GET_MODE (x);
enum machine_mode submode;
enum mode_class class = GET_MODE_CLASS (mode);
gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
@ -2656,20 +2655,21 @@ emit_move_insn_1 (rtx x, rtx y)
emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y));
/* Expand complex moves by moving real part and imag part, if possible. */
else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
else if (COMPLEX_MODE_P (mode)
&& BLKmode != (submode = GET_MODE_INNER (mode))
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
unsigned int modesize = GET_MODE_SIZE (mode);
unsigned int submodesize = GET_MODE_SIZE (submode);
/* Don't split destination if it is a stack push. */
int stack = push_operand (x, GET_MODE (x));
int stack = push_operand (x, mode);
#ifdef PUSH_ROUNDING
/* In case we output to the stack, but the size is smaller than the
machine can push exactly, we need to use move instructions. */
if (stack
&& (PUSH_ROUNDING (GET_MODE_SIZE (submode))
!= GET_MODE_SIZE (submode)))
if (stack && PUSH_ROUNDING (submodesize) != submodesize)
{
rtx temp;
HOST_WIDE_INT offset1, offset2;
@ -2683,9 +2683,7 @@ emit_move_insn_1 (rtx x, rtx y)
add_optab,
#endif
stack_pointer_rtx,
GEN_INT
(PUSH_ROUNDING
(GET_MODE_SIZE (GET_MODE (x)))),
GEN_INT (PUSH_ROUNDING (modesize)),
stack_pointer_rtx, 0, OPTAB_LIB_WIDEN);
if (temp != stack_pointer_rtx)
@ -2693,11 +2691,10 @@ emit_move_insn_1 (rtx x, rtx y)
#ifdef STACK_GROWS_DOWNWARD
offset1 = 0;
offset2 = GET_MODE_SIZE (submode);
offset2 = submodesize;
#else
offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
+ GET_MODE_SIZE (submode));
offset1 = -PUSH_ROUNDING (modesize);
offset2 = -PUSH_ROUNDING (modesize) + submodesize;
#endif
emit_move_insn (change_address (x, submode,
@ -2748,42 +2745,32 @@ emit_move_insn_1 (rtx x, rtx y)
memory and reload. FIXME, we should see about using extract and
insert on integer registers, but complex short and complex char
variables should be rarely used. */
if (GET_MODE_BITSIZE (mode) < 2 * BITS_PER_WORD
&& (reload_in_progress | reload_completed) == 0)
if ((reload_in_progress | reload_completed) == 0
&& (!validate_subreg (submode, mode, NULL, submodesize)
|| !validate_subreg (submode, mode, NULL, 0)))
{
int packed_dest_p
= (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER);
int packed_src_p
= (REG_P (y) && REGNO (y) < FIRST_PSEUDO_REGISTER);
if (packed_dest_p || packed_src_p)
if (REG_P (x) || REG_P (y))
{
enum mode_class reg_class = ((class == MODE_COMPLEX_FLOAT)
? MODE_FLOAT : MODE_INT);
rtx mem, cmem;
enum machine_mode reg_mode
= mode_for_size (GET_MODE_BITSIZE (mode), reg_class, 1);
= mode_for_size (GET_MODE_BITSIZE (mode), MODE_INT, 1);
if (reg_mode != BLKmode)
gcc_assert (reg_mode != BLKmode);
mem = assign_stack_temp (reg_mode, modesize, 0);
cmem = adjust_address (mem, mode, 0);
if (REG_P (x))
{
rtx mem = assign_stack_temp (reg_mode,
GET_MODE_SIZE (mode), 0);
rtx cmem = adjust_address (mem, mode, 0);
if (packed_dest_p)
{
rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
emit_move_insn_1 (cmem, y);
return emit_move_insn_1 (sreg, mem);
}
else
{
rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
emit_move_insn_1 (mem, sreg);
return emit_move_insn_1 (x, cmem);
}
rtx sreg = gen_rtx_SUBREG (reg_mode, x, 0);
emit_move_insn_1 (cmem, y);
return emit_move_insn_1 (sreg, mem);
}
else
{
rtx sreg = gen_rtx_SUBREG (reg_mode, y, 0);
emit_move_insn_1 (mem, sreg);
return emit_move_insn_1 (x, cmem);
}
}
}

View File

@ -1964,6 +1964,8 @@ extern rtx delete_insn_and_edges (rtx);
extern void delete_insn_chain_and_edges (rtx, rtx);
extern rtx gen_lowpart_SUBREG (enum machine_mode, rtx);
extern rtx gen_const_mem (enum machine_mode, rtx);
extern bool validate_subreg (enum machine_mode, enum machine_mode,
rtx, unsigned int);
/* In combine.c */
extern int combine_instructions (rtx, unsigned int);

View File

@ -3642,12 +3642,14 @@ simplify_subreg (enum machine_mode outermode, rtx op,
}
/* Recurse for further possible simplifications. */
newx = simplify_subreg (outermode, SUBREG_REG (op),
GET_MODE (SUBREG_REG (op)),
final_offset);
newx = simplify_subreg (outermode, SUBREG_REG (op), innermostmode,
final_offset);
if (newx)
return newx;
return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
if (validate_subreg (outermode, innermostmode,
SUBREG_REG (op), final_offset))
return gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
return NULL_RTX;
}
/* SUBREG of a hard register => just change the register number
@ -3725,9 +3727,9 @@ simplify_subreg (enum machine_mode outermode, rtx op,
res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
if (res)
return res;
/* We can at least simplify it by referring directly to the
relevant part. */
return gen_rtx_SUBREG (outermode, part, final_offset);
if (validate_subreg (outermode, GET_MODE (part), part, final_offset))
return gen_rtx_SUBREG (outermode, part, final_offset);
return NULL_RTX;
}
/* Optimize SUBREG truncations of zero and sign extended values. */
@ -3775,17 +3777,6 @@ simplify_gen_subreg (enum machine_mode outermode, rtx op,
enum machine_mode innermode, unsigned int byte)
{
rtx newx;
/* Little bit of sanity checking. */
gcc_assert (innermode != VOIDmode);
gcc_assert (outermode != VOIDmode);
gcc_assert (innermode != BLKmode);
gcc_assert (outermode != BLKmode);
gcc_assert (GET_MODE (op) == innermode
|| GET_MODE (op) == VOIDmode);
gcc_assert ((byte % GET_MODE_SIZE (outermode)) == 0);
gcc_assert (byte < GET_MODE_SIZE (innermode));
newx = simplify_subreg (outermode, op, innermode, byte);
if (newx)
@ -3795,8 +3786,12 @@ simplify_gen_subreg (enum machine_mode outermode, rtx op,
|| (REG_P (op) && REGNO (op) < FIRST_PSEUDO_REGISTER))
return NULL_RTX;
return gen_rtx_SUBREG (outermode, op, byte);
if (validate_subreg (outermode, innermode, op, byte))
return gen_rtx_SUBREG (outermode, op, byte);
return NULL_RTX;
}
/* Simplify X, an rtx expression.
Return the simplified expression or NULL if no simplifications