https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70467
--- Comment #7 from Jakub Jelinek <jakub at gcc dot gnu.org> --- That is correct expectation, but the problem is that no pass that uses it actually manages to update the insn. As I said earlier, the combiner doesn't trigger, because there is just a single insn, nothing to combine. And CSE only triggers for & 0 and similar (which turns it into mem = 0), but doesn't trigger for the case where we would want a no-op move. There are two reasons for that. One is PR35258, which wants to avoid overlapping sets, but doesn't consider noop moves to be fine. And then, most of the architectures actually don't allow MEM to MEM moves, so even if we get through that, we don't validate the changes. The following untested patch fixes that: --- gcc/cse.c.jj 2016-02-17 11:40:19.000000000 +0100 +++ gcc/cse.c 2016-03-31 14:42:27.104824253 +0200 @@ -5166,7 +5166,7 @@ cse_insn (rtx_insn *insn) } /* Avoid creation of overlapping memory moves. */ - if (MEM_P (trial) && MEM_P (SET_DEST (sets[i].rtl))) + if (MEM_P (trial) && MEM_P (dest) && !rtx_equal_p (trial, dest)) { rtx src, dest; @@ -5277,6 +5277,20 @@ cse_insn (rtx_insn *insn) break; } + /* Similarly, lots of targets don't allow no-op + (set (mem x) (mem x)) moves. */ + else if (n_sets == 1 + && MEM_P (trial) + && MEM_P (dest) + && rtx_equal_p (trial, dest) + && !side_effects_p (dest) + && (cfun->can_delete_dead_exceptions + || insn_nothrow_p (insn))) + { + SET_SRC (sets[i].rtl) = trial; + break; + } + /* Reject certain invalid forms of CONST that we create. */ else if (CONSTANT_P (trial) && GET_CODE (trial) == CONST @@ -5495,6 +5509,21 @@ cse_insn (rtx_insn *insn) sets[i].rtl = 0; } + /* Similarly for no-op MEM moves. */ + else if (n_sets == 1 + && MEM_P (SET_DEST (sets[i].rtl)) + && MEM_P (SET_SRC (sets[i].rtl)) + && rtx_equal_p (SET_DEST (sets[i].rtl), + SET_SRC (sets[i].rtl)) + && !side_effects_p (SET_DEST (sets[i].rtl)) + && (cfun->can_delete_dead_exceptions || insn_nothrow_p (insn))) + { + if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn)) + cse_cfg_altered = true; + delete_insn_and_edges (insn); + sets[i].rtl = 0; + } + /* If this SET is now setting PC to a label, we know it used to be a conditional or computed branch. */ else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF