https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100263
--- Comment #6 from Stefan Schulze Frielinghaus <stefansf at linux dot ibm.com>
---
Prior postreload we have
(insn 12 379 332 3 (set (reg:QI 17 %f2 [orig:198 l_lsm_flag.27 ] [198])
(const_int 1 [0x1])) 1480 {*movqi}
(expr_list:REG_EQUIV (const_int 1 [0x1])
(nil)))
which gets substituted during postreload by
(insn 12 379 332 3 (set (reg:QI 17 %f2 [orig:198 l_lsm_flag.27 ] [198])
(reg:QI 17 %f2 [orig:198 l_lsm_flag.27 ] [198])) 1480 {*movqi}
(expr_list:REG_EQUIV (const_int 1 [0x1])
(nil)))
which gets deleted during split2 where we have
deleting insn with uid = 12.
The culprit seems to be that postreload changes the RHS of the assignment to
`reg:QI 17 %f2` which is wrong. Register %f2 holds indeed constant 1, however,
in DImode which is not compatible to QImode on IBM Z.
The decision takes place in function move2add_valid_value_p where the wrong
offset is returned by call
subreg_regno_offset (17, DImode, 7, QImode)
I would have expected offset 7 but 0 is returned which renders the subsequent
if-condition false. The 0 comes from function call subreg_get_info which
returns in this case via
/* Lowpart subregs are otherwise valid. */
if (!rknown && known_eq (offset, subreg_lowpart_offset (ymode, xmode)))
{
info->representable_p = true;
rknown = true;
if (known_eq (offset, 0U) || nregs_xmode == nregs_ymode)
{
info->offset = 0;
info->nregs = nregs_ymode;
return;
}
}
The offset doesn't equal zero but the number of registers. Still the offset is
set to zero.
I did a quick test by using instead
diff --git a/gcc/postreload.c b/gcc/postreload.c
index dc67643384d..64297be2c45 100644
--- a/gcc/postreload.c
+++ b/gcc/postreload.c
@@ -1732,12 +1732,7 @@ move2add_valid_value_p (int regno, scalar_int_mode mode)
(REG:reg_mode[regno] regno). Now, for big endian, the starting
regno of the lowpart might be different. */
poly_int64 s_off = subreg_lowpart_offset (mode, old_mode);
- s_off = subreg_regno_offset (regno, old_mode, s_off, mode);
- if (maybe_ne (s_off, 0))
- /* We could in principle adjust regno, check reg_mode[regno] to be
- BLKmode, and return s_off to the caller (vs. -1 for failure),
- but we currently have no callers that could make use of this
- information. */
+ if (simplify_subreg_regno (regno, old_mode, s_off, mode) < 0)
return false;
}
which works at least for the example (haven't done a bootstrap nor regtest
yet). However, I'm still wondering whether subreg_get_info is supposed to
return with a zero offset in cases like this? Any thoughts?