https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109086
--- Comment #10 from liwei at loongson dot cn --- (In reply to Richard Biener from comment #4) > (In reply to liwei from comment #3) > > Thank you for your quick reply! > > > > The final call of the expand_simple_binop function returns part of the code > > as follows (optabs.cc): > > > > 1671 xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend); > > 1672 > > 1673 /* The second operand of a shift must always be extended. */ > > 1674 xop1 = widen_operand (xop1, wider_mode, mode, unsignedp, > > 1675 no_extend && binoptab != ashl_optab); > > 1676 > > 1677 temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX, > > 1678 unsignedp, OPTAB_DIRECT); > > 1679 if (temp) > > 1680 { > > 1681 if (mclass != MODE_INT > > 1682 || !TRULY_NOOP_TRUNCATION_MODES_P (mode, wider_mode)) > > 1683 { > > 1684 if (target == 0) > > 1685 target = gen_reg_rtx (mode); > > 1686 convert_move (target, temp, 0); > > 1687 return target; > > 1688 } > > 1689 else > > 1690 return gen_lowpart (mode, temp); > > 1691 } > > > > In the above code, target = result, when promote xop0 and xop1 machine mode > > to DI, then match adddi3 insn pattern and save the new rtx to temp, then > > because the mclass equal MODE_INT (also equal true for > > TRULY_NOOP_TRUNCATION_MODES_P function), the code enter else branch and > > return lowpart of temp which is irrelevant with target (i.e. result). > > Sure, but expand_simple_binop doesn't need to return 'target' > > > Maybe the expand_binop function does not consider the case of dependency > > with `target` when generating rtx for the case of promote MODE_INT mode, and > > maybe theoretically it does not need to be considered, except that > > builtin_strcmp happens to meet such cases, so I think it is enough to modify > > the processing logic of builtin_strcmp (my humble opinion). > > I'm still missing the obvious? We assign the result to 'result', so it > should be all fine? I see that emit_cmp_and_jump_insns eventually forces > the lowpart to a register but still it should work. Thanks for Xi Ruoyao's explanation, here I will add a specific diff example. Following is the expand pass result of add above bug patch: ;; expand_simple_binop in loop where i = 0 (insn 13 12 14 (set (reg:DI 87) (plus:DI (subreg:DI (reg:SI 86) 0) (const_int -45 [0xffffffffffffffd3])))) ;; emit_cmp_and_jump_insns in loop where i = 0 (insn 14 13 15 (set (reg:DI 88) (sign_extend:DI (subreg:SI (reg:DI 87) 0)))) (jump_insn 15 14 16 (set (pc) (if_then_else (ne (reg:DI 88) (const_int 0 [0])) (label_ref 18) (pc)))) ... ;; expand_simple_binop in loop where i = 1 (insn 17 16 18 (set (reg:DI 90) (plus:DI (subreg:DI (reg:SI 89) 0) (const_int 0 [0])))) (code_label 18 17 19 3 (nil)) ;; finish and return result -> subreg:SI (reg:DI 90) 0) ;; next insn (insn 19 18 0 (set (reg:DI 80 [ _1 ]) (sign_extend:DI (subreg:SI (reg:DI 90) 0)))) The problem is in insn 17, because the compare result is set in reg:DI 90, which is diff with compare result(loop0) set in reg:DI 87. The reason for this is because after loop0 the rtx result = subreg:SI (reg:DI 87) 0), then in expand_simple_binop function, due to no addsi3 insn pattern, gcc promote mode and match adddi3 and finally return temporary register (reg:DI 90), and lowpart it to match mode so after loop1 the result = (subreg:SI (reg:DI 90)). The way to solve this kind of problem is to record the result of the previous loop comparison in loop1 and later, and when the comparison result in the current loop is not the same as the previous one, correct it by `move`, so that no matter which branch it jumps from, the result is correct.