https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109086

--- Comment #9 from Xi Ruoyao <xry111 at gcc dot gnu.org> ---
(In reply to Richard Biener from comment #4)

> > 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.

The problem here is we are assigning the result (i. e. virtual register number)
to 'result', not *moving* the result (i. e. the difference between s[i] and
t[i]) into 'result'.

When expand_simple_binop is allowed to assign new vreg in the loop, it's
possible that loop iteration 1 uses vreg1, iteration 2 use vreg2, ...,
iteration N use vregN.  When we move the result into 'result', the "moving"
will happen only if the execution really reaches the move insn, such a behavior
is correct.

But we we assign the result into 'result', the assignment will "always" happen
(because assignment is a logic in the compiler itself, unlike moving which is a
part of target code).  I. e. we always return vregN as the result, which is not
correct if the loop jumps out early.

I'd suggest

diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 305c65c29be..0c14a3b52b3 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -7142,8 +7142,11 @@ inline_string_cmp (rtx target, tree var_str, const char
*const_str,

       op0 = convert_modes (mode, unit_mode, op0, 1);
       op1 = convert_modes (mode, unit_mode, op1, 1);
-      result = expand_simple_binop (mode, MINUS, op0, op1,
-                                   result, 1, OPTAB_WIDEN);
+      rtx diff = expand_simple_binop (mode, MINUS, op0, op1,
+                                     result, 1, OPTAB_WIDEN);
+      if (diff != result)
+       emit_move_insn (result, diff);
+
       if (i < length - 1)
        emit_cmp_and_jump_insns (result, CONST0_RTX (mode), NE, NULL_RTX,
                                 mode, true, ne_label);

Reply via email to