Hi all,

While trying to fix the failing test gcc.dg/torture/pr111821.c on s390 I'm
stumbling across another problem.  After ira we have

(note 4 1 18 2 [bb 2] NOTE_INSN_BASIC_BLOCK)
(insn 18 4 2 2 (set (reg:DI 66)
        (reg:DI 2 %r2 [ p ])) "/gcc/testsuite/gcc.dg/torture/pr111821.c":5:1 
1503 {*movdi_64}
     (expr_list:REG_DEAD (reg:DI 2 %r2 [ p ])
        (nil)))
(note 2 18 3 2 NOTE_INSN_DELETED)
(note 3 2 17 2 NOTE_INSN_FUNCTION_BEG)
(insn 17 3 6 2 (set (reg:DI 61 [ MEM[(const union T *)p_2(D)] ])
        (const_int 0 [0])) "/gcc/testsuite/gcc.dg/torture/pr111821.c":7:22 1503 
{*movdi_64}
     (expr_list:REG_EQUAL (const_int 0 [0])
        (nil)))
(insn 6 17 8 2 (parallel [
            (set (strict_low_part (subreg:HI (reg:DI 61 [ MEM[(const union T 
*)p_2(D)] ]) 6))
                (mem:HI (plus:DI (reg:DI 66)
                        (const_int 6 [0x6])) [0 MEM[(const union T *)p_2(D)]+6 
S2 A8]))
            (clobber (reg:CC 33 %cc))
        ]) "/gcc/testsuite/gcc.dg/torture/pr111821.c":7:22 1518 {movstricthi}
     (expr_list:REG_DEAD (reg:DI 66)
        (expr_list:REG_UNUSED (reg:CC 33 %cc)
            (nil))))
(note 8 6 13 2 NOTE_INSN_DELETED)
(insn 13 8 14 2 (set (reg/i:DI 2 %r2)
        (zero_extend:DI (reg/v:HI 61 [ v ]))) 
"/gcc/testsuite/gcc.dg/torture/pr111821.c":9:1 1684 {*zero_extendhidi2_z10}
     (expr_list:REG_DEAD (reg/v:HI 61 [ v ])
        (nil)))
(insn 14 13 0 2 (use (reg/i:DI 2 %r2)) 
"/gcc/testsuite/gcc.dg/torture/pr111821.c":9:1 -1
     (nil))

and then error out during lra with

during RTL pass: reload
dump file: pr111821.c.316r.reload
/gcc/testsuite/gcc.dg/torture/pr111821.c: In function 'f':
/gcc/testsuite/gcc.dg/torture/pr111821.c:9:1: internal compiler error: in 
alter_subregs, at lra-spills.cc:690
0x3d503cd internal_error(char const*, ...)
        /gcc/diagnostic-global-context.cc:491
0x3d1c5a5 fancy_abort(char const*, int, char const*)
        /gcc/diagnostic.cc:1772
0x2204c11 alter_subregs
        /gcc/lra-spills.cc:690
0x22052df lra_final_code_change()
        /gcc/lra-spills.cc:802
0x21c8ee9 lra(_IO_FILE*, int)
        /gcc/lra.cc:2577
0x214e913 do_reload
        /gcc/ira.cc:5976
0x214f049 execute
        /gcc/ira.cc:6164
Please submit a full bug report, with preprocessed source (by using 
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

Before iterating in lra_final_code_change() over all insns we first substitute
remaining pseudos via

for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
  if (lra_reg_info[i].nrefs != 0
      && (hard_regno = lra_get_regno_hard_regno (i)) >= 0)
    SET_REGNO (regno_reg_rtx[i], hard_regno);

There we also see that `(reg/v:HI 61 [ v ])` is substituted by regno 1.  This
materializes in insn 13:

(insn 13 8 14 2 (set (reg/i:DI 2 %r2)
        (zero_extend:DI (reg/v:HI 1 %r1 [orig:61 v ] [61]))) 
"/gcc/testsuite/gcc.dg/torture/pr111821.c":9:1 1684 {*zero_extendhidi2_z10}
     (expr_list:REG_DEAD (reg/v:HI 1 %r1 [orig:61 v ] [61])
        (nil)))

However `(reg:DI 61 [ MEM[(const union T *)p_2(D)] ])` referencing the
same pseudo in a different mode is not substituted in insn 6 which
leads in the following to an error.  The insn is emitted in
s390_expand_insv() during

if ((bitpos % BITS_PER_UNIT) == 0
    && (bitsize % BITS_PER_UNIT) == 0
    && (bitpos & 32) == ((bitpos + bitsize - 1) & 32)
    && MEM_P (src)
    && (mode == DImode || mode == SImode)
    && mode != smode
    && register_operand (dest, mode))
  {
    /* Emit a strict_low_part pattern if possible.  */
    if (smode_bsize == bitsize && bitpos == mode_bsize - smode_bsize)
      {
        rtx low_dest = s390_gen_lowpart_subreg (smode, dest);
        rtx low_src = gen_lowpart (smode, src);

        switch (smode)
          {
          case E_QImode: emit_insn (gen_movstrictqi (low_dest, low_src)); 
return true;
          case E_HImode: emit_insn (gen_movstricthi (low_dest, low_src)); 
return true;
          case E_SImode: emit_insn (gen_movstrictsi (low_dest, low_src)); 
return true;
          default: break;
          }
      }

    /* ??? There are more powerful versions of ICM that are not
       completely represented in the md file.  */
  }

where in s390_gen_lowpart_subreg() we generate a new reference
`(reg:DI 61 [ MEM[(const union T *)p_2(D)] ])` to pseudo 61 in DI mode in order
to finally wrap-it up in a subreg suitable for a strict_low_part:

rtx
s390_gen_lowpart_subreg (machine_mode mode, rtx expr)
{
  rtx lowpart = gen_lowpart (mode, expr);

  /* There might be no SUBREG in case it could be applied to the hard
     REG rtx or it could be folded with a paradoxical subreg.  Bring
     it back.  */
  if (!SUBREG_P (lowpart))
    {
      machine_mode reg_mode = TARGET_ZARCH ? DImode : SImode;
      gcc_assert (REG_P (lowpart));
      lowpart = gen_lowpart_SUBREG (mode,
                                    gen_rtx_REG (reg_mode,
                                                 REGNO (lowpart)));
    }

  return lowpart;
}

I'm wondering whether this is allowed or if this kind of "casting" of a
register into a different mode is the culprit of the error?

Beside that I'm wondering whether we shouldn't just bail out if gen_lowpart
doesn't return a subreg since then most likely `expr` was a paradoxical subreg.
At least in this example this leads to a partial initialization of pseudo 61 in
insn 6.  This is fixed up later by pass init-regs which is introducing insn 17
and zeroing the entire pseudo 61.  However, this is another story and I'm
currently more interested whether a "cast" as done in s390_gen_lowpart_subreg()
is allowed at all or not.

Cheers,
Stefan
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index 7aea776da2f..e87f2b8daac 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -7113,7 +7113,8 @@ s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
       if (smode_bsize == bitsize && bitpos == mode_bsize - smode_bsize)
        {
          rtx low_dest = s390_gen_lowpart_subreg (smode, dest);
-         rtx low_src = gen_lowpart (smode, src);
+         poly_int64 offset = GET_MODE_SIZE (mode) - GET_MODE_SIZE (smode);
+         rtx low_src = adjust_address (src, smode, offset);
 
          switch (smode)
            {

Reply via email to