mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-10 07:10:27 +08:00
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:
parent
4e55a16271
commit
beb7268481
@ -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
|
||||
|
100
gcc/emit-rtl.c
100
gcc/emit-rtl.c
@ -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);
|
||||
}
|
||||
|
||||
|
75
gcc/expr.c
75
gcc/expr.c
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user