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)
{