https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112653
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- We do use the alias oracle in folding memmove: /* If the destination and source do not alias optimize into memcpy as well. */ if ((is_gimple_min_invariant (dest) || TREE_CODE (dest) == SSA_NAME) && (is_gimple_min_invariant (src) || TREE_CODE (src) == SSA_NAME)) { ao_ref destr, srcr; ao_ref_init_from_ptr_and_size (&destr, dest, len); ao_ref_init_from_ptr_and_size (&srcr, src, len); if (!refs_may_alias_p_1 (&destr, &srcr, false)) { tree fn; fn = builtin_decl_implicit (BUILT_IN_MEMCPY); if (!fn) return false; but the issue is that test2 escapes which makes this conflict: # PT = null { D.2775 } (escaped, escaped heap) # ALIGN = 8, MISALIGN = 0 # USE = nonlocal escaped # CLB = nonlocal escaped test2_4 = __builtin_malloc (1000); # PT = nonlocal escaped null test.0_1 = test; __builtin_memmove (test2_4, test.0_1, 1000); it works for char *test, *test3; void copy_test () { char *test2 = __builtin_malloc (1000); __builtin_memmove (test2, test, 1000); __builtin_memmove (test3, test2, 1000); __builtin_free (test2); } where both memmove calls become memcpy. So this isn't asking for better folding but for better pointer analysis I guess.