summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorsteven <steven@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-24 19:15:36 +0000
committersteven <steven@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-24 19:15:36 +0000
commit0b3f0f444150a9e3b64cc963ad1ef6bd44d7a70e (patch)
treef5db0208687505d3114934ff0a9f353f86b4947f /gcc
parent44b28efc77e651970b3e9fe5a0fae2f69de7b542 (diff)
downloadgcc-0b3f0f444150a9e3b64cc963ad1ef6bd44d7a70e.tar.gz
* jump.c (reset_insn_reg_label_operand_notes): New function,
split out from ... (init_label_info): ... here. Reset LABEL_NUSES in cfglayout mode. * cfgcleanup.c (delete_dead_jump_tables_between): New function, split out from ... (delete_dead_jumptables): ... here. Handle cfglayout mode. (cleanup_cfg): Delete dead jump tables in cfglayout mode if an expensive CFG cleanup is called for. * cfgrtl.c (fixup_reorder_chain): Remove BARRIERs from fallthru paths. (cfg_layout_finalize): Delete dead jump tables before re-building the insns chain. * ira.c (ira): Rebuild jump labels *after* deleting unreachable basic blocks, not before. * loop-init.c (rtl_loop_done): Call for an expensive CFG cleanup. * modulo-sched.c (sms_schedule): Do not look for BARRIERs in the insns chain of a scheduling extended basic block, they cannot appear there in cfglayout mode. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205337 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog21
-rw-r--r--gcc/cfgcleanup.c89
-rw-r--r--gcc/cfgrtl.c31
-rw-r--r--gcc/ira.c2
-rw-r--r--gcc/jump.c80
-rw-r--r--gcc/loop-init.c2
-rw-r--r--gcc/modulo-sched.c5
7 files changed, 159 insertions, 71 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 903725782d0..29ac53cb0fd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,24 @@
+2013-11-24 Steven Bosscher <steven@gcc.gnu.org>
+
+ * jump.c (reset_insn_reg_label_operand_notes): New function,
+ split out from ...
+ (init_label_info): ... here. Reset LABEL_NUSES in cfglayout mode.
+ * cfgcleanup.c (delete_dead_jump_tables_between): New function,
+ split out from ...
+ (delete_dead_jumptables): ... here. Handle cfglayout mode.
+ (cleanup_cfg): Delete dead jump tables in cfglayout mode if an
+ expensive CFG cleanup is called for.
+ * cfgrtl.c (fixup_reorder_chain): Remove BARRIERs from fallthru paths.
+ (cfg_layout_finalize): Delete dead jump tables before re-building
+ the insns chain.
+ * ira.c (ira): Rebuild jump labels *after* deleting unreachable
+ basic blocks, not before.
+ * loop-init.c (rtl_loop_done): Call for an expensive CFG cleanup.
+
+ * modulo-sched.c (sms_schedule): Do not look for BARRIERs in the
+ insns chain of a scheduling extended basic block, they cannot appear
+ there in cfglayout mode.
+
2013-11-24 Tobias Burnus <burnus@net-b.de>
* doc/invoke.texi (-fsanitize=leak): Add link to the wiki page.
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 234e5b64fe7..e909b03253d 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -2944,40 +2944,65 @@ delete_unreachable_blocks (void)
return changed;
}
+
+/* Look for, and delete, any dead jumptables between START and END. */
+
+static void
+delete_dead_jump_tables_between (rtx start, rtx end)
+{
+ rtx insn, next;
+
+ for (insn = start; insn != end; insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (next != NULL_RTX
+ && LABEL_P (insn)
+ && LABEL_NUSES (insn) == LABEL_PRESERVE_P (insn)
+ && JUMP_TABLE_DATA_P (next))
+ {
+ rtx label = insn, jump = next;
+
+ if (dump_file)
+ fprintf (dump_file, "Dead jumptable %i removed\n",
+ INSN_UID (insn));
+
+ next = NEXT_INSN (next);
+ delete_insn (jump);
+ delete_insn (label);
+ }
+ }
+}
+
+
/* Delete any jump tables never referenced. We can't delete them at the
- time of removing tablejump insn as they are referenced by the preceding
- insns computing the destination, so we delay deleting and garbagecollect
- them once life information is computed. */
+ time of removing tablejump insn as the label preceding the jump table
+ data may be referenced by the preceding insns computing the destination.
+ So we delay deleting and garbage-collect them from time to time, after
+ a CFG cleanup. */
+
void
delete_dead_jumptables (void)
{
basic_block bb;
- /* A dead jump table does not belong to any basic block. Scan insns
- between two adjacent basic blocks. */
+ /* Label reference count must up-to-date to detect dead jump tables. */
+ rebuild_jump_labels (get_insns ());
+
FOR_EACH_BB (bb)
{
- rtx insn, next;
-
- for (insn = NEXT_INSN (BB_END (bb));
- insn && !NOTE_INSN_BASIC_BLOCK_P (insn);
- insn = next)
+ if (current_ir_type () == IR_RTL_CFGLAYOUT)
{
- next = NEXT_INSN (insn);
- if (LABEL_P (insn)
- && LABEL_NUSES (insn) == LABEL_PRESERVE_P (insn)
- && JUMP_TABLE_DATA_P (next))
- {
- rtx label = insn, jump = next;
-
- if (dump_file)
- fprintf (dump_file, "Dead jumptable %i removed\n",
- INSN_UID (insn));
-
- next = NEXT_INSN (next);
- delete_insn (jump);
- delete_insn (label);
- }
+ /* Jump tables only appear in the header or footer of BB. */
+ delete_dead_jump_tables_between (BB_HEADER (bb), NULL_RTX);
+ delete_dead_jump_tables_between (BB_FOOTER (bb), NULL_RTX);
+ }
+ else
+ {
+ /* Jump tables are in the insns chain between basic blocks. */
+ rtx start = NEXT_INSN (BB_END (bb));
+ rtx end = (bb->next_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
+ ? NULL_RTX : BB_HEAD (bb->next_bb);
+ delete_dead_jump_tables_between (start, end);
}
}
}
@@ -3049,13 +3074,13 @@ cleanup_cfg (int mode)
if (mode & CLEANUP_CROSSJUMP)
remove_fake_exit_edges ();
- /* Don't call delete_dead_jumptables in cfglayout mode, because
- that function assumes that jump tables are in the insns stream.
- But we also don't _have_ to delete dead jumptables in cfglayout
- mode because we shouldn't even be looking at things that are
- not in a basic block. Dead jumptables are cleaned up when
- going out of cfglayout mode. */
- if (!(mode & CLEANUP_CFGLAYOUT))
+ /* Don't always call delete_dead_jumptables in cfglayout mode, because
+ jump tables can only appear in the headers and footers of basic blocks
+ and we usually are not interested in anything hiding there.
+ But if an expensive cleanup is called for, garbage-collect the dead
+ jump tables to get label reference counts right. This sometimes
+ allows some labels to be removed and more basic blocks to be merged. */
+ if (!(mode & CLEANUP_CFGLAYOUT) || (mode & CLEANUP_EXPENSIVE))
delete_dead_jumptables ();
/* ??? We probably do this way too often. */
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 63f44afbbae..4ce7273834c 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -3696,10 +3696,10 @@ fixup_reorder_chain (void)
#endif
/* Now add jumps and labels as needed to match the blocks new
- outgoing edges. */
+ outgoing edges. Fixup missing or redundant BARRIERs. */
- for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb ; bb = (basic_block)
- bb->aux)
+ for (bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; bb ;
+ bb = (basic_block) bb->aux)
{
edge e_fall, e_taken, e;
rtx bb_end_insn;
@@ -3853,13 +3853,26 @@ fixup_reorder_chain (void)
relink_block_chain (/*stay_in_cfglayout_mode=*/false);
- /* Annoying special case - jump around dead jumptables left in the code. */
+ /* Annoying special case - stray barriers left in the code. This happens
+ if a tablejump is transformed to a simpe or confitional jump, or if a
+ basic block ending in a tablejump is removed but the jump table itself
+ is not. */
FOR_EACH_BB (bb)
{
edge e = find_fallthru_edge (bb->succs);
- if (e && !can_fallthru (e->src, e->dest))
- force_nonfallthru (e);
+ if (e && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
+ {
+ rtx insn, next;
+ for (insn = NEXT_INSN (BB_END (e->src));
+ insn != BB_HEAD (e->dest);
+ insn = next)
+ {
+ next = NEXT_INSN (insn);
+ if (BARRIER_P (insn))
+ remove_insn (insn);
+ }
+ }
}
/* Ensure goto_locus from edges has some instructions with that locus
@@ -4273,7 +4286,7 @@ break_superblocks (void)
}
/* Finalize the changes: reorder insn list according to the sequence specified
- by aux pointers, enter compensation code, rebuild scope forest. */
+ by aux pointers, enter compensation code. */
void
cfg_layout_finalize (void)
@@ -4281,6 +4294,7 @@ cfg_layout_finalize (void)
#ifdef ENABLE_CHECKING
verify_flow_info ();
#endif
+ delete_dead_jumptables ();
force_one_exit_fallthru ();
rtl_register_cfg_hooks ();
if (reload_completed
@@ -4291,9 +4305,6 @@ cfg_layout_finalize (void)
fixup_fallthru_exit_predecessor ();
fixup_reorder_chain ();
- rebuild_jump_labels (get_insns ());
- delete_dead_jumptables ();
-
#ifdef ENABLE_CHECKING
verify_insn_chain ();
verify_flow_info ();
diff --git a/gcc/ira.c b/gcc/ira.c
index 2902ebe0a8b..43f98d4d69a 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -5273,9 +5273,9 @@ ira (FILE *f)
if (optimize && rebuild_p)
{
timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
if (purge_all_dead_edges ())
delete_unreachable_blocks ();
+ rebuild_jump_labels (get_insns ());
timevar_pop (TV_JUMP);
}
diff --git a/gcc/jump.c b/gcc/jump.c
index a27aaa94b8d..87f9619d751 100644
--- a/gcc/jump.c
+++ b/gcc/jump.c
@@ -177,6 +177,34 @@ make_pass_cleanup_barriers (gcc::context *ctxt)
}
+/* Remove all REG_LABEL_OPERAND notes from INSN.
+
+ 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. */
+
+static void
+reset_insn_reg_label_operand_notes (rtx insn)
+{
+ 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);
+ }
+ }
+}
+
+
/* 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. */
@@ -186,32 +214,38 @@ init_label_info (rtx f)
{
rtx insn;
- for (insn = f; insn; insn = NEXT_INSN (insn))
+ if (current_ir_type () == IR_RTL_CFGLAYOUT)
{
- 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))
+ basic_block bb;
+
+ FOR_EACH_BB (bb)
{
- rtx note, next;
+ /* Labels only appear between BB_HEAD and the basic block note,
+ and in the basic block header and footer. */
+ for (insn = BB_HEAD (bb);
+ insn && LABEL_P (insn);
+ insn = NEXT_INSN (insn))
+ LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+ for (insn = BB_HEADER (bb); insn; insn = NEXT_INSN (insn))
+ if (LABEL_P (insn))
+ LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+ for (insn = BB_FOOTER (bb); insn; insn = NEXT_INSN (insn))
+ 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_OPERAND
- && ! reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- remove_note (insn, note);
- }
+ FOR_BB_INSNS (bb, insn)
+ if (INSN_P (insn))
+ reset_insn_reg_label_operand_notes (insn);
+ }
+ }
+ else
+ {
+ for (insn = f; insn; insn = NEXT_INSN (insn))
+ {
+ if (LABEL_P (insn))
+ LABEL_NUSES (insn) = (LABEL_PRESERVE_P (insn) != 0);
+ if (INSN_P (insn))
+ reset_insn_reg_label_operand_notes (insn);
}
}
}
diff --git a/gcc/loop-init.c b/gcc/loop-init.c
index 664b1ace427..0d8e4383744 100644
--- a/gcc/loop-init.c
+++ b/gcc/loop-init.c
@@ -415,7 +415,7 @@ rtl_loop_done (void)
loop_optimizer_finalize ();
free_dominance_info (CDI_DOMINATORS);
- cleanup_cfg (0);
+ cleanup_cfg (CLEANUP_EXPENSIVE);
if (dump_file)
{
dump_reg_info (dump_file);
diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c
index f3130449909..444ffda34e9 100644
--- a/gcc/modulo-sched.c
+++ b/gcc/modulo-sched.c
@@ -1471,7 +1471,7 @@ sms_schedule (void)
continue;
}
- /* Don't handle BBs with calls or barriers
+ /* Don't handle BBs with calls
or !single_set with the exception of instructions that include
count_reg---these instructions are part of the control part
that do-loop recognizes.
@@ -1481,7 +1481,6 @@ sms_schedule (void)
rtx set;
if (CALL_P (insn)
- || BARRIER_P (insn)
|| (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE
&& !reg_mentioned_p (count_reg, insn))
@@ -1496,8 +1495,6 @@ sms_schedule (void)
{
if (CALL_P (insn))
fprintf (dump_file, "SMS loop-with-call\n");
- else if (BARRIER_P (insn))
- fprintf (dump_file, "SMS loop-with-barrier\n");
else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
fprintf (dump_file, "SMS loop-with-not-single-set\n");