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:
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.
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] ])
(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} list:REG_ DEAD (reg:DF 590 [ MEM[base: sdiag_143(D), index: ivtmp.67_240, offset: 0B] ])
(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}
(if_then_ else:SI (ne (reg:CCZ 33 %cc)
(const_ int 0 [0]))
(reg/ v:SI 109 [ nsing ])
(if_then_ else (le (reg:SI 320 [ _444 ])
(reg/ v:SI 109 [ nsing ]))
( label_ref: DI 943)
( pc)))
(clobber (reg:CC 33 %cc)) br_signed_ si} list:REG_ UNUSED (reg:CC 33 %cc)
(int_list: REG_BR_ PROB 536870916 (nil)))
(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)
(expr_
(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)
(nil))
(insn 2482 2481 927 88 (set (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)
]) "min.qrsolv.f":52 1260 {*cmp_and_
(expr_
-> 943)
In the backend we have that interesting splitter which triggers for the old and now obsolete compare in insn 916
(define_split operand: FP 2 "const0_ operand" )))] HARD_FLOAT && REG_P (operands[1]) && dead_or_set_p (insn, operands[1])"
[(set (match_operand 0 "cc_reg_operand")
(compare (match_operand:FP 1 "register_operand")
(match_
"TARGET_
[(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] ])
(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] ]))
(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}
(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)
]) "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)
(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])
(const_ int 520 [0x208])) [3 sdiag+0 S8 A64])) "min.qrsolv.f":51 1270 {*movdi_64} list:REG_ DEAD (reg:DI 3 %r3 [1060])
(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])) 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) )))
(const_ double: DF 0.0 [0x0.0p+0])) 1289 {*movdf_64dfp}
(compare: CCZ (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index: ivtmp.67_240, offset: 0B] ] [590]) list:REG_ DEAD (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index: ivtmp.67_240, offset: 0B] ] [590])
(mem/f/c:DI (plus:DI (reg/f:DI 15 %r15)
(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_
(nil)))
(insn 2677 915 3108 121 (parallel [
(set (reg:CCZ 33 %cc)
]) "min.qrsolv.f":51 1250 {*cmpdf_ccs_0}
(expr_
(insn 3108 2677 2481 121 (set (reg:DF 20 %f1 [1061])
(nil))
(insn 2481 3108 2480 121 (set (reg:CCZ 33 %cc)
(reg:DF 20 %f1 [1061]))) 1255 {*cmpdf_ccs}
(expr_
(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}
(compare: CCZ (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index: ivtmp.67_240, offset: 0B] ] [590]) list:REG_ DEAD (reg:DF 16 %f0 [orig:590 MEM[base: sdiag_143(D), index: ivtmp.67_240, offset: 0B] ] [590]) list:REG_ EQUIV (const_int 0 [0])
(if_then_ else:SI (ne (reg:CCZ 33 %cc)
(const_ int 0 [0]))
(reg/ v:SI 2 %r2 [orig:109 nsing ] [109]) list:REG_ DEAD (reg:CCZ 33 %cc)
(expr_ list:REG_ DEAD (reg:SI 3 %r3 [733])
(nil) )))
(nil))
(insn 2481 3108 2480 121 (set (reg:CCZ 33 %cc)
(reg:DF 20 %f1 [1061]))) 1255 {*cmpdf_ccs}
(expr_
(nil)))
(insn 2480 2481 2482 121 (set (reg:SI 0 %r0 [733])
(const_int 0 [0])) 1274 {*movsi_zarch}
(expr_
(nil)))
(insn 2482 2480 928 121 (set (reg/v:SI 2 %r2 [orig:109 nsing ] [109])
(reg:SI 0 %r0 [733]))) 1676 {*movsicc}
(expr_
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.