#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "tm_p.h"
#include "target.h"
-#include "obstack.h"
-
/* cleanup_cfg maintains following flags for each basic block. */
enum bb_flags
static bool
mark_effect (exp, nonequal)
- rtx exp;
- regset nonequal;
+ rtx exp;
+ regset nonequal;
{
int regno;
rtx dest;
{
/* In case we do clobber the register, mark it as equal, as we know the
value is dead so it don't have to match. */
- case CLOBBER:
- if (REG_P (XEXP (exp, 0)))
- {
- dest = XEXP (exp, 0);
- regno = REGNO (dest);
- CLEAR_REGNO_REG_SET (nonequal, regno);
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- int n = HARD_REGNO_NREGS (regno, GET_MODE (dest));
- while (--n > 0)
- CLEAR_REGNO_REG_SET (nonequal, regno + n);
- }
- }
- return false;
+ case CLOBBER:
+ if (REG_P (XEXP (exp, 0)))
+ {
+ dest = XEXP (exp, 0);
+ regno = REGNO (dest);
+ CLEAR_REGNO_REG_SET (nonequal, regno);
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int n = HARD_REGNO_NREGS (regno, GET_MODE (dest));
+ while (--n > 0)
+ CLEAR_REGNO_REG_SET (nonequal, regno + n);
+ }
+ }
+ return false;
- case SET:
- if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp)))
- return false;
- dest = SET_DEST (exp);
- if (dest == pc_rtx)
- return false;
- if (!REG_P (dest))
- return true;
- regno = REGNO (dest);
- SET_REGNO_REG_SET (nonequal, regno);
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- int n = HARD_REGNO_NREGS (regno, GET_MODE (dest));
- while (--n > 0)
- SET_REGNO_REG_SET (nonequal, regno + n);
- }
+ case SET:
+ if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp)))
return false;
-
- default:
+ dest = SET_DEST (exp);
+ if (dest == pc_rtx)
return false;
+ if (!REG_P (dest))
+ return true;
+ regno = REGNO (dest);
+ SET_REGNO_REG_SET (nonequal, regno);
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int n = HARD_REGNO_NREGS (regno, GET_MODE (dest));
+ while (--n > 0)
+ SET_REGNO_REG_SET (nonequal, regno + n);
+ }
+ return false;
+
+ default:
+ return false;
}
}
return 0;
}
/* Attempt to prove that the basic block B will have no side effects and
- allways continues in the same edge if reached via E. Return the edge
+ always continues in the same edge if reached via E. Return the edge
if exist, NULL otherwise. */
static edge
/* Second branch must end with onlyjump, as we will eliminate the jump. */
if (!any_condjump_p (e->src->end))
return NULL;
-
+
if (!any_condjump_p (b->end) || !onlyjump_p (b->end))
{
BB_SET_FLAG (b, BB_NONTHREADABLE_BLOCK);
return NULL;
/* Ensure that the comparison operators are equivalent.
- ??? This is far too pesimistic. We should allow swapped operands,
+ ??? This is far too pessimistic. We should allow swapped operands,
different CCmodes, or for example comparisons for interval, that
dominate even when operands are not equivalent. */
if (!rtx_equal_p (XEXP (cond1, 0), XEXP (cond2, 0))
for (insn = NEXT_INSN (b->head); insn != NEXT_INSN (b->end) && !failed;
insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- {
- rtx pat = PATTERN (insn);
-
- if (GET_CODE (pat) == PARALLEL)
- {
- for (i = 0; i < XVECLEN (pat, 0); i++)
- failed |= mark_effect (XVECEXP (pat, 0, i), nonequal);
- }
- else
- failed |= mark_effect (pat, nonequal);
- }
+ {
+ if (INSN_P (insn))
+ {
+ rtx pat = PATTERN (insn);
- cselib_process_insn (insn);
- }
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ failed |= mark_effect (XVECEXP (pat, 0, i), nonequal);
+ }
+ else
+ failed |= mark_effect (pat, nonequal);
+ }
+
+ cselib_process_insn (insn);
+ }
/* Later we should clear nonequal of dead registers. So far we don't
have life information in cfg_cleanup. */
target = first = e->dest;
counter = 0;
- while (counter < num_basic_blocks)
+ while (counter < n_basic_blocks)
{
basic_block new_target = NULL;
bool new_target_threaded = false;
{
/* Bypass trivial infinite loops. */
if (target == target->succ->dest)
- counter = num_basic_blocks;
+ counter = n_basic_blocks;
new_target = target->succ->dest;
}
{
if (!threaded_edges)
threaded_edges = xmalloc (sizeof (*threaded_edges)
- * num_basic_blocks);
+ * n_basic_blocks);
else
{
int i;
break;
if (i < nthreaded_edges)
{
- counter = num_basic_blocks;
+ counter = n_basic_blocks;
break;
}
}
if (t->dest == b)
break;
- if (nthreaded_edges >= num_basic_blocks)
+ if (nthreaded_edges >= n_basic_blocks)
abort ();
threaded_edges[nthreaded_edges++] = t;
if (mode & CLEANUP_PRE_LOOP)
{
rtx insn = (target->succ->flags & EDGE_FALLTHRU
- ? target->head : prev_nonnote_insn (target->end));
+ ? target->head : prev_nonnote_insn (target->end));
if (GET_CODE (insn) != NOTE)
insn = NEXT_INSN (insn);
if (GET_CODE (insn) == NOTE)
break;
+
+ /* Do not clean up branches to just past the end of a loop
+ at this time; it can mess up the loop optimizer's
+ recognition of some patterns. */
+
+ insn = PREV_INSN (target->head);
+ if (insn && GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ break;
}
counter++;
target = new_target;
threaded |= new_target_threaded;
- }
+ }
- if (counter >= num_basic_blocks)
+ if (counter >= n_basic_blocks)
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Infinite loop in BB %i.\n",
- target->sindex);
+ target->index);
}
else if (target == first)
; /* We didn't do anything. */
{
notice_new_block (redirect_edge_and_branch_force (e, target));
if (rtl_dump_file)
- fprintf (rtl_dump_file, "Conditionals threaded.\n");
+ fprintf (rtl_dump_file, "Conditionals threaded.\n");
}
else if (!redirect_edge_and_branch (e, target))
{
if (rtl_dump_file)
fprintf (rtl_dump_file,
"Forwarding edge %i->%i to %i failed.\n",
- b->sindex, e->dest->sindex, target->sindex);
+ b->index, e->dest->index, target->index);
continue;
}
&& first == threaded_edges [n]->src)
n++;
t = first->succ;
- }
+ }
t->count -= edge_count;
if (t->count < 0)
if (rtl_dump_file)
fprintf (rtl_dump_file, "Moved block %d before %d and merged.\n",
- a->sindex, b->sindex);
+ a->index, b->index);
/* Swap the records for the two blocks around. */
+
unlink_block (a);
link_block (a, b->prev_bb);
if (rtl_dump_file)
fprintf (rtl_dump_file, "Moved block %d after %d and merged.\n",
- b->sindex, a->sindex);
+ b->index, a->index);
/* Now blocks A and B are contiguous. Merge them. */
merge_blocks_nomove (a, b);
/* If B has a fallthru edge to C, no need to move anything. */
if (e->flags & EDGE_FALLTHRU)
{
- int b_index = b->sindex, c_index = c->sindex;
+ int b_index = b->index, c_index = c->index;
merge_blocks_nomove (b, c);
update_forwarder_flag (b);
if (rtl_dump_file)
fprintf (rtl_dump_file, "Merged %d and %d without moving.\n",
- b_index, c_index);
+ b_index, c_index);
return true;
}
static bool
insns_match_p (mode, i1, i2)
- int mode ATTRIBUTE_UNUSED;
- rtx i1, i2;
+ int mode ATTRIBUTE_UNUSED;
+ rtx i1, i2;
{
rtx p1, p2;
equal, they were constructed identically. */
if (GET_CODE (i1) == CALL_INSN
- && !rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
- CALL_INSN_FUNCTION_USAGE (i2)))
+ && (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
+ CALL_INSN_FUNCTION_USAGE (i2))
+ || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)))
return false;
#ifdef STACK_REGS
remove_note (i1, equiv1);
remove_note (i2, equiv2);
}
-
+
afterlast1 = last1, afterlast2 = last2;
last1 = i1, last2 = i2;
- ninsns++;
+ ninsns++;
}
i1 = PREV_INSN (i1);
/* If BB1 has only one successor, we may be looking at either an
unconditional jump, or a fake edge to exit. */
if (bb1->succ && !bb1->succ->succ_next
- && !(bb1->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)))
+ && (bb1->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+ && (GET_CODE (bb1->end) != JUMP_INSN || simplejump_p (bb1->end)))
return (bb2->succ && !bb2->succ->succ_next
- && (bb2->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0);
+ && (bb2->succ->flags & (EDGE_COMPLEX | EDGE_FAKE)) == 0
+ && (GET_CODE (bb2->end) != JUMP_INSN || simplejump_p (bb2->end)));
/* Match conditional jumps - this may get tricky when fallthru and branch
edges are crossed. */
enum rtx_code code1, code2;
if (!bb2->succ
- || !bb2->succ->succ_next
+ || !bb2->succ->succ_next
|| bb2->succ->succ_next->succ_next
|| !any_condjump_p (bb2->end)
|| !onlyjump_p (bb2->end))
return false;
- /* Do not crossjump across loop boundaries. This is a temporary
- workaround for the common scenario in which crossjumping results
- in killing the duplicated loop condition, making bb-reorder rotate
- the loop incorectly, leaving an extra unconditional jump inside
- the loop.
-
- This check should go away once bb-reorder knows how to duplicate
- code in this case or rotate the loops to avoid this scenario. */
- if (bb1->loop_depth != bb2->loop_depth)
- return false;
-
b1 = BRANCH_EDGE (bb1);
b2 = BRANCH_EDGE (bb2);
f1 = FALLTHRU_EDGE (bb1);
if (rtl_dump_file)
fprintf (rtl_dump_file,
"Outcomes of branch in bb %i and %i differs to much (%i %i)\n",
- bb1->sindex, bb2->sindex, b1->probability, prob2);
+ bb1->index, bb2->index, b1->probability, prob2);
return false;
}
if (rtl_dump_file && match)
fprintf (rtl_dump_file, "Conditionals in bb %i and %i match.\n",
- bb1->sindex, bb2->sindex);
+ bb1->index, bb2->index);
return match;
}
- /* Generic case - we are seeing an computed jump, table jump or trapping
+ /* Generic case - we are seeing a computed jump, table jump or trapping
instruction. */
/* First ensure that the instructions match. There may be many outgoing
if (fallthru1)
{
basic_block d1 = (forwarder_block_p (fallthru1->dest)
- ? fallthru1->dest->succ->dest: fallthru1->dest);
+ ? fallthru1->dest->succ->dest: fallthru1->dest);
basic_block d2 = (forwarder_block_p (fallthru2->dest)
- ? fallthru2->dest->succ->dest: fallthru2->dest);
+ ? fallthru2->dest->succ->dest: fallthru2->dest);
if (d1 != d2)
return false;
{
int nmatch;
basic_block src1 = e1->src, src2 = e2->src;
- basic_block redirect_to;
+ basic_block redirect_to, redirect_from, to_remove;
rtx newpos1, newpos2;
edge s;
- rtx last;
- rtx label;
/* Search backward through forwarder blocks. We don't need to worry
about multiple entry or chained forwarders, as they will be optimized
{
if (rtl_dump_file)
fprintf (rtl_dump_file, "Splitting bb %i before %i insns\n",
- src2->sindex, nmatch);
+ src2->index, nmatch);
redirect_to = split_block (src2, PREV_INSN (newpos2))->dest;
}
if (rtl_dump_file)
fprintf (rtl_dump_file,
"Cross jumping from bb %i to bb %i; %i common insns\n",
- src1->sindex, src2->sindex, nmatch);
+ src1->index, src2->index, nmatch);
redirect_to->count += src1->count;
redirect_to->frequency += src1->frequency;
if (GET_CODE (newpos1) == NOTE)
newpos1 = NEXT_INSN (newpos1);
- last = src1->end;
-
- /* Emit the jump insn. */
- label = block_label (redirect_to);
- emit_jump_insn_after (gen_jump (label), src1->end);
- JUMP_LABEL (src1->end) = label;
- LABEL_NUSES (label)++;
- /* Delete the now unreachable instructions. */
- delete_insn_chain (newpos1, last);
+ redirect_from = split_block (src1, PREV_INSN (newpos1))->src;
+ to_remove = redirect_from->succ->dest;
- /* Make sure there is a barrier after the new jump. */
- last = next_nonnote_insn (src1->end);
- if (!last || GET_CODE (last) != BARRIER)
- emit_barrier_after (src1->end);
+ redirect_edge_and_branch_force (redirect_from->succ, redirect_to);
+ flow_delete_block (to_remove);
- /* Update CFG. */
- while (src1->succ)
- remove_edge (src1->succ);
- make_single_succ_edge (src1, redirect_to, 0);
-
- update_forwarder_flag (src1);
+ update_forwarder_flag (redirect_from);
return true;
}
for (e2 = bb->pred; e2; e2 = nexte2)
{
- basic_block foll;
nexte2 = e2->pred_next;
if (e2 == e)
checks of crossjump(A,B). In order to prevent redundant
checks of crossjump(B,A), require that A be the block
with the lowest index. */
- for (foll = e->src; foll && foll != e2->src; foll = foll->next_bb)
- {
- }
- if (!foll)
+ if (e->src->index > e2->src->index)
continue;
if (try_crossjump_to_edge (mode, e, e2))
if (mode & CLEANUP_CROSSJUMP)
add_noreturn_fake_exit_edges ();
- FOR_ALL_BB (bb)
+ FOR_EACH_BB (bb)
update_forwarder_flag (bb);
if (mode & CLEANUP_UPDATE_LIFE)
c = b->prev_bb;
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleting block %i.\n",
- b->sindex);
+ b->index);
flow_delete_block (b);
changed = true;
delete_insn_chain (label, label);
if (rtl_dump_file)
fprintf (rtl_dump_file, "Deleted label in block %i.\n",
- b->sindex);
+ b->index);
}
/* If we fall through an empty block, we can remove it. */
/* Note that forwarder_block_p true ensures that
there is a successor for this block. */
&& (b->succ->flags & EDGE_FALLTHRU)
- && num_basic_blocks > 1)
+ && n_basic_blocks > 1)
{
if (rtl_dump_file)
fprintf (rtl_dump_file,
"Deleting fallthru block %i.\n",
- b->sindex);
+ b->index);
c = b->prev_bb == ENTRY_BLOCK_PTR ? b->next_bb : b->prev_bb;
redirect_edge_succ_nodup (b->pred, b->succ->dest);
&& !(s->flags & EDGE_COMPLEX)
&& (c = s->dest) != EXIT_BLOCK_PTR
&& c->pred->pred_next == NULL
+ && b != c
/* If the jump insn has side effects,
we can't kill the edge. */
&& (GET_CODE (b->end) != JUMP_INSN
for (b = ENTRY_BLOCK_PTR->next_bb; b != EXIT_BLOCK_PTR; b = next_bb)
{
next_bb = b->next_bb;
+
if (!(b->flags & BB_REACHABLE))
{
flow_delete_block (b);
{
changed = true;
/* We've possibly created trivially dead code. Cleanup it right
- now to introduce more oppurtunities for try_optimize_cfg. */
- if (!(mode & (CLEANUP_UPDATE_LIFE | CLEANUP_PRE_SIBCALL))
+ now to introduce more opportunities for try_optimize_cfg. */
+ if (!(mode & (CLEANUP_NO_INSN_DEL
+ | CLEANUP_UPDATE_LIFE | CLEANUP_PRE_SIBCALL))
&& !reload_completed)
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 oppurtunities for dead code
- removal that in turn may introduce more oppurtunities for
+ /* 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_LOG_LINKS))
break;
}
- else if (!(mode & CLEANUP_PRE_SIBCALL) && !reload_completed)
+ else if (!(mode & (CLEANUP_NO_INSN_DEL | CLEANUP_PRE_SIBCALL))
+ && !reload_completed)
{
if (!delete_trivially_dead_insns (get_insns(), max_reg_num ()))
break;