[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