We don't really have a good place for discussions anymore other than
gcc-patches, but this really isn't a patch.. Oh well.
I'm debugging a failure of ext-dce on a big endian target (m68k) and I
can't help but think it's actually exposed a latent bug in subreg
handling. Your input would be appreciated.
So we have this insn:
(insn 14 13 15 2 (set (reg:DI 55 [ _6 ])
(zero_extend:DI (subreg:SI (reg:DI 35 [ _5 ]) 0))) "j.c":21:27 85
{*zero_extendsidi2}
(expr_list:REG_DEAD (reg:DI 35 [ _5 ])
(nil)))
So bits 32..63 from (reg:DI 35) and shove them into bits 0..31 of
(reg:DI 55) with zero extension.
ext-dce has correctly determined that we only need bits 0..31 of (reg:DI
55). It it conceptually wants to transform that into:
(set (reg:DI 55) (subreg:DI (subreg:SI (reg:DI 35) 0) 0))
Of course we don't want nested subregs, so we actually use
simplify_gen_subreg.
It's simplifying that to...
(set (reg:DI 55) (reg:DI 35))
Which seems wrong for the SET_SRC expression.
This code looks suspicious to me (simplify-rtx.cc):
/* Changing mode twice with SUBREG => just change it once,
or not at all if changing back op starting mode. */
if (GET_CODE (op) == SUBREG)
{
machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
poly_uint64 innermostsize = GET_MODE_SIZE (innermostmode);
rtx newx;
/* Make sure that the relationship between the two subregs is
known at compile time. */
if (!ordered_p (outersize, innermostsize))
return NULL_RTX;
if (outermode == innermostmode
&& known_eq (byte, 0U)
&& known_eq (SUBREG_BYTE (op), 0))
return SUBREG_REG (op);
That test just seems wrong on a big endian target. If fact if I take
out that early exit and let the rest of the code run we get into this:
/* Work out the memory offset of the final OUTERMODE value relative
to the inner value of OP. */
poly_int64 mem_offset = subreg_memory_offset (outermode,
innermode, byte);
poly_int64 op_mem_offset = subreg_memory_offset (op);
poly_int64 final_offset = mem_offset + op_mem_offset;
/* See whether resulting subreg will be paradoxical. */
if (!paradoxical_subreg_p (outermode, innermostmode))
{
/* Bail out in case resulting subreg would be incorrect. */
if (maybe_lt (final_offset, 0)
|| maybe_ge (poly_uint64 (final_offset), innermostsize)
|| !multiple_p (final_offset, outersize))
return NULL_RTX;
}
OUTERMODE and INNERMOSTMODE are both DImode, so it's not paradoxical at
this point. But FINAL_OFFSET is -4, which triggers rejecting the
simplification.
Am I totally offbase here? Or should we just not have called
gen_simplify_subreg in the way we did?
Thanks in advance,
jeff