aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorXi Ruoyao <xry111@xry111.site>2023-03-15 15:34:52 +0800
committerXi Ruoyao <xry111@xry111.site>2023-03-15 17:28:13 +0800
commit45641f3a99281bb0a429649741a29c2aace4c63e (patch)
tree15089cf7c6fcf11508ea436428b074301a1cf5a5 /gcc
parent02fcaf412ae9508b75efa9602cd4ac58bc63d6a4 (diff)
downloadgcc-45641f3a99281bb0a429649741a29c2aace4c63e.zip
gcc-45641f3a99281bb0a429649741a29c2aace4c63e.tar.gz
gcc-45641f3a99281bb0a429649741a29c2aace4c63e.tar.bz2
builtins: Move the character difference into result instead of reassigning result [PR109086]
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/builtins.cc12
1 files changed, 10 insertions, 2 deletions
diff --git a/gcc/builtins.cc b/gcc/builtins.cc
index 305c65c..90246e2 100644
--- a/gcc/builtins.cc
+++ b/gcc/builtins.cc
@@ -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);