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

Reply via email to