diff options
author | hp <hp@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-09-09 04:41:58 +0000 |
---|---|---|
committer | hp <hp@138bc75d-0d04-0410-961f-82ee72b054a4> | 2007-09-09 04:41:58 +0000 |
commit | 19d2fe05f138cae2ed1b7b42d8e03e8e36e44496 (patch) | |
tree | 23db0441b293cca445046c70fba12a335a0c4ff2 | |
parent | 9f32756fa3cfdb8d3c94bb80e45b326ebdeecf5f (diff) | |
download | gcc-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/ChangeLog | 72 | ||||
-rw-r--r-- | gcc/cfgrtl.c | 24 | ||||
-rw-r--r-- | gcc/combine.c | 36 | ||||
-rw-r--r-- | gcc/config/alpha/alpha.md | 12 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 24 | ||||
-rw-r--r-- | gcc/cse.c | 24 | ||||
-rw-r--r-- | gcc/doc/rtl.texi | 40 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 10 | ||||
-rw-r--r-- | gcc/gcse.c | 27 | ||||
-rw-r--r-- | gcc/jump.c | 233 | ||||
-rw-r--r-- | gcc/print-rtl.c | 3 | ||||
-rw-r--r-- | gcc/reg-notes.def | 14 | ||||
-rw-r--r-- | gcc/reload.c | 35 | ||||
-rw-r--r-- | gcc/reload1.c | 13 | ||||
-rw-r--r-- | gcc/reorg.c | 37 | ||||
-rw-r--r-- | gcc/rtl.h | 10 | ||||
-rw-r--r-- | gcc/rtlanal.c | 6 | ||||
-rw-r--r-- | gcc/sched-rgn.c | 22 |
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; } |