OSDN Git Service

Add missing ChangeLog entries.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 6a4604d..36997cd 100644 (file)
@@ -1,6 +1,6 @@
 /* Emit RTL for the GCC expander.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -837,6 +837,22 @@ gen_rtvec_v (int n, rtx *argp)
   return rt_val;
 }
 \f
+/* Return the number of bytes between the start of an OUTER_MODE
+   in-memory value and the start of an INNER_MODE in-memory value,
+   given that the former is a lowpart of the latter.  It may be a
+   paradoxical lowpart, in which case the offset will be negative
+   on big-endian targets.  */
+
+int
+byte_lowpart_offset (enum machine_mode outer_mode,
+                    enum machine_mode inner_mode)
+{
+  if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode))
+    return subreg_lowpart_offset (outer_mode, inner_mode);
+  else
+    return -subreg_lowpart_offset (inner_mode, outer_mode);
+}
+\f
 /* Generate a REG rtx for a new pseudo register of mode MODE.
    This pseudo is assigned the next sequential register number.  */
 
@@ -891,101 +907,18 @@ gen_reg_rtx (enum machine_mode mode)
   return val;
 }
 
-/* Update NEW with the same attributes as REG, but offsetted by OFFSET.
-   Do the big endian correction if needed.  */
+/* Update NEW with the same attributes as REG, but with OFFSET added
+   to the REG_OFFSET.  */
 
 static void
 update_reg_offset (rtx new, rtx reg, int offset)
 {
-  tree decl;
-  HOST_WIDE_INT var_size;
-
-  /* PR middle-end/14084
-     The problem appears when a variable is stored in a larger register
-     and later it is used in the original mode or some mode in between
-     or some part of variable is accessed.
-
-     On little endian machines there is no problem because
-     the REG_OFFSET of the start of the variable is the same when
-     accessed in any mode (it is 0).
-
-     However, this is not true on big endian machines.
-     The offset of the start of the variable is different when accessed
-     in different modes.
-     When we are taking a part of the REG we have to change the OFFSET
-     from offset WRT size of mode of REG to offset WRT size of variable.
-
-     If we would not do the big endian correction the resulting REG_OFFSET
-     would be larger than the size of the DECL.
-
-     Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine:
-
-     REG.mode  MODE  DECL size  old offset  new offset  description
-     DI        SI    4          4           0           int32 in SImode
-     DI        SI    1          4           0           char in SImode
-     DI        QI    1          7           0           char in QImode
-     DI        QI    4          5           1           1st element in QImode
-                                                        of char[4]
-     DI        HI    4          6           2           1st element in HImode
-                                                        of int16[2]
-
-     If the size of DECL is equal or greater than the size of REG
-     we can't do this correction because the register holds the
-     whole variable or a part of the variable and thus the REG_OFFSET
-     is already correct.  */
-
-  decl = REG_EXPR (reg);
-  if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN)
-      && decl != NULL
-      && offset > 0
-      && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (GET_MODE (new))
-      && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0
-         && var_size < GET_MODE_SIZE (GET_MODE (reg))))
-    {
-      int offset_le;
-
-      /* Convert machine endian to little endian WRT size of mode of REG.  */
-      if (WORDS_BIG_ENDIAN)
-       offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
-                    / UNITS_PER_WORD) * UNITS_PER_WORD;
-      else
-       offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
-
-      if (BYTES_BIG_ENDIAN)
-       offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset)
-                     % UNITS_PER_WORD);
-      else
-       offset_le += offset % UNITS_PER_WORD;
-
-      if (offset_le >= var_size)
-       {
-         /* MODE is wider than the variable so the new reg will cover
-            the whole variable so the resulting OFFSET should be 0.  */
-         offset = 0;
-       }
-      else
-       {
-         /* Convert little endian to machine endian WRT size of variable.  */
-         if (WORDS_BIG_ENDIAN)
-           offset = ((var_size - 1 - offset_le)
-                     / UNITS_PER_WORD) * UNITS_PER_WORD;
-         else
-           offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD;
-
-         if (BYTES_BIG_ENDIAN)
-           offset += ((var_size - 1 - offset_le)
-                      % UNITS_PER_WORD);
-         else
-           offset += offset_le % UNITS_PER_WORD;
-       }
-    }
-
   REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
                                   REG_OFFSET (reg) + offset);
 }
 
-/* Generate a register with same attributes as REG, but offsetted by
-   OFFSET.  */
+/* Generate a register with same attributes as REG, but with OFFSET
+   added to the REG_OFFSET.  */
 
 rtx
 gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
@@ -998,7 +931,7 @@ gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno,
 }
 
 /* Generate a new pseudo-register with the same attributes as REG, but
-   offsetted by OFFSET.  */
+   with OFFSET added to the REG_OFFSET.  */
 
 rtx
 gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
@@ -1009,14 +942,30 @@ gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset)
   return new;
 }
 
-/* Set the decl for MEM to DECL.  */
+/* Adjust REG in-place so that it has mode MODE.  It is assumed that the
+   new register is a (possibly paradoxical) lowpart of the old one.  */
 
 void
-set_reg_attrs_from_mem (rtx reg, rtx mem)
+adjust_reg_mode (rtx reg, enum machine_mode mode)
 {
-  if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+  update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg)));
+  PUT_MODE (reg, mode);
+}
+
+/* Copy REG's attributes from X, if X has any attributes.  If REG and X
+   have different modes, REG is a (possibly paradoxical) lowpart of X.  */
+
+void
+set_reg_attrs_from_value (rtx reg, rtx x)
+{
+  int offset;
+
+  offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x));
+  if (MEM_P (x) && MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT)
     REG_ATTRS (reg)
-      = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem)));
+      = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset);
+  if (REG_P (x) && REG_ATTRS (x))
+    update_reg_offset (reg, x, offset);
 }
 
 /* Set the register attributes for registers contained in PARM_RTX.
@@ -1026,7 +975,7 @@ void
 set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
 {
   if (REG_P (parm_rtx))
-    set_reg_attrs_from_mem (parm_rtx, mem);
+    set_reg_attrs_from_value (parm_rtx, mem);
   else if (GET_CODE (parm_rtx) == PARALLEL)
     {
       /* Check for a NULL entry in the first slot, used to indicate that the
@@ -1043,54 +992,21 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem)
     }
 }
 
-/* Assign the RTX X to declaration T.  */
-void
-set_decl_rtl (tree t, rtx x)
-{
-  DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
+/* Set the REG_ATTRS for registers in value X, given that X represents
+   decl T.  */
 
-  if (!x)
-    return;
-  /* For register, we maintain the reverse information too.  */
-  if (REG_P (x))
-    REG_ATTRS (x) = get_reg_attrs (t, 0);
-  else if (GET_CODE (x) == SUBREG)
-    REG_ATTRS (SUBREG_REG (x))
-      = get_reg_attrs (t, -SUBREG_BYTE (x));
-  if (GET_CODE (x) == CONCAT)
-    {
-      if (REG_P (XEXP (x, 0)))
-        REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0);
-      if (REG_P (XEXP (x, 1)))
-       REG_ATTRS (XEXP (x, 1))
-         = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0))));
-    }
-  if (GET_CODE (x) == PARALLEL)
+static void
+set_reg_attrs_for_decl_rtl (tree t, rtx x)
+{
+  if (GET_CODE (x) == SUBREG)
     {
-      int i;
-      for (i = 0; i < XVECLEN (x, 0); i++)
-       {
-         rtx y = XVECEXP (x, 0, i);
-         if (REG_P (XEXP (y, 0)))
-           REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1)));
-       }
+      gcc_assert (subreg_lowpart_p (x));
+      x = SUBREG_REG (x);
     }
-}
-
-/* Assign the RTX X to parameter declaration T.  */
-void
-set_decl_incoming_rtl (tree t, rtx x)
-{
-  DECL_INCOMING_RTL (t) = x;
-
-  if (!x)
-    return;
-  /* For register, we maintain the reverse information too.  */
   if (REG_P (x))
-    REG_ATTRS (x) = get_reg_attrs (t, 0);
-  else if (GET_CODE (x) == SUBREG)
-    REG_ATTRS (SUBREG_REG (x))
-      = get_reg_attrs (t, -SUBREG_BYTE (x));
+    REG_ATTRS (x)
+      = get_reg_attrs (t, byte_lowpart_offset (GET_MODE (x),
+                                              DECL_MODE (t)));
   if (GET_CODE (x) == CONCAT)
     {
       if (REG_P (XEXP (x, 0)))
@@ -1119,6 +1035,27 @@ set_decl_incoming_rtl (tree t, rtx x)
     }
 }
 
+/* Assign the RTX X to declaration T.  */
+
+void
+set_decl_rtl (tree t, rtx x)
+{
+  DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x;
+  if (x)
+    set_reg_attrs_for_decl_rtl (t, x);
+}
+
+/* Assign the RTX X to parameter declaration T.  BY_REFERENCE_P is true
+   if the ABI requires the parameter to be passed by reference.  */
+
+void
+set_decl_incoming_rtl (tree t, rtx x, bool by_reference_p)
+{
+  DECL_INCOMING_RTL (t) = x;
+  if (x && !by_reference_p)
+    set_reg_attrs_for_decl_rtl (t, x);
+}
+
 /* Identify REG (which may be a CONCAT) as a user register.  */
 
 void
@@ -1304,8 +1241,7 @@ gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx
                              subreg_highpart_offset (outermode, innermode));
 }
 
-/* Return offset in bytes to get OUTERMODE low part
-   of the value in mode INNERMODE stored in memory in target format.  */
+/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value.  */
 
 unsigned int
 subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode)
@@ -1796,7 +1732,7 @@ set_mem_attributes (rtx ref, tree t, int objectp)
   set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
 }
 
-/* Set the decl for MEM to DECL.  */
+/* Set MEM to the decl that REG refers to.  */
 
 void
 set_mem_attrs_from_reg (rtx mem, rtx reg)
@@ -2258,7 +2194,7 @@ struct tree_opt_pass pass_unshare_all_rtl =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
-  TODO_dump_func,                       /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_rtl_sharing, /* todo_flags_finish */
   0                                     /* letter */
 };
 
@@ -2441,7 +2377,7 @@ set_used_decls (tree blk)
       set_used_flags (DECL_RTL (t));
 
   /* Now process sub-blocks.  */
-  for (t = BLOCK_SUBBLOCKS (blk); t; t = TREE_CHAIN (t))
+  for (t = BLOCK_SUBBLOCKS (blk); t; t = BLOCK_CHAIN (t))
     set_used_decls (t);
 }
 
@@ -2865,169 +2801,103 @@ get_max_uid (void)
 /* Return the next insn.  If it is a SEQUENCE, return the first insn
    of the sequence.  */
 
-#define NEXT_INSN_BODY do { \
-  if (insn) \
-    { \
-      insn = NEXT_INSN (insn); \
-      if (insn && NONJUMP_INSN_P (insn) \
-         && GET_CODE (PATTERN (insn)) == SEQUENCE) \
-       insn = XVECEXP (PATTERN (insn), 0, 0); \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 next_insn (rtx insn)
 {
-  NEXT_INSN_BODY;
-}
+  if (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn && NONJUMP_INSN_P (insn)
+         && GET_CODE (PATTERN (insn)) == SEQUENCE)
+       insn = XVECEXP (PATTERN (insn), 0, 0);
+    }
 
-const_rtx
-const_next_insn (const_rtx insn)
-{
-  NEXT_INSN_BODY;
+  return insn;
 }
 
-#undef NEXT_INSN_BODY
-
 /* Return the previous insn.  If it is a SEQUENCE, return the last insn
    of the sequence.  */
 
-#define PREVIOUS_INSN_BODY do { \
-  if (insn) \
-    { \
-      insn = PREV_INSN (insn); \
-      if (insn && NONJUMP_INSN_P (insn) \
-         && GET_CODE (PATTERN (insn)) == SEQUENCE) \
-       insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1); \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 previous_insn (rtx insn)
 {
-  PREVIOUS_INSN_BODY;
-}
+  if (insn)
+    {
+      insn = PREV_INSN (insn);
+      if (insn && NONJUMP_INSN_P (insn)
+         && GET_CODE (PATTERN (insn)) == SEQUENCE)
+       insn = XVECEXP (PATTERN (insn), 0, XVECLEN (PATTERN (insn), 0) - 1);
+    }
 
-const_rtx
-const_previous_insn (const_rtx insn)
-{
-  PREVIOUS_INSN_BODY;
+  return insn;
 }
 
-#undef PREVIOUS_INSN_BODY
-
 /* Return the next insn after INSN that is not a NOTE.  This routine does not
    look inside SEQUENCEs.  */
 
-#define NEXT_NONNOTE_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = NEXT_INSN (insn); \
-      if (insn == 0 || !NOTE_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 next_nonnote_insn (rtx insn)
 {
-  NEXT_NONNOTE_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0 || !NOTE_P (insn))
+       break;
+    }
 
-const_rtx
-const_next_nonnote_insn (const_rtx insn)
-{
-  NEXT_NONNOTE_INSN_BODY;
+  return insn;
 }
 
-#undef NEXT_NONNOTE_INSN_BODY
-
 /* Return the previous insn before INSN that is not a NOTE.  This routine does
    not look inside SEQUENCEs.  */
 
-#define PREV_NONNOTE_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = PREV_INSN (insn); \
-      if (insn == 0 || !NOTE_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 prev_nonnote_insn (rtx insn)
 {
-  PREV_NONNOTE_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = PREV_INSN (insn);
+      if (insn == 0 || !NOTE_P (insn))
+       break;
+    }
 
-const_rtx
-const_prev_nonnote_insn (const_rtx insn)
-{
-  PREV_NONNOTE_INSN_BODY;
+  return insn;
 }
 
-#undef PREV_NONNOTE_INSN_BODY
-
 /* Return the next INSN, CALL_INSN or JUMP_INSN after INSN;
    or 0, if there is none.  This routine does not look inside
    SEQUENCEs.  */
 
-#define NEXT_REAL_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = NEXT_INSN (insn); \
-      if (insn == 0 || INSN_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 next_real_insn (rtx insn)
 {
-  NEXT_REAL_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0 || INSN_P (insn))
+       break;
+    }
 
-const_rtx
-const_next_real_insn (const_rtx insn)
-{
-  NEXT_REAL_INSN_BODY;
+  return insn;
 }
 
-#undef NEXT_REAL_INSN_BODY
-
 /* Return the last INSN, CALL_INSN or JUMP_INSN before INSN;
    or 0, if there is none.  This routine does not look inside
    SEQUENCEs.  */
 
-#define PREV_REAL_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = PREV_INSN (insn); \
-      if (insn == 0 || INSN_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 prev_real_insn (rtx insn)
 {
-  PREV_REAL_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = PREV_INSN (insn);
+      if (insn == 0 || INSN_P (insn))
+       break;
+    }
 
-const_rtx
-const_prev_real_insn (const_rtx insn)
-{
-  PREV_REAL_INSN_BODY;
+  return insn;
 }
 
-#undef PREV_REAL_INSN_BODY
-
 /* Return the last CALL_INSN in the current list, or 0 if there is none.
    This routine does not look inside SEQUENCEs.  */
 
@@ -3058,110 +2928,66 @@ active_insn_p (const_rtx insn)
                      && GET_CODE (PATTERN (insn)) != CLOBBER))));
 }
 
-#define NEXT_ACTIVE_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = NEXT_INSN (insn); \
-      if (insn == 0 || active_insn_p (insn)) \
-       break; \
-    } \
-  return insn;\
-} while (0)
-
 rtx
 next_active_insn (rtx insn)
 {
-  NEXT_ACTIVE_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0 || active_insn_p (insn))
+       break;
+    }
 
-const_rtx
-const_next_active_insn (const_rtx insn)
-{
-  NEXT_ACTIVE_INSN_BODY;
+  return insn;
 }
 
-#undef NEXT_ACTIVE_INSN_BODY
-
 /* Find the last insn before INSN that really does something.  This routine
    does not look inside SEQUENCEs.  Until reload has completed, this is the
    same as prev_real_insn.  */
 
-#define PREV_ACTIVE_INSN_BODY do { \
-  while (insn) \
-    { \
-      insn = PREV_INSN (insn);\
-      if (insn == 0 || active_insn_p (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 prev_active_insn (rtx insn)
 {
-  PREV_ACTIVE_INSN_BODY;
-}
+  while (insn)
+    {
+      insn = PREV_INSN (insn);
+      if (insn == 0 || active_insn_p (insn))
+       break;
+    }
 
-const_rtx
-const_prev_active_insn (const_rtx insn)
-{
-  PREV_ACTIVE_INSN_BODY;
+  return insn;
 }
 
-#undef PREV_ACTIVE_INSN_BODY
-
 /* Return the next CODE_LABEL after the insn INSN, or 0 if there is none.  */
 
-#define NEXT_LABEL_BODY do { \
-  while (insn) \
-    { \
-      insn = NEXT_INSN (insn); \
-      if (insn == 0 || LABEL_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 next_label (rtx insn)
 {
-  NEXT_LABEL_BODY;
-}
+  while (insn)
+    {
+      insn = NEXT_INSN (insn);
+      if (insn == 0 || LABEL_P (insn))
+       break;
+    }
 
-const_rtx
-const_next_label (const_rtx insn)
-{
-  NEXT_LABEL_BODY;
+  return insn;
 }
 
-#undef NEXT_LABEL_BODY
-
 /* Return the last CODE_LABEL before the insn INSN, or 0 if there is none.  */
 
-#define PREV_LABEL_BODY do { \
-  while (insn) \
-    { \
-      insn = PREV_INSN (insn); \
-      if (insn == 0 || LABEL_P (insn)) \
-       break; \
-    } \
-  return insn; \
-} while (0)
-
 rtx
 prev_label (rtx insn)
 {
-  PREV_LABEL_BODY;
-}
+  while (insn)
+    {
+      insn = PREV_INSN (insn);
+      if (insn == 0 || LABEL_P (insn))
+       break;
+    }
 
-const_rtx
-const_prev_label (const_rtx insn)
-{
-  PREV_LABEL_BODY;
+  return insn;
 }
 
-#undef PREV_LABEL_BODY
-
 /* Return the last label to mark the same position as LABEL.  Return null
    if LABEL itself is null.  */
 
@@ -3310,7 +3136,7 @@ try_split (rtx pat, rtx trial, int last)
   rtx before = PREV_INSN (trial);
   rtx after = NEXT_INSN (trial);
   int has_barrier = 0;
-  rtx tem, note_retval;
+  rtx tem, note_retval, note_libcall;
   rtx note, seq;
   int probability;
   rtx insn_last, insn;
@@ -3458,6 +3284,18 @@ try_split (rtx pat, rtx trial, int last)
          XEXP (note_retval, 0) = insn_last;
          break;
 
+       case REG_RETVAL:
+         /* Relink the insns with REG_LIBCALL note and with REG_RETVAL note
+            after split.  */
+         REG_NOTES (insn_last) 
+           = gen_rtx_INSN_LIST (REG_RETVAL,
+                                XEXP (note, 0),
+                                REG_NOTES (insn_last)); 
+
+         note_libcall = find_reg_note (XEXP (note, 0), REG_LIBCALL, NULL);
+         XEXP (note_libcall, 0) = insn_last;
+         break;
+
        default:
          break;
        }
@@ -3465,11 +3303,12 @@ try_split (rtx pat, rtx trial, int last)
 
   /* If there are LABELS inside the split insns increment the
      usage count so we don't delete the label.  */
-  if (NONJUMP_INSN_P (trial))
+  if (INSN_P (trial))
     {
       insn = insn_last;
       while (insn != NULL_RTX)
        {
+         /* JUMP_P insns have already been "marked" above.  */
          if (NONJUMP_INSN_P (insn))
            mark_label_nuses (PATTERN (insn));
 
@@ -4694,11 +4533,7 @@ emit_note (enum insn_note kind)
 void
 force_next_line_note (void)
 {
-#ifdef USE_MAPPED_LOCATION
   last_location = -1;
-#else
-  last_location.line = -1;
-#endif
 }
 
 /* Place a note of KIND on insn INSN with DATUM as the datum. If a
@@ -5639,10 +5474,11 @@ emit_copy_of_insn_after (rtx insn, rtx after)
      which may be duplicated by the basic block reordering code.  */
   RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
 
-  /* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
-     make them.  */
+  /* Copy all REG_NOTES except REG_LABEL_OPERAND since mark_jump_label
+     will make them.  REG_LABEL_TARGETs are created there too, but are
+     supposed to be sticky, so we copy them.  */
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
-    if (REG_NOTE_KIND (link) != REG_LABEL)
+    if (REG_NOTE_KIND (link) != REG_LABEL_OPERAND)
       {
        if (GET_CODE (link) == EXPR_LIST)
          REG_NOTES (new)