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?