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. From-SVN: r128287
This commit is contained in:
parent
97c954f700
commit
cf7c4aa6af
18 changed files with 441 additions and 205 deletions
|
@ -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:
|
||||
|
|
24
gcc/cfgrtl.c
24
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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
24
gcc/cse.c
24
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
27
gcc/gcse.c
27
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;
|
||||
}
|
||||
|
||||
|
|
237
gcc/jump.c
237
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/* 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_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))
|
||||
{
|
||||
/* 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 = find_reg_note (insn, REG_LABEL, NULL_RTX);
|
||||
if (label_note)
|
||||
{
|
||||
/* 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);
|
||||
/* 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)
|
||||
{
|
||||
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_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))))))
|
||||
|
||||
{
|
||||
/* 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,
|
||||
|
@ -919,6 +970,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;
|
||||
|
@ -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. */
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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
|
||||
|
|
35
gcc/reload.c
35
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
37
gcc/reorg.c
37
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
|
||||
|
|
10
gcc/rtl.h
10
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) \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue