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?

Reply via email to