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