[Bug target/88856] [8/9 Regression] gfortran producing wrong code with -funroll-loops
krebbel at gcc dot gnu.org
gcc-bugzilla@gcc.gnu.org
Fri Feb 1 17:46:00 GMT 2019
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88856
--- Comment #8 from Andreas Krebbel <krebbel at gcc dot gnu.org> ---
The r265193 patch was found via reghunt. However, it just reveals an underlying
issue.
The problem can also be seen with mainline.
The miscompile happens in the following loop:
do 110 j = 1, n
if (sdiag(j) .eq. zero .and. nsing .eq. n) nsing = j - 1
if (nsing .lt. n) wa(j) = zero
110 continue
The problem appears to be rather related to ifcvt. ifcvt generates a load on
condition for the sdiag(j) .eq. zero comparison by inserting insns: 2480, 2481,
2482:
265.ce2
(insn 915 918 916 88 (set (reg:DF 590 [ MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ])
(mem:DF (reg/v/f:DI 239 [ sdiag ]) [2 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B]+0 S8 A64])) "min.qrsolv.f":51 1289 {*movdf_64dfp}
(nil))
(insn 916 915 2480 88 (set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 590 [ MEM[base: sdiag_143(D), index: ivtmp.67_240,
offset: 0B] ])
(const_double:DF 0.0 [0x0.0p+0]))) "min.qrsolv.f":51 1255
{*cmpdf_ccs}
(expr_list:REG_DEAD (reg:DF 590 [ MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ])
(nil)))
(insn 2480 916 2481 88 (set (reg:SI 733)
(const_int 0 [0])) 1274 {*movsi_zarch}
(nil))
(insn 2481 2480 2482 88 (set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 590 [ MEM[base: sdiag_143(D), index: ivtmp.67_240,
offset: 0B] ])
(const_double:DF 0.0 [0x0.0p+0]))) 1255 {*cmpdf_ccs}
(nil))
(insn 2482 2481 927 88 (set (reg/v:SI 109 [ nsing ])
(if_then_else:SI (ne (reg:CCZ 33 %cc)
(const_int 0 [0]))
(reg/v:SI 109 [ nsing ])
(reg:SI 733))) 1676 {*movsicc}
(nil))
(note 927 2482 928 88 NOTE_INSN_DELETED)
(jump_insn 928 927 932 88 (parallel [
(set (pc)
(if_then_else (le (reg:SI 320 [ _444 ])
(reg/v:SI 109 [ nsing ]))
(label_ref:DI 943)
(pc)))
(clobber (reg:CC 33 %cc))
]) "min.qrsolv.f":52 1260 {*cmp_and_br_signed_si}
(expr_list:REG_UNUSED (reg:CC 33 %cc)
(int_list:REG_BR_PROB 536870916 (nil)))
-> 943)
In the backend we have that interesting splitter which triggers for the old and
now obsolete compare in insn 916
(define_split
[(set (match_operand 0 "cc_reg_operand")
(compare (match_operand:FP 1 "register_operand")
(match_operand:FP 2 "const0_operand")))]
"TARGET_HARD_FLOAT && REG_P (operands[1]) && dead_or_set_p (insn,
operands[1])"
[(parallel
[(set (match_dup 0) (match_dup 3))
(clobber (match_dup 1))])]
{
/* s390_match_ccmode requires the compare to have the same CC mode
as the CC destination register. */
operands[3] = gen_rtx_COMPARE (GET_MODE (operands[0]),
operands[1], operands[2]);
})
268.split1 insn 916 -> insn 2677
The REG_DEAD note becomes a clobber due to that
(insn 915 918 2677 105 (set (reg:DF 590 [ MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ])
(mem:DF (reg/v/f:DI 239 [ sdiag ]) [2 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B]+0 S8 A64])) "min.qrsolv.f":51 1289 {*movdf_64dfp}
(nil))
(insn 2677 915 2480 105 (parallel [
(set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 590 [ MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ])
(const_double:DF 0.0 [0x0.0p+0])))
(clobber (reg:DF 590 [ MEM[base: sdiag_143(D), index: ivtmp.67_240,
offset: 0B] ]))
]) "min.qrsolv.f":51 -1
(nil))
(insn 2480 2677 2481 105 (set (reg:SI 733)
(const_int 0 [0])) 1274 {*movsi_zarch}
(nil))
(insn 2481 2480 2482 105 (set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 590 [ MEM[base: sdiag_143(D), index: ivtmp.67_240,
offset: 0B] ])
(const_double:DF 0.0 [0x0.0p+0]))) 1255 {*cmpdf_ccs}
(nil))
294.cprop_hardreg appears to mess up things: REG_DEAD note in insn 2677 does
not appear to fit the used reg but CC is unused now
(insn 3107 927 915 121 (set (reg:DI 3 %r3 [1060])
(mem/f/c:DI (plus:DI (reg/f:DI 15 %r15)
(const_int 520 [0x208])) [3 sdiag+0 S8 A64])) "min.qrsolv.f":51
1270 {*movdi_64}
(nil))
(insn 915 3107 2677 121 (set (reg:DF 19 %f6 [orig:590 MEM[base: sdiag_143(D),
index: ivtmp.67_240, offset: 0B] ] [590])
(mem:DF (reg:DI 3 %r3 [1060]) [2 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B]+0 S8 A64])) "min.qrsolv.f":51 1289 {*movdf_64dfp}
(expr_list:REG_DEAD (reg:DI 3 %r3 [1060])
(nil)))
(insn 2677 915 3108 121 (parallel [
(set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 19 %f6 [orig:590 MEM[base: sdiag_143(D),
index: ivtmp.67_240, offset: 0B] ] [590])
(const_double:DF 0.0 [0x0.0p+0])))
(clobber (reg:DF 19 %f6 [orig:590 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ] [590]))
]) "min.qrsolv.f":51 1250 {*cmpdf_ccs_0}
(expr_list:REG_DEAD (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D),
index: ivtmp.67_240, offset: 0B] ] [590])
(expr_list:REG_UNUSED (reg:CCZ 33 %cc)
(nil))))
(insn 3108 2677 2481 121 (set (reg:DF 20 %f1 [1061])
(const_double:DF 0.0 [0x0.0p+0])) 1289 {*movdf_64dfp}
(nil))
(insn 2481 3108 2480 121 (set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ] [590])
(reg:DF 20 %f1 [1061]))) 1255 {*cmpdf_ccs}
(expr_list:REG_DEAD (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D),
index: ivtmp.67_240, offset: 0B] ] [590])
(nil)))
295.rtl_dce consequently removes insn 3107, 915, 2677
(insn 3108 927 2481 121 (set (reg:DF 20 %f1 [1061])
(const_double:DF 0.0 [0x0.0p+0])) 1289 {*movdf_64dfp}
(nil))
(insn 2481 3108 2480 121 (set (reg:CCZ 33 %cc)
(compare:CCZ (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index:
ivtmp.67_240, offset: 0B] ] [590])
(reg:DF 20 %f1 [1061]))) 1255 {*cmpdf_ccs}
(expr_list:REG_DEAD (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D),
index: ivtmp.67_240, offset: 0B] ] [590])
(nil)))
(insn 2480 2481 2482 121 (set (reg:SI 0 %r0 [733])
(const_int 0 [0])) 1274 {*movsi_zarch}
(expr_list:REG_EQUIV (const_int 0 [0])
(nil)))
(insn 2482 2480 928 121 (set (reg/v:SI 2 %r2 [orig:109 nsing ] [109])
(if_then_else:SI (ne (reg:CCZ 33 %cc)
(const_int 0 [0]))
(reg/v:SI 2 %r2 [orig:109 nsing ] [109])
(reg:SI 0 %r0 [733]))) 1676 {*movsicc}
(expr_list:REG_DEAD (reg:CCZ 33 %cc)
(expr_list:REG_DEAD (reg:SI 3 %r3 [733])
(nil))))
To my understanding the data flow is already broken after ifcvt inserted the
new compare while leaving the REG_DEAD note in the old. The new compare already
appears to read a dead register here and this appears to trigger the rest of
the unfortunate events.
More information about the Gcc-bugs
mailing list