builtins: Move the character difference into result instead of reassigning result...
authorXi Ruoyao <xry111@xry111.site>
Wed, 15 Mar 2023 07:34:52 +0000 (15:34 +0800)
committerXi Ruoyao <xry111@xry111.site>
Wed, 15 Mar 2023 09:28:13 +0000 (17:28 +0800)
expand_simple_binop() is allowed to allocate a new pseudo-register and
return it, instead of forcing the result into the provided
pseudo-register.  This can cause a problem when we expand the unrolled
loop for __builtin_strcmp: the compiler always generates code for all n
iterations of the loop, so "result" will be an alias of the
pseudo-register allocated and used in the last iteration; but at runtime
the loop can break early, causing this pseudo-register uninitialized.

Emit a move instruction in the iteration to force the difference into
one register which has been allocated before the loop, to avoid this
issue.

gcc/ChangeLog:

PR other/109086
* builtins.cc (inline_string_cmp): Force the character
difference into "result" pseudo-register, instead of reassign
the pseudo-register.

gcc/builtins.cc

index 305c65c..90246e2 100644 (file)
@@ -7142,8 +7142,16 @@ 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);
+
+      /* Force the difference into result register.  We cannot reassign
+        result here ("result = diff") or we may end up returning
+        uninitialized result when expand_simple_binop allocates a new
+        pseudo-register for returning.  */
+      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);