/* Control flow optimization code for GNU compiler.
Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This file contains optimizer of the control flow. The main entry point is
cleanup_cfg. Following optimizations are performed:
#include "tree-pass.h"
#include "cfgloop.h"
#include "expr.h"
+#include "df.h"
+#include "dce.h"
#define FORWARDER_BLOCK_P(BB) ((BB)->flags & BB_FORWARDER_BLOCK)
static bool try_optimize_cfg (int);
static bool try_simplify_condjump (basic_block);
static bool try_forward_edges (int, basic_block);
-static edge thread_jump (int, edge, basic_block);
+static edge thread_jump (edge, basic_block);
static bool mark_effect (rtx, bitmap);
static void notice_new_block (basic_block);
static void update_forwarder_flag (basic_block);
if exist, NULL otherwise. */
static edge
-thread_jump (int mode, edge e, basic_block b)
+thread_jump (edge e, basic_block b)
{
rtx set1, set2, cond1, cond2, insn;
enum rtx_code code1, code2, reversed_code2;
if (for_each_rtx (&cond2, mentions_nonequal_regs, nonequal))
goto failed_exit;
- /* In case liveness information is available, we need to prove equivalence
- only of the live values. */
- if (mode & CLEANUP_UPDATE_LIFE)
- AND_REG_SET (nonequal, b->il.rtl->global_live_at_end);
-
EXECUTE_IF_SET_IN_REG_SET (nonequal, 0, i, rsi)
goto failed_exit;
int counter;
bool threaded = false;
int nthreaded_edges = 0;
- bool may_thread = first_pass | (b->flags & BB_DIRTY);
+ bool may_thread = first_pass | df_get_bb_dirty (b);
/* Skip complex edges because we don't know how to update them.
{
basic_block new_target = NULL;
bool new_target_threaded = false;
- may_thread |= target->flags & BB_DIRTY;
+ may_thread |= df_get_bb_dirty (target);
if (FORWARDER_BLOCK_P (target)
&& !(single_succ_edge (target)->flags & EDGE_CROSSING)
of probabilities. */
else if ((mode & CLEANUP_THREADING) && may_thread)
{
- edge t = thread_jump (mode, e, target);
+ edge t = thread_jump (e, target);
if (t)
{
if (!threaded_edges)
merge_blocks_move_predecessor_nojumps (basic_block a, basic_block b)
{
rtx barrier;
- bool only_notes;
/* If we are partitioning hot/cold basic blocks, we don't want to
mess up unconditional or indirect jumps that cross between hot
gcc_assert (BARRIER_P (barrier));
delete_insn (barrier);
- /* Move block and loop notes out of the chain so that we do not
- disturb their order.
-
- ??? A better solution would be to squeeze out all the non-nested notes
- and adjust the block trees appropriately. Even better would be to have
- a tighter connection between block trees and rtl so that this is not
- necessary. */
- only_notes = squeeze_notes (&BB_HEAD (a), &BB_END (a));
- gcc_assert (!only_notes);
-
/* Scramble the insn chain. */
if (BB_END (a) != PREV_INSN (BB_HEAD (b)))
reorder_insns_nobb (BB_HEAD (a), BB_END (a), PREV_INSN (BB_HEAD (b)));
- a->flags |= BB_DIRTY;
+ df_set_bb_dirty (a);
if (dump_file)
fprintf (dump_file, "Moved block %d before %d and merged.\n",
{
rtx barrier, real_b_end;
rtx label, table;
- bool only_notes;
/* If we are partitioning hot/cold basic blocks, we don't want to
mess up unconditional or indirect jumps that cross between hot
if (barrier && BARRIER_P (barrier))
delete_insn (barrier);
- /* Move block and loop notes out of the chain so that we do not
- disturb their order.
-
- ??? A better solution would be to squeeze out all the non-nested notes
- and adjust the block trees appropriately. Even better would be to have
- a tighter connection between block trees and rtl so that this is not
- necessary. */
- only_notes = squeeze_notes (&BB_HEAD (b), &BB_END (b));
- gcc_assert (!only_notes);
-
/* Scramble the insn chain. */
reorder_insns_nobb (BB_HEAD (b), BB_END (b), BB_END (a));
if (BB_PARTITION (b) != BB_PARTITION (c))
return NULL;
-
-
/* If B has a fallthru edge to C, no need to move anything. */
if (e->flags & EDGE_FALLTHRU)
{
if (REG_NOTE_KIND (note) == REG_DEAD && STACK_REG_P (XEXP (note, 0)))
SET_HARD_REG_BIT (i2_regset, REGNO (XEXP (note, 0)));
- GO_IF_HARD_REG_EQUAL (i1_regset, i2_regset, done);
-
- return false;
-
- done:
- ;
+ if (!hard_reg_set_equal_p (i1_regset, i2_regset))
+ return false;
}
#endif
partition boundaries). See the comments at the top of
bb-reorder.c:partition_hot_cold_basic_blocks for complete details. */
- if (flag_reorder_blocks_and_partition && no_new_pseudos)
+ if (flag_reorder_blocks_and_partition && reload_completed)
return false;
/* Search backward through forwarder blocks. We don't need to worry
redirect_to->count += src1->count;
redirect_to->frequency += src1->frequency;
/* We may have some registers visible through the block. */
- redirect_to->flags |= BB_DIRTY;
+ df_set_bb_dirty (redirect_to);
/* Recompute the frequencies and counts of outgoing edges. */
FOR_EACH_EDGE (s, ei, redirect_to->succs)
/* If nothing changed since the last attempt, there is nothing
we can do. */
if (!first_pass
- && (!(e->src->flags & BB_DIRTY)
- && !(fallthru->src->flags & BB_DIRTY)))
+ && (!(df_get_bb_dirty (e->src))
+ && !(df_get_bb_dirty (fallthru->src))))
continue;
if (try_crossjump_to_edge (mode, e, fallthru))
/* If nothing changed since the last attempt, there is nothing
we can do. */
if (!first_pass
- && (!(e->src->flags & BB_DIRTY)
- && !(e2->src->flags & BB_DIRTY)))
+ && (!(df_get_bb_dirty (e->src))
+ && !(df_get_bb_dirty (e2->src))))
continue;
if (try_crossjump_to_edge (mode, e, e2))
if (mode & CLEANUP_CROSSJUMP)
add_noreturn_fake_exit_edges ();
- if (mode & (CLEANUP_UPDATE_LIFE | CLEANUP_CROSSJUMP | CLEANUP_THREADING))
+ if (mode & (CLEANUP_CROSSJUMP | CLEANUP_THREADING))
clear_bb_flags ();
FOR_EACH_BB (bb)
bool changed_here = false;
/* Delete trivially dead basic blocks. */
- while (EDGE_COUNT (b->preds) == 0)
+ if (EDGE_COUNT (b->preds) == 0)
{
c = b->prev_bb;
if (dump_file)
delete_basic_block (b);
if (!(mode & CLEANUP_CFGLAYOUT))
changed = true;
- b = c;
+ /* Avoid trying to remove ENTRY_BLOCK_PTR. */
+ b = (c == ENTRY_BLOCK_PTR ? c->next_bb : c);
+ continue;
}
/* Remove code labels no longer used. */
{
rtx label = BB_HEAD (b);
- delete_insn_chain (label, label);
- /* In the case label is undeletable, move it after the
+ delete_insn_chain (label, label, false);
+ /* If the case label is undeletable, move it after the
BASIC_BLOCK note. */
- if (NOTE_LINE_NUMBER (BB_HEAD (b)) == NOTE_INSN_DELETED_LABEL)
+ if (NOTE_KIND (BB_HEAD (b)) == NOTE_INSN_DELETED_LABEL)
{
rtx bb_note = NEXT_INSN (BB_HEAD (b));
reorder_insns_nobb (label, label, bb_note);
BB_HEAD (b) = bb_note;
+ if (BB_END (b) == bb_note)
+ BB_END (b) = label;
}
if (dump_file)
fprintf (dump_file, "Deleted label in block %i.\n",
return changed;
}
-/* Merges sequential blocks if possible. */
-
-bool
-merge_seq_blocks (void)
+/* 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. */
+void
+delete_dead_jumptables (void)
{
basic_block bb;
- bool changed = false;
- for (bb = ENTRY_BLOCK_PTR->next_bb; bb != EXIT_BLOCK_PTR; )
+ /* A dead jump table does not belong to any basic block. Scan insns
+ between two adjacent basic blocks. */
+ FOR_EACH_BB (bb)
{
- if (single_succ_p (bb)
- && can_merge_blocks_p (bb, single_succ (bb)))
+ rtx insn, next;
+
+ for (insn = NEXT_INSN (BB_END (bb));
+ insn && !NOTE_INSN_BASIC_BLOCK_P (insn);
+ insn = next)
{
- /* Merge the blocks and retry. */
- merge_blocks (bb, single_succ (bb));
- changed = true;
- continue;
- }
+ next = NEXT_INSN (insn);
+ if (LABEL_P (insn)
+ && LABEL_NUSES (insn) == LABEL_PRESERVE_P (insn)
+ && JUMP_P (next)
+ && (GET_CODE (PATTERN (next)) == ADDR_VEC
+ || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
+ {
+ rtx label = insn, jump = next;
- bb = bb->next_bb;
- }
+ if (dump_file)
+ fprintf (dump_file, "Dead jumptable %i removed\n",
+ INSN_UID (insn));
- return changed;
+ next = NEXT_INSN (next);
+ delete_insn (jump);
+ delete_insn (label);
+ }
+ }
+ }
}
+
\f
/* Tidy the CFG by deleting unreachable code and whatnot. */
{
bool changed = false;
+ /* Set the cfglayout mode flag here. We could update all the callers
+ but that is just inconvenient, especially given that we eventually
+ want to have cfglayout mode as the default. */
+ if (current_ir_type () == IR_RTL_CFGLAYOUT)
+ mode |= CLEANUP_CFGLAYOUT;
+
timevar_push (TV_CLEANUP_CFG);
if (delete_unreachable_blocks ())
{
changed = true;
/* We've possibly created trivially dead code. Cleanup it right
now to introduce more opportunities for try_optimize_cfg. */
- if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_UPDATE_LIFE))
+ if (!(mode & (CLEANUP_NO_INSN_DEL))
&& !reload_completed)
- delete_trivially_dead_insns (get_insns(), max_reg_num ());
+ delete_trivially_dead_insns (get_insns (), max_reg_num ());
}
compact_blocks ();
while (try_optimize_cfg (mode))
{
delete_unreachable_blocks (), changed = true;
- if (mode & CLEANUP_UPDATE_LIFE)
- {
- /* Cleaning up CFG introduces more opportunities for dead code
- removal that in turn may introduce more opportunities for
- cleaning up the CFG. */
- if (!update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
- PROP_DEATH_NOTES
- | PROP_SCAN_DEAD_CODE
- | PROP_KILL_DEAD_CODE
- | ((mode & CLEANUP_LOG_LINKS)
- ? PROP_LOG_LINKS : 0)))
- break;
- }
- else if (!(mode & CLEANUP_NO_INSN_DEL)
- && (mode & CLEANUP_EXPENSIVE)
- && !reload_completed)
+ if (!(mode & CLEANUP_NO_INSN_DEL)
+ && (mode & CLEANUP_EXPENSIVE)
+ && !reload_completed)
{
- if (!delete_trivially_dead_insns (get_insns(), max_reg_num ()))
+ if (!delete_trivially_dead_insns (get_insns (), max_reg_num ()))
break;
}
else
break;
- delete_dead_jumptables ();
}
+ /* 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))
+ delete_dead_jumptables ();
+
timevar_pop (TV_CLEANUP_CFG);
return changed;
static unsigned int
rest_of_handle_jump2 (void)
{
- /* Turn NOTE_INSN_EXPECTED_VALUE into REG_BR_PROB. Do this
- before jump optimization switches branch directions. */
- if (flag_guess_branch_prob)
- expected_value_to_br_prob ();
-
delete_trivially_dead_insns (get_insns (), max_reg_num ());
- reg_scan (get_insns (), max_reg_num ());
if (dump_file)
dump_flow_info (dump_file, dump_flags);
cleanup_cfg ((optimize ? CLEANUP_EXPENSIVE : 0)
| (flag_thread_jumps ? CLEANUP_THREADING : 0));
-
- purge_line_number_notes ();
-
- if (optimize)
- cleanup_cfg (CLEANUP_EXPENSIVE);
-
- /* Jump optimization, and the removal of NULL pointer checks, may
- have reduced the number of instructions substantially. CSE, and
- future passes, allocate arrays whose dimensions involve the
- maximum instruction UID, so if we can reduce the maximum UID
- we'll save big on memory. */
- renumber_insns ();
return 0;
}