summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>2007-09-09 04:41:58 +0000
committerhp <hp@138bc75d-0d04-0410-961f-82ee72b054a4>2007-09-09 04:41:58 +0000
commit19d2fe05f138cae2ed1b7b42d8e03e8e36e44496 (patch)
tree23db0441b293cca445046c70fba12a335a0c4ff2
parent9f32756fa3cfdb8d3c94bb80e45b326ebdeecf5f (diff)
downloadgcc-19d2fe05f138cae2ed1b7b42d8e03e8e36e44496.tar.gz
Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET.
* doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn. Similar for what label_refs can go in the JUMP_TARGET field. Split REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND. * reload.c (find_reloads): Generate REG_LABEL_OPERAND, not REG_LABEL when replacing an operand with a LABEL_REF for a non-jump insn. (subst_reloads): When replacing a LABEL_REG with a register, instead of generating a REG_LABEL note, assert that there already is one or that the label is a known target for the insn. * rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL note, check the JUMP_LABEL field. Remove "else" after return. * reorg.c (emit_delay_sequence): Replace case for REG_LABEL with cases for REG_LABEL_OPERAND and REG_LABEL_TARGET. (fill_slots_from_thread): Handle both REG_LABEL_OPERAND and REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P insns. Iterate over all notes; don't assume there's only one. * cse.c (recorded_label_ref): Adjust comment to refer to REG_LABEL_OPERAND. (cse_extended_basic_block): Do LABEL_REF check for all INSN_P insns, not just NONJUMP_INSN_P. (check_for_label_ref): For JUMP_P insns, check that the LABEL_REF isn't a jump target. * jump.c (rebuild_jump_labels): Adjust head comment. (init_label_info): Ditto. Remove REG_LABEL_OPERAND notes only; don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field. (mark_all_labels): For JUMP_P insns without a target, check if the the target is noted on the previous nonjump insn. (mark_jump_label_1): New function, guts from mark_jump_label. <case IF_THEN_ELSE>: Handle first operand as a non-target when marking jump target labels. <case LABEL_REF>: Adjust for whether to generate a REG_LABEL_TARGET or a REG_LABEL_OPERAND note. For 'E' format rtl, iterate in descending element order. (delete_related_insns): Handle both REG_LABEL_TARGET and REG_LABEL_OPERAND notes. For JUMP_P insns with labels with zero reference count, delete and fallthrough. Move finding-next- non-deleted insn last in the function. Look at all INSN_P insns for REG_LABEL_OPERAND notes. (redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of JUMP. * print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL JUMP_LABEL, output the INSN_UID of it. * gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND and/or REG_LABEL_TARGET. (add_label_notes): Only add REG_LABEL_OPERAND notes. Put in line with jump.c copy by only adding notes for labels actually referenced in the insn. * emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need usage count increment; handle all INSN_P trial insns. (emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND notes. * rtl.h (struct rtx_def) <volatil>: Adjust to mention REG_LABEL_TARGET and REG_LABEL_OPERAND. (LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and REG_LABEL_OPERAND. * combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on JUMP_P insns and REG_LABEL_OPERAND everywhere. * sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS on all INSN_P insns. * reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL. * cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and REG_LABEL_OPERAND notes. * reload1.c (calculate_needs_all_insns): Adjust comments. (set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes. * config/alpha/alpha.md (split for load of an address into a four-insn sequence on Unicos/Mk): Adjust to use REG_LABEL_OPERAND. * config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128287 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog72
-rw-r--r--gcc/cfgrtl.c24
-rw-r--r--gcc/combine.c36
-rw-r--r--gcc/config/alpha/alpha.md12
-rw-r--r--gcc/config/sh/sh.c24
-rw-r--r--gcc/cse.c24
-rw-r--r--gcc/doc/rtl.texi40
-rw-r--r--gcc/emit-rtl.c10
-rw-r--r--gcc/gcse.c27
-rw-r--r--gcc/jump.c233
-rw-r--r--gcc/print-rtl.c3
-rw-r--r--gcc/reg-notes.def14
-rw-r--r--gcc/reload.c35
-rw-r--r--gcc/reload1.c13
-rw-r--r--gcc/reorg.c37
-rw-r--r--gcc/rtl.h10
-rw-r--r--gcc/rtlanal.c6
-rw-r--r--gcc/sched-rgn.c22
18 files changed, 439 insertions, 203 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 212a56debaf..6f3056329b9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,75 @@
+2007-09-09 Hans-Peter Nilsson <hp@axis.com>
+
+ Divide REG_LABEL notes into REG_LABEL_OPERAND and REG_LABEL_TARGET.
+ * doc/rtl.texi (Insns): Specify when a label_ref makes a jump_insn.
+ Similar for what label_refs can go in the JUMP_TARGET field. Split
+ REG_LABEL documentation into REG_LABEL_TARGET and REG_LABEL_OPERAND.
+ * reload.c (find_reloads): Generate REG_LABEL_OPERAND, not
+ REG_LABEL when replacing an operand with a LABEL_REF for a
+ non-jump insn.
+ (subst_reloads): When replacing a LABEL_REG with a register,
+ instead of generating a REG_LABEL note, assert that there already
+ is one or that the label is a known target for the insn.
+ * rtlanal.c (computed_jump_p): Instead of looking for a REG_LABEL
+ note, check the JUMP_LABEL field. Remove "else" after return.
+ * reorg.c (emit_delay_sequence): Replace case for REG_LABEL with
+ cases for REG_LABEL_OPERAND and REG_LABEL_TARGET.
+ (fill_slots_from_thread): Handle both REG_LABEL_OPERAND and
+ REG_LABEL_TARGET notes, including the JUMP_TARGET field on JUMP_P
+ insns. Iterate over all notes; don't assume there's only one.
+ * cse.c (recorded_label_ref): Adjust comment to refer to
+ REG_LABEL_OPERAND.
+ (cse_extended_basic_block): Do LABEL_REF check for all INSN_P
+ insns, not just NONJUMP_INSN_P.
+ (check_for_label_ref): For JUMP_P insns, check that the LABEL_REF
+ isn't a jump target.
+ * jump.c (rebuild_jump_labels): Adjust head comment.
+ (init_label_info): Ditto. Remove REG_LABEL_OPERAND notes only;
+ don't reset REG_LABEL_TARGET notes, including the JUMP_LABEL field.
+ (mark_all_labels): For JUMP_P insns without a target, check if the
+ the target is noted on the previous nonjump insn.
+ (mark_jump_label_1): New function, guts from mark_jump_label.
+ <case IF_THEN_ELSE>: Handle first operand as a non-target when
+ marking jump target labels.
+ <case LABEL_REF>: Adjust for whether to generate a
+ REG_LABEL_TARGET or a REG_LABEL_OPERAND note.
+ For 'E' format rtl, iterate in descending element order.
+ (delete_related_insns): Handle both REG_LABEL_TARGET and
+ REG_LABEL_OPERAND notes. For JUMP_P insns with labels with zero
+ reference count, delete and fallthrough. Move finding-next-
+ non-deleted insn last in the function. Look at all INSN_P insns
+ for REG_LABEL_OPERAND notes.
+ (redirect_jump_2): Assert that OLABEL equals the old JUMP_LABEL of
+ JUMP.
+ * print-rtl.c (print_rtx): For JUMP_P insns and a non-NULL
+ JUMP_LABEL, output the INSN_UID of it.
+ * gcse.c: Adjust comments as appropriate to say REG_LABEL_OPERAND
+ and/or REG_LABEL_TARGET.
+ (add_label_notes): Only add REG_LABEL_OPERAND notes. Put in line
+ with jump.c copy by only adding notes for labels actually
+ referenced in the insn.
+ * emit-rtl.c (try_split): Don't assume only NONJUMP_INSN_P need
+ usage count increment; handle all INSN_P trial insns.
+ (emit_copy_of_insn_after): Change to not copy REG_LABEL_OPERAND
+ notes.
+ * rtl.h (struct rtx_def) <volatil>: Adjust to mention
+ REG_LABEL_TARGET and REG_LABEL_OPERAND.
+ (LABEL_REF_NONLOCAL_P): Allow REG_LABEL_TARGET and
+ REG_LABEL_OPERAND.
+ * combine.c (distribute_notes): Adjust for REG_LABEL_TARGET on
+ JUMP_P insns and REG_LABEL_OPERAND everywhere.
+ * sched-rgn.c (is_cfg_nonregular): Check for REG_LABEL_OPERANDS
+ on all INSN_P insns.
+ * reg-notes.def (LABEL_TARGET, LABEL_OPERAND): Split from LABEL.
+ * cfgrtl.c (delete_insn): Adjust to handle REG_LABEL_TARGET and
+ REG_LABEL_OPERAND notes.
+ * reload1.c (calculate_needs_all_insns): Adjust comments.
+ (set_label_offsets): Adjust to look for REG_LABEL_OPERAND notes.
+ * config/alpha/alpha.md (split for load of an address into a
+ four-insn sequence on Unicos/Mk): Adjust to use
+ REG_LABEL_OPERAND.
+ * config/sh/sh.md (sh_reorg, final_prescan_insn): Ditto.
+
2007-09-09 Laurynas Biveinis <laurynas.biveinis@gmail.com>
Revert:
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 33ba86cff14..2893c837051 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -138,15 +138,15 @@ delete_insn (rtx insn)
/* If deleting a jump, decrement the use count of the label. Deleting
the label itself should happen in the normal course of block merging. */
- if (JUMP_P (insn)
- && JUMP_LABEL (insn)
- && LABEL_P (JUMP_LABEL (insn)))
- LABEL_NUSES (JUMP_LABEL (insn))--;
-
- /* Also if deleting an insn that references a label. */
- else
+ if (JUMP_P (insn))
{
- while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != NULL_RTX
+ if (JUMP_LABEL (insn)
+ && LABEL_P (JUMP_LABEL (insn)))
+ LABEL_NUSES (JUMP_LABEL (insn))--;
+
+ /* If there are more targets, remove them too. */
+ while ((note
+ = find_reg_note (insn, REG_LABEL_TARGET, NULL_RTX)) != NULL_RTX
&& LABEL_P (XEXP (note, 0)))
{
LABEL_NUSES (XEXP (note, 0))--;
@@ -154,6 +154,14 @@ delete_insn (rtx insn)
}
}
+ /* Also if deleting any insn that references a label as an operand. */
+ while ((note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX)) != NULL_RTX
+ && LABEL_P (XEXP (note, 0)))
+ {
+ LABEL_NUSES (XEXP (note, 0))--;
+ remove_note (insn, note);
+ }
+
if (JUMP_P (insn)
&& (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC))
diff --git a/gcc/combine.c b/gcc/combine.c
index 133dfbe5433..319c5325870 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -12408,7 +12408,8 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
}
break;
- case REG_LABEL:
+ case REG_LABEL_TARGET:
+ case REG_LABEL_OPERAND:
/* This can show up in several ways -- either directly in the
pattern, or hidden off in the constant pool with (or without?)
a REG_EQUAL note. */
@@ -12431,34 +12432,33 @@ distribute_notes (rtx notes, rtx from_insn, rtx i3, rtx i2, rtx elim_i2,
place = i2;
}
- /* Don't attach REG_LABEL note to a JUMP_INSN. Add
- a JUMP_LABEL instead or decrement LABEL_NUSES. */
- if (place && JUMP_P (place))
+ /* For REG_LABEL_TARGET on a JUMP_P, we prefer to put the note
+ as a JUMP_LABEL or decrement LABEL_NUSES if it's already
+ there. */
+ if (place && JUMP_P (place)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place) == NULL
+ || JUMP_LABEL (place) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place);
if (!label)
JUMP_LABEL (place) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
- place = 0;
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
}
- if (place2 && JUMP_P (place2))
+
+ if (place2 && JUMP_P (place2)
+ && REG_NOTE_KIND (note) == REG_LABEL_TARGET
+ && (JUMP_LABEL (place2) == NULL
+ || JUMP_LABEL (place2) == XEXP (note, 0)))
{
rtx label = JUMP_LABEL (place2);
if (!label)
JUMP_LABEL (place2) = XEXP (note, 0);
- else
- {
- gcc_assert (label == XEXP (note, 0));
- if (LABEL_P (label))
- LABEL_NUSES (label)--;
- }
+ else if (LABEL_P (label))
+ LABEL_NUSES (label)--;
place2 = 0;
}
break;
diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index f381dded9cc..f4f3eb3a8df 100644
--- a/gcc/config/alpha/alpha.md
+++ b/gcc/config/alpha/alpha.md
@@ -5375,9 +5375,9 @@
;; Split the load of an address into a four-insn sequence on Unicos/Mk.
;; Always generate a REG_EQUAL note for the last instruction to facilitate
-;; optimizations. If the symbolic operand is a label_ref, generate REG_LABEL
-;; notes and update LABEL_NUSES because this is not done automatically.
-;; Labels may be incorrectly deleted if we don't do this.
+;; optimizations. If the symbolic operand is a label_ref, generate
+;; REG_LABEL_OPERAND notes and update LABEL_NUSES because this is not done
+;; automatically. Labels may be incorrectly deleted if we don't do this.
;;
;; Describing what the individual instructions do correctly is too complicated
;; so use UNSPECs for each of the three parts of an address.
@@ -5401,11 +5401,11 @@
rtx label;
label = XEXP (operands[1], 0);
- REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (insn1));
- REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (insn2));
- REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (insn3));
LABEL_NUSES (label) += 3;
}
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 927355fb775..ad9dd2263cc 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -4716,8 +4716,8 @@ sh_reorg (void)
mdep_reorg_phase = SH_INSERT_USES_LABELS;
if (TARGET_RELAX)
{
- /* Remove all REG_LABEL notes. We want to use them for our own
- purposes. This works because none of the remaining passes
+ /* Remove all REG_LABEL_OPERAND notes. We want to use them for our
+ own purposes. This works because none of the remaining passes
need to look at them.
??? But it may break in the future. We should use a machine
@@ -4728,7 +4728,8 @@ sh_reorg (void)
{
rtx note;
- while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
+ while ((note = find_reg_note (insn, REG_LABEL_OPERAND,
+ NULL_RTX)) != 0)
remove_note (insn, note);
}
}
@@ -4879,16 +4880,16 @@ sh_reorg (void)
continue;
}
- /* Create a code label, and put it in a REG_LABEL note on
- the insn which sets the register, and on each call insn
- which uses the register. In final_prescan_insn we look
- for the REG_LABEL notes, and output the appropriate label
+ /* Create a code label, and put it in a REG_LABEL_OPERAND note
+ on the insn which sets the register, and on each call insn
+ which uses the register. In final_prescan_insn we look for
+ the REG_LABEL_OPERAND notes, and output the appropriate label
or pseudo-op. */
label = gen_label_rtx ();
- REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
+ REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (link));
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
REG_NOTES (insn));
if (rescan)
{
@@ -4904,7 +4905,8 @@ sh_reorg (void)
|| ((reg2 = sfunc_uses_reg (scan))
&& REGNO (reg2) == REGNO (reg))))
REG_NOTES (scan)
- = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
+ = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, label,
+ REG_NOTES (scan));
}
while (scan != dies);
}
@@ -5405,7 +5407,7 @@ final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
{
rtx note;
- note = find_reg_note (insn, REG_LABEL, NULL_RTX);
+ note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX);
if (note)
{
rtx pattern;
diff --git a/gcc/cse.c b/gcc/cse.c
index c26c6e73efc..7e766611e6e 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -353,8 +353,9 @@ static HARD_REG_SET hard_regs_in_table;
static int cse_jumps_altered;
-/* Nonzero if we put a LABEL_REF into the hash table for an INSN without a
- REG_LABEL, we have to rerun jump after CSE to put in the note. */
+/* Nonzero if we put a LABEL_REF into the hash table for an INSN
+ without a REG_LABEL_OPERAND, we have to rerun jump after CSE to put
+ in the note. */
static int recorded_label_ref;
/* canon_hash stores 1 in do_not_record
@@ -6091,7 +6092,7 @@ cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
/* If we haven't already found an insn where we added a LABEL_REF,
check this one. */
- if (NONJUMP_INSN_P (insn) && ! recorded_label_ref
+ if (INSN_P (insn) && ! recorded_label_ref
&& for_each_rtx (&PATTERN (insn), check_for_label_ref,
(void *) insn))
recorded_label_ref = 1;
@@ -6277,23 +6278,26 @@ cse_main (rtx f ATTRIBUTE_UNUSED, int nregs)
return cse_jumps_altered || recorded_label_ref;
}
-/* Called via for_each_rtx to see if an insn is using a LABEL_REF for which
- there isn't a REG_LABEL note. Return one if so. DATA is the insn. */
+/* Called via for_each_rtx to see if an insn is using a LABEL_REF for
+ which there isn't a REG_LABEL_OPERAND note.
+ Return one if so. DATA is the insn. */
static int
check_for_label_ref (rtx *rtl, void *data)
{
rtx insn = (rtx) data;
- /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
- we must rerun jump since it needs to place the note. If this is a
- LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
- since no REG_LABEL will be added. */
+ /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
+ note for it, we must rerun jump since it needs to place the note. If
+ this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
+ don't do this since no REG_LABEL_OPERAND will be added. */
return (GET_CODE (*rtl) == LABEL_REF
&& ! LABEL_REF_NONLOCAL_P (*rtl)
+ && (!JUMP_P (insn)
+ || !label_is_jump_target_p (XEXP (*rtl, 0), insn))
&& LABEL_P (XEXP (*rtl, 0))
&& INSN_UID (XEXP (*rtl, 0)) != 0
- && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
+ && ! find_reg_note (insn, REG_LABEL_OPERAND, XEXP (*rtl, 0)));
}
/* Count the number of times registers are used (not set) in X.
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 83fa0895d0d..639aabe885a 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -3201,9 +3201,10 @@ mandatory ones listed above. These four are described in a table below.
@findex jump_insn
@item jump_insn
The expression code @code{jump_insn} is used for instructions that may
-jump (or, more generally, may contain @code{label_ref} expressions). If
-there is an instruction to return from the current function, it is
-recorded as a @code{jump_insn}.
+jump (or, more generally, may contain @code{label_ref} expressions to
+which @code{pc} can be set in that instruction). If there is an
+instruction to return from the current function, it is recorded as a
+@code{jump_insn}.
@findex JUMP_LABEL
@code{jump_insn} insns have the same extra fields as @code{insn} insns,
@@ -3213,9 +3214,11 @@ accessed in the same way and in addition contain a field
For simple conditional and unconditional jumps, this field contains
the @code{code_label} to which this insn will (possibly conditionally)
branch. In a more complex jump, @code{JUMP_LABEL} records one of the
-labels that the insn refers to; the only way to find the others is to
-scan the entire body of the insn. In an @code{addr_vec},
-@code{JUMP_LABEL} is @code{NULL_RTX}.
+labels that the insn refers to; other jump target labels are recorded
+as @code{REG_LABEL_TARGET} notes. The exception is @code{addr_vec}
+and @code{addr_diff_vec}, where @code{JUMP_LABEL} is @code{NULL_RTX}
+and the only way to find the labels is to scan the entire body of the
+insn.
Return insns count as jumps, but since they do not refer to any
labels, their @code{JUMP_LABEL} is @code{NULL_RTX}.
@@ -3531,14 +3534,25 @@ note giving the expression being computed. This block is encapsulated
with @code{REG_LIBCALL} and @code{REG_RETVAL} notes on the first and
last insns, respectively.
-@findex REG_LABEL
-@item REG_LABEL
+@findex REG_LABEL_OPERAND
+@item REG_LABEL_OPERAND
This insn uses @var{op}, a @code{code_label} or a @code{note} of type
-@code{NOTE_INSN_DELETED_LABEL}, but is not a
-@code{jump_insn}, or it is a @code{jump_insn} that required the label to
-be held in a register. The presence of this note allows jump
-optimization to be aware that @var{op} is, in fact, being used, and flow
-optimization to build an accurate flow graph.
+@code{NOTE_INSN_DELETED_LABEL}, but is not a @code{jump_insn}, or it
+is a @code{jump_insn} that refers to the operand as an ordinary
+operand. The label may still eventually be a jump target, but if so
+in an indirect jump in a subsequent insn. The presence of this note
+allows jump optimization to be aware that @var{op} is, in fact, being
+used, and flow optimization to build an accurate flow graph.
+
+@findex REG_LABEL_TARGET
+@item REG_LABEL_TARGET
+This insn is a @code{jump_insn} but not a @code{addr_vec} or
+@code{addr_diff_vec}. It uses @var{op}, a @code{code_label} as a
+direct or indirect jump target. Its purpose is similar to that of
+@code{REG_LABEL_OPERAND}. This note is only present if the insn has
+multiple targets; the last label in the insn (in the highest numbered
+insn-field) goes into the @code{JUMP_LABEL} field and does not have a
+@code{REG_LABEL_TARGET} note. @xref{Insns, JUMP_LABEL}.
@findex REG_CROSSING_JUMP
@item REG_CROSSING_JUMP
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index b3f21013a0b..8d1b1c7e85a 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3355,11 +3355,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));
@@ -5529,10 +5530,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)
diff --git a/gcc/gcse.c b/gcc/gcse.c
index b6b7c5e410c..e3ffae0d05c 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -4584,14 +4584,15 @@ one_pre_gcse_pass (int pass)
return changed;
}
-/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN.
- If notes are added to an insn which references a CODE_LABEL, the
- LABEL_NUSES count is incremented. We have to add REG_LABEL notes,
- because the following loop optimization pass requires them. */
+/* If X contains any LABEL_REF's, add REG_LABEL_OPERAND notes for them
+ to INSN. If such notes are added to an insn which references a
+ CODE_LABEL, the LABEL_NUSES count is incremented. We have to add
+ that note, because the following loop optimization pass requires
+ them. */
/* ??? If there was a jump optimization pass after gcse and before loop,
then we would not need to do this here, because jump would add the
- necessary REG_LABEL notes. */
+ necessary REG_LABEL_OPERAND and REG_LABEL_TARGET notes. */
static void
add_label_notes (rtx x, rtx insn)
@@ -4608,10 +4609,18 @@ add_label_notes (rtx x, rtx insn)
We no longer ignore such label references (see LABEL_REF handling in
mark_jump_label for additional information). */
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, XEXP (x, 0),
- REG_NOTES (insn));
- if (LABEL_P (XEXP (x, 0)))
- LABEL_NUSES (XEXP (x, 0))++;
+ if (reg_mentioned_p (XEXP (x, 0), insn))
+ {
+ /* There's no reason for current users to emit jump-insns
+ with such a LABEL_REF, so we don't have to handle
+ REG_LABEL_TARGET notes. */
+ gcc_assert (!JUMP_P (insn));
+ REG_NOTES (insn)
+ = gen_rtx_INSN_LIST (REG_LABEL_OPERAND, XEXP (x, 0),
+ REG_NOTES (insn));
+ if (LABEL_P (XEXP (x, 0)))
+ LABEL_NUSES (XEXP (x, 0))++;
+ }
return;
}
diff --git a/gcc/jump.c b/gcc/jump.c
index cd51764f03a..e62024fbc71 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -67,13 +67,15 @@ along with GCC; see the file COPYING3. If not see
static void init_label_info (rtx);
static void mark_all_labels (rtx);
+static void mark_jump_label_1 (rtx, rtx, bool, bool);
static void redirect_exp_1 (rtx *, rtx, rtx, rtx);
static int invert_exp_1 (rtx, rtx);
static int returnjump_p_1 (rtx *, void *);
-/* Alternate entry into the jump optimizer. This entry point only rebuilds
- the JUMP_LABEL field in jumping insns and REG_LABEL notes in non-jumping
- instructions. */
+/* This function rebuilds the JUMP_LABEL field and REG_LABEL_TARGET
+ notes in jumping insns and REG_LABEL_OPERAND notes in non-jumping
+ instructions and jumping insns that have labels as operands
+ (e.g. cbranchsi4). */
void
rebuild_jump_labels (rtx f)
{
@@ -138,31 +140,43 @@ struct tree_opt_pass pass_cleanup_barriers =
};
-/* Initialize LABEL_NUSES and JUMP_LABEL fields. Delete any REG_LABEL
- notes whose labels don't occur in the insn any more. Returns the
- largest INSN_UID found. */
+/* Initialize LABEL_NUSES and JUMP_LABEL fields, add REG_LABEL_TARGET
+ for remaining targets for JUMP_P. Delete any REG_LABEL_OPERAND
+ notes whose labels don't occur in the insn any more. */
+
static void
init_label_info (rtx f)
{
rtx insn;
for (insn = f; insn; insn = NEXT_INSN (insn))
- if (LABEL_P (insn))
- LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
- else if (JUMP_P (insn))
- JUMP_LABEL (insn) = 0;
- else if (NONJUMP_INSN_P (insn) || CALL_P (insn))
- {
- rtx note, next;
+ {
+ if (LABEL_P (insn))
+ LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+
+ /* REG_LABEL_TARGET notes (including the JUMP_LABEL field) are
+ sticky and not reset here; that way we won't lose association
+ with a label when e.g. the source for a target register
+ disappears out of reach for targets that may use jump-target
+ registers. Jump transformations are supposed to transform
+ any REG_LABEL_TARGET notes. The target label reference in a
+ branch may disappear from the branch (and from the
+ instruction before it) for other reasons, like register
+ allocation. */
+
+ if (INSN_P (insn))
+ {
+ rtx note, next;
- for (note = REG_NOTES (insn); note; note = next)
- {
- next = XEXP (note, 1);
- if (REG_NOTE_KIND (note) == REG_LABEL
- && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- remove_note (insn, note);
- }
- }
+ for (note = REG_NOTES (insn); note; note = next)
+ {
+ next = XEXP (note, 1);
+ if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+ && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ remove_note (insn, note);
+ }
+ }
+ }
}
/* Mark the label each jump jumps to.
@@ -172,34 +186,69 @@ static void
mark_all_labels (rtx f)
{
rtx insn;
+ rtx prev_nonjump_insn = NULL;
for (insn = f; insn; insn = NEXT_INSN (insn))
if (INSN_P (insn))
{
mark_jump_label (PATTERN (insn), insn, 0);
- if (! INSN_DELETED_P (insn) && JUMP_P (insn))
+
+ /* If the previous non-jump insn sets something to a label,
+ something that this jump insn uses, make that label the primary
+ target of this insn if we don't yet have any. That previous
+ insn must be a single_set and not refer to more than one label.
+ The jump insn must not refer to other labels as jump targets
+ and must be a plain (set (pc) ...), maybe in a parallel, and
+ may refer to the item being set only directly or as one of the
+ arms in an IF_THEN_ELSE. */
+ if (! INSN_DELETED_P (insn)
+ && JUMP_P (insn)
+ && JUMP_LABEL (insn) == NULL)
{
- /* When we know the LABEL_REF contained in a REG used in
- an indirect jump, we'll have a REG_LABEL note so that
- flow can tell where it's going. */
- if (JUMP_LABEL (insn) == 0)
+ rtx label_note = NULL;
+ rtx pc = pc_set (insn);
+ rtx pc_src = pc != NULL ? SET_SRC (pc) : NULL;
+
+ if (prev_nonjump_insn != NULL)
+ label_note
+ = find_reg_note (prev_nonjump_insn, REG_LABEL_OPERAND, NULL);
+
+ if (label_note != NULL && pc_src != NULL)
{
- rtx label_note = find_reg_note (insn, REG_LABEL, NULL_RTX);
- if (label_note)
+ rtx label_set = single_set (prev_nonjump_insn);
+ rtx label_dest
+ = label_set != NULL ? SET_DEST (label_set) : NULL;
+
+ if (label_set != NULL
+ /* The source must be the direct LABEL_REF, not a
+ PLUS, UNSPEC, IF_THEN_ELSE etc. */
+ && GET_CODE (SET_SRC (label_set)) == LABEL_REF
+ && (rtx_equal_p (label_dest, pc_src)
+ || (GET_CODE (pc_src) == IF_THEN_ELSE
+ && (rtx_equal_p (label_dest, XEXP (pc_src, 1))
+ || rtx_equal_p (label_dest,
+ XEXP (pc_src, 2))))))
+
{
- /* But a LABEL_REF around the REG_LABEL note, so
- that we can canonicalize it. */
- rtx label_ref = gen_rtx_LABEL_REF (Pmode,
- XEXP (label_note, 0));
-
- mark_jump_label (label_ref, insn, 0);
- XEXP (label_note, 0) = XEXP (label_ref, 0);
- JUMP_LABEL (insn) = XEXP (label_note, 0);
+ /* The CODE_LABEL referred to in the note must be the
+ CODE_LABEL in the LABEL_REF of the "set". We can
+ conveniently use it for the marker function, which
+ requires a LABEL_REF wrapping. */
+ gcc_assert (XEXP (label_note, 0)
+ == XEXP (SET_SRC (label_set), 0));
+
+ mark_jump_label_1 (label_set, insn, false, true);
+ gcc_assert (JUMP_LABEL (insn)
+ == XEXP (SET_SRC (label_set), 0));
}
}
}
+ else if (! INSN_DELETED_P (insn))
+ prev_nonjump_insn = insn;
}
-
+ else if (LABEL_P (insn))
+ prev_nonjump_insn = NULL;
+
/* If we are in cfglayout mode, there may be non-insns between the
basic blocks. If those non-insns represent tablejump data, they
contain label references that we must record. */
@@ -904,12 +953,14 @@ sets_cc0_p (const_rtx x)
}
#endif
-/* Find all CODE_LABELs referred to in X, and increment their use counts.
- If INSN is a JUMP_INSN and there is at least one CODE_LABEL referenced
- in INSN, then store one of them in JUMP_LABEL (INSN).
- If INSN is an INSN or a CALL_INSN and there is at least one CODE_LABEL
- referenced in INSN, add a REG_LABEL note containing that label to INSN.
- Also, when there are consecutive labels, canonicalize on the last of them.
+/* Find all CODE_LABELs referred to in X, and increment their use
+ counts. If INSN is a JUMP_INSN and there is at least one
+ CODE_LABEL referenced in INSN as a jump target, then store the last
+ one in JUMP_LABEL (INSN). For a tablejump, this must be the label
+ for the ADDR_VEC. Store any other jump targets as REG_LABEL_TARGET
+ notes. If INSN is an INSN or a CALL_INSN or non-target operands of
+ a JUMP_INSN, and there is at least one CODE_LABEL referenced in
+ INSN, add a REG_LABEL_OPERAND note containing that label to INSN.
Note that two labels separated by a loop-beginning note
must be kept distinct if we have not yet done loop-optimization,
@@ -920,6 +971,19 @@ sets_cc0_p (const_rtx x)
void
mark_jump_label (rtx x, rtx insn, int in_mem)
{
+ mark_jump_label_1 (x, insn, in_mem != 0,
+ (insn != NULL && x == PATTERN (insn) && JUMP_P (insn)));
+}
+
+/* Worker function for mark_jump_label. IN_MEM is TRUE when X occurrs
+ within a (MEM ...). IS_TARGET is TRUE when X is to be treated as a
+ jump-target; when the JUMP_LABEL field of INSN should be set or a
+ REG_LABEL_TARGET note should be added, not a REG_LABEL_OPERAND
+ note. */
+
+static void
+mark_jump_label_1 (rtx x, rtx insn, bool in_mem, bool is_target)
+{
RTX_CODE code = GET_CODE (x);
int i;
const char *fmt;
@@ -936,7 +1000,7 @@ mark_jump_label (rtx x, rtx insn, int in_mem)
return;
case MEM:
- in_mem = 1;
+ in_mem = true;
break;
case SEQUENCE:
@@ -951,9 +1015,19 @@ mark_jump_label (rtx x, rtx insn, int in_mem)
/* If this is a constant-pool reference, see if it is a label. */
if (CONSTANT_POOL_ADDRESS_P (x))
- mark_jump_label (get_pool_constant (x), insn, in_mem);
+ mark_jump_label_1 (get_pool_constant (x), insn, in_mem, is_target);
break;
+ /* Handle operands in the condition of an if-then-else as for a
+ non-jump insn. */
+ case IF_THEN_ELSE:
+ if (!is_target)
+ break;
+ mark_jump_label_1 (XEXP (x, 0), insn, in_mem, false);
+ mark_jump_label_1 (XEXP (x, 1), insn, in_mem, true);
+ mark_jump_label_1 (XEXP (x, 2), insn, in_mem, true);
+ return;
+
case LABEL_REF:
{
rtx label = XEXP (x, 0);
@@ -976,17 +1050,21 @@ mark_jump_label (rtx x, rtx insn, int in_mem)
if (insn)
{
- if (JUMP_P (insn))
+ if (is_target
+ && (JUMP_LABEL (insn) == NULL || JUMP_LABEL (insn) == label))
JUMP_LABEL (insn) = label;
else
{
- /* Add a REG_LABEL note for LABEL unless there already
- is one. All uses of a label, except for labels
- that are the targets of jumps, must have a
- REG_LABEL note. */
- if (! find_reg_note (insn, REG_LABEL, label))
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
- REG_NOTES (insn));
+ enum reg_note kind
+ = is_target ? REG_LABEL_TARGET : REG_LABEL_OPERAND;
+
+ /* Add a REG_LABEL_OPERAND or REG_LABEL_TARGET note
+ for LABEL unless there already is one. All uses of
+ a label, except for the primary target of a jump,
+ must have such a note. */
+ if (! find_reg_note (insn, kind, label))
+ REG_NOTES (insn)
+ = gen_rtx_INSN_LIST (kind, label, REG_NOTES (insn));
}
}
return;
@@ -1001,7 +1079,8 @@ mark_jump_label (rtx x, rtx insn, int in_mem)
int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
for (i = 0; i < XVECLEN (x, eltnum); i++)
- mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, in_mem);
+ mark_jump_label_1 (XVECEXP (x, eltnum, i), NULL_RTX, in_mem,
+ is_target);
}
return;
@@ -1010,15 +1089,21 @@ mark_jump_label (rtx x, rtx insn, int in_mem)
}
fmt = GET_RTX_FORMAT (code);
+
+ /* The primary target of a tablejump is the label of the ADDR_VEC,
+ which is canonically mentioned *last* in the insn. To get it
+ marked as JUMP_LABEL, we iterate over items in reverse order. */
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- mark_jump_label (XEXP (x, i), insn, in_mem);
+ mark_jump_label_1 (XEXP (x, i), insn, in_mem, is_target);
else if (fmt[i] == 'E')
{
int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- mark_jump_label (XVECEXP (x, i, j), insn, in_mem);
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ mark_jump_label_1 (XVECEXP (x, i, j), insn, in_mem,
+ is_target);
}
}
}
@@ -1062,20 +1147,10 @@ delete_related_insns (rtx insn)
rtx lab = JUMP_LABEL (insn), lab_next;
if (LABEL_NUSES (lab) == 0)
- {
- /* This can delete NEXT or PREV,
- either directly if NEXT is JUMP_LABEL (INSN),
- or indirectly through more levels of jumps. */
- delete_related_insns (lab);
-
- /* I feel a little doubtful about this loop,
- but I see no clean and sure alternative way
- to find the first insn after INSN that is not now deleted.
- I hope this works. */
- while (next && INSN_DELETED_P (next))
- next = NEXT_INSN (next);
- return next;
- }
+ /* This can delete NEXT or PREV,
+ either directly if NEXT is JUMP_LABEL (INSN),
+ or indirectly through more levels of jumps. */
+ delete_related_insns (lab);
else if (tablejump_p (insn, NULL, &lab_next))
{
/* If we're deleting the tablejump, delete the dispatch table.
@@ -1104,10 +1179,12 @@ delete_related_insns (rtx insn)
return next;
}
- /* Likewise for an ordinary INSN / CALL_INSN with a REG_LABEL note. */
- if (NONJUMP_INSN_P (insn) || CALL_P (insn))
+ /* Likewise for any JUMP_P / INSN / CALL_INSN with a
+ REG_LABEL_OPERAND or REG_LABEL_TARGET note. */
+ if (INSN_P (insn))
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_LABEL
+ if ((REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+ || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
/* This could also be a NOTE_INSN_DELETED_LABEL note. */
&& LABEL_P (XEXP (note, 0)))
if (LABEL_NUSES (XEXP (note, 0)) == 0)
@@ -1151,6 +1228,12 @@ delete_related_insns (rtx insn)
}
}
+ /* I feel a little doubtful about this loop,
+ but I see no clean and sure alternative way
+ to find the first insn after INSN that is not now deleted.
+ I hope this works. */
+ while (next && INSN_DELETED_P (next))
+ next = NEXT_INSN (next);
return next;
}
@@ -1307,6 +1390,8 @@ redirect_jump_2 (rtx jump, rtx olabel, rtx nlabel, int delete_unused,
{
rtx note;
+ gcc_assert (JUMP_LABEL (jump) == olabel);
+
/* Negative DELETE_UNUSED used to be used to signalize behavior on
moving FUNCTION_END note. Just sanity check that no user still worry
about this. */
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 3dc8762b355..d77645573f3 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -335,6 +335,9 @@ print_rtx (const_rtx in_rtx)
break;
}
}
+ else if (i == 9 && JUMP_P (in_rtx) && XEXP (in_rtx, i) != NULL)
+ /* Output the JUMP_LABEL reference. */
+ fprintf (outfile, "\n -> %d", INSN_UID (XEXP (in_rtx, i)));
break;
case 'e':
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index a01d8888655..713bc2878e5 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -91,10 +91,16 @@ REG_NOTE (UNUSED)
REG_NOTE (CC_SETTER)
REG_NOTE (CC_USER)
-/* Points to a CODE_LABEL. Used by non-JUMP_INSNs to say that the
- CODE_LABEL contained in the REG_LABEL note is used by the insn.
- This note is an INSN_LIST. */
-REG_NOTE (LABEL)
+/* Points to a CODE_LABEL. Used by JUMP_INSNs to say that the CODE_LABEL
+ contained in the REG_LABEL_TARGET note is a possible jump target of
+ this insn. This note is an INSN_LIST. */
+REG_NOTE (LABEL_TARGET)
+
+/* Points to a CODE_LABEL. Used by any insn to say that the CODE_LABEL
+ contained in the REG_LABEL_OPERAND note is used by the insn, but as an
+ operand, not as a jump target (though it may indirectly be a jump
+ target for a later jump insn). This note is an INSN_LIST. */
+REG_NOTE (LABEL_OPERAND)
/* REG_DEP_OUTPUT and REG_DEP_ANTI are used in scheduler dependencies lists
to represent write-after-write and write-after-read dependencies
diff --git a/gcc/reload.c b/gcc/reload.c
index 6eb380202e2..e88a82de7c4 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -4103,13 +4103,18 @@ find_reloads (rtx insn, int replace, int ind_levels, int live_known,
*recog_data.operand_loc[i] = substitution;
- /* If we're replacing an operand with a LABEL_REF, we need
- to make sure that there's a REG_LABEL note attached to
+ /* If we're replacing an operand with a LABEL_REF, we need to
+ make sure that there's a REG_LABEL_OPERAND note attached to
this instruction. */
- if (!JUMP_P (insn)
- && GET_CODE (substitution) == LABEL_REF
- && !find_reg_note (insn, REG_LABEL, XEXP (substitution, 0)))
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
+ if (GET_CODE (substitution) == LABEL_REF
+ && !find_reg_note (insn, REG_LABEL_OPERAND,
+ XEXP (substitution, 0))
+ /* For a JUMP_P, if it was a branch target it must have
+ already been recorded as such. */
+ && (!JUMP_P (insn)
+ || !label_is_jump_target_p (XEXP (substitution, 0),
+ insn)))
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL_OPERAND,
XEXP (substitution, 0),
REG_NOTES (insn));
}
@@ -6123,17 +6128,15 @@ subst_reloads (rtx insn)
}
#endif /* DEBUG_RELOAD */
- /* If we're replacing a LABEL_REF with a register, add a
- REG_LABEL note to indicate to flow which label this
+ /* If we're replacing a LABEL_REF with a register, there must
+ already be an indication (to e.g. flow) which label this
register refers to. */
- if (GET_CODE (*r->where) == LABEL_REF
- && JUMP_P (insn))
- {
- REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL,
- XEXP (*r->where, 0),
- REG_NOTES (insn));
- JUMP_LABEL (insn) = XEXP (*r->where, 0);
- }
+ gcc_assert (GET_CODE (*r->where) != LABEL_REF
+ || !JUMP_P (insn)
+ || find_reg_note (insn,
+ REG_LABEL_OPERAND,
+ XEXP (*r->where, 0))
+ || label_is_jump_target_p (XEXP (*r->where, 0), insn));
/* Encapsulate RELOADREG so its machine mode matches what
used to be there. Note that gen_lowpart_common will
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 31626f57a40..9021050c409 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -1539,8 +1539,8 @@ calculate_needs_all_insns (int global)
chain->need_operand_change = 0;
/* If this is a label, a JUMP_INSN, or has REG_NOTES (which might
- include REG_LABEL), we need to see what effects this has on the
- known offsets at labels. */
+ include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see
+ what effects this has on the known offsets at labels. */
if (LABEL_P (insn) || JUMP_P (insn)
|| (INSN_P (insn) && REG_NOTES (insn) != 0))
@@ -2295,10 +2295,11 @@ set_label_offsets (rtx x, rtx insn, int initial_p)
case INSN:
case CALL_INSN:
- /* Any labels mentioned in REG_LABEL notes can be branched to indirectly
- and hence must have all eliminations at their initial offsets. */
+ /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched
+ to indirectly and hence must have all eliminations at their
+ initial offsets. */
for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1))
- if (REG_NOTE_KIND (tem) == REG_LABEL)
+ if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND)
set_label_offsets (XEXP (tem, 0), insn, 1);
return;
@@ -8049,7 +8050,7 @@ gen_reload (rtx out, rtx in, int opnum, enum reload_type type)
else if (OBJECT_P (in) || GET_CODE (in) == SUBREG)
{
tem = emit_insn (gen_move_insn (out, in));
- /* IN may contain a LABEL_REF, if so add a REG_LABEL note. */
+ /* IN may contain a LABEL_REF, if so add a REG_LABEL_OPERAND note. */
mark_jump_label (in, tem, 0);
}
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 8083c88c9b8..291e1aad3b1 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -541,7 +541,8 @@ emit_delay_sequence (rtx insn, rtx list, int length)
remove_note (tem, note);
break;
- case REG_LABEL:
+ case REG_LABEL_OPERAND:
+ case REG_LABEL_TARGET:
/* Keep the label reference count up to date. */
if (LABEL_P (XEXP (note, 0)))
LABEL_NUSES (XEXP (note, 0)) ++;
@@ -2736,14 +2737,40 @@ fill_slots_from_thread (rtx insn, rtx condition, rtx thread,
/* We are moving this insn, not deleting it. We must
temporarily increment the use count on any referenced
label lest it be deleted by delete_related_insns. */
- note = find_reg_note (trial, REG_LABEL, 0);
- /* REG_LABEL could be NOTE_INSN_DELETED_LABEL too. */
- if (note && LABEL_P (XEXP (note, 0)))
+ for (note = REG_NOTES (trial);
+ note != NULL;
+ note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+ || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+ {
+ /* REG_LABEL_OPERAND could be
+ NOTE_INSN_DELETED_LABEL too. */
+ if (LABEL_P (XEXP (note, 0)))
+ LABEL_NUSES (XEXP (note, 0))++;
+ else
+ gcc_assert (REG_NOTE_KIND (note)
+ == REG_LABEL_OPERAND);
+ }
+ if (JUMP_P (trial) && JUMP_LABEL (trial))
LABEL_NUSES (XEXP (note, 0))++;
delete_related_insns (trial);
- if (note && LABEL_P (XEXP (note, 0)))
+ for (note = REG_NOTES (trial);
+ note != NULL;
+ note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_LABEL_OPERAND
+ || REG_NOTE_KIND (note) == REG_LABEL_TARGET)
+ {
+ /* REG_LABEL_OPERAND could be
+ NOTE_INSN_DELETED_LABEL too. */
+ if (LABEL_P (XEXP (note, 0)))
+ LABEL_NUSES (XEXP (note, 0))--;
+ else
+ gcc_assert (REG_NOTE_KIND (note)
+ == REG_LABEL_OPERAND);
+ }
+ if (JUMP_P (trial) && JUMP_LABEL (trial))
LABEL_NUSES (XEXP (note, 0))--;
}
else
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 0a114c3dbbd..3473fb3c34a 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -265,7 +265,8 @@ struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),
1 in a REG expression if corresponds to a variable declared by the user,
0 for an internally generated temporary.
1 in a SUBREG with a negative value.
- 1 in a LABEL_REF or in a REG_LABEL note for a non-local label.
+ 1 in a LABEL_REF, REG_LABEL_TARGET or REG_LABEL_OPERAND note for a
+ non-local label.
In a SYMBOL_REF, this flag is used for machine-specific purposes. */
unsigned int volatil : 1;
/* 1 in a MEM referring to a field of an aggregate.
@@ -1224,10 +1225,11 @@ do { \
MEM_ATTRS (LHS) = MEM_ATTRS (RHS))
/* 1 if RTX is a label_ref for a nonlocal label. */
-/* Likewise in an expr_list for a reg_label note. */
+/* Likewise in an expr_list for a REG_LABEL_OPERAND or
+ REG_LABEL_TARGET note. */
#define LABEL_REF_NONLOCAL_P(RTX) \
- (RTL_FLAG_CHECK2("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF, \
- REG_LABEL)->volatil)
+ (RTL_FLAG_CHECK3("LABEL_REF_NONLOCAL_P", (RTX), LABEL_REF, \
+ REG_LABEL_OPERAND, REG_LABEL_TARGET)->volatil)
/* 1 if RTX is a code_label that should always be considered to be needed. */
#define LABEL_PRESERVE_P(RTX) \
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index 3c4331e8581..a47c36f0b09 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -2703,9 +2703,11 @@ computed_jump_p (const_rtx insn)
{
rtx pat = PATTERN (insn);
- if (find_reg_note (insn, REG_LABEL, NULL_RTX))
+ /* If we have a JUMP_LABEL set, we're not a computed jump. */
+ if (JUMP_LABEL (insn) != NULL)
return 0;
- else if (GET_CODE (pat) == PARALLEL)
+
+ if (GET_CODE (pat) == PARALLEL)
{
int len = XVECLEN (pat, 0);
int has_use_labelref = 0;
diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c
index 6df5c33ec25..0ca1a472fa3 100644
--- a/gcc/sched-rgn.c
+++ b/gcc/sched-rgn.c
@@ -315,24 +315,20 @@ is_cfg_nonregular (void)
if (current_function_has_exception_handlers ())
return 1;
- /* If we have non-jumping insns which refer to labels, then we consider
- the cfg not well structured. */
+ /* If we have insns which refer to labels as non-jumped-to operands,
+ then we consider the cfg not well structured. */
FOR_EACH_BB (b)
FOR_BB_INSNS (b, insn)
{
- /* Check for labels referred by non-jump insns. */
- if (NONJUMP_INSN_P (insn) || CALL_P (insn))
- {
- rtx note = find_reg_note (insn, REG_LABEL, NULL_RTX);
- if (note
- && ! (JUMP_P (NEXT_INSN (insn))
- && find_reg_note (NEXT_INSN (insn), REG_LABEL,
- XEXP (note, 0))))
- return 1;
- }
+ /* Check for labels referred to but (at least not directly) as
+ jump targets. */
+ if (INSN_P (insn)
+ && find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX))
+ return 1;
+
/* If this function has a computed jump, then we consider the cfg
not well structured. */
- else if (JUMP_P (insn) && computed_jump_p (insn))
+ if (JUMP_P (insn) && computed_jump_p (insn))
return 1;
}