/* Basic block reordering routines for the GNU compiler.
- Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "obstack.h"
#include "expr.h"
#include "params.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
+#include "toplev.h" /* user_defined_section_attribute */
#include "tree-pass.h"
#include "df.h"
-
-#ifndef HAVE_conditional_execution
-#define HAVE_conditional_execution 0
-#endif
+#include "bb-reorder.h"
/* The number of rounds. In most cases there will only be 4 rounds, but
when partitioning hot and cold basic blocks into separate sections of
#endif
+struct target_bb_reorder default_target_bb_reorder;
+#if SWITCHABLE_TARGET
+struct target_bb_reorder *this_target_bb_reorder = &default_target_bb_reorder;
+#endif
+
+#define uncond_jump_length \
+ (this_target_bb_reorder->x_uncond_jump_length)
+
/* Branch thresholds in thousandths (per mille) of the REG_BR_PROB_BASE. */
static int branch_threshold[N_ROUNDS] = {400, 200, 100, 0, 0};
block the edge destination is not duplicated while connecting traces. */
#define DUPLICATION_THRESHOLD 100
-/* Length of unconditional jump instruction. */
-static int uncond_jump_length;
-
/* Structure to hold needed information for each basic block. */
typedef struct bbro_basic_block_data_def
{
basic_block bb;
fprintf (dump_file, "Trace %d (round %d): ", i + 1,
traces[i].round + 1);
- for (bb = traces[i].first; bb != traces[i].last; bb = bb->aux)
+ for (bb = traces[i].first; bb != traces[i].last; bb = (basic_block) bb->aux)
fprintf (dump_file, "%d [%d] ", bb->index, bb->frequency);
fprintf (dump_file, "%d [%d]\n", bb->index, bb->frequency);
}
}
}
}
- bb = bb->aux;
+ bb = (basic_block) bb->aux;
}
while (bb != back_edge->dest);
the trace. */
if (back_edge->dest == trace->first)
{
- trace->first = best_bb->aux;
+ trace->first = (basic_block) best_bb->aux;
}
else
{
for (prev_bb = trace->first;
prev_bb->aux != back_edge->dest;
- prev_bb = prev_bb->aux)
+ prev_bb = (basic_block) prev_bb->aux)
;
prev_bb->aux = best_bb->aux;
fibheapkey_t key;
edge_iterator ei;
- bb = fibheap_extract_min (*heap);
+ bb = (basic_block) fibheap_extract_min (*heap);
bbd[bb->index].heap = NULL;
bbd[bb->index].node = NULL;
/* The loop has less than 4 iterations. */
if (single_succ_p (bb)
- && copy_bb_p (best_edge->dest, !optimize_size))
+ && copy_bb_p (best_edge->dest,
+ optimize_edge_for_speed_p (best_edge)))
{
bb = copy_bb (best_edge->dest, best_edge, bb,
*n_traces);
new_size = MAX (last_basic_block, new_bb->index + 1);
new_size = GET_ARRAY_SIZE (new_size);
- bbd = xrealloc (bbd, new_size * sizeof (bbro_basic_block_data));
+ bbd = XRESIZEVEC (bbro_basic_block_data, bbd, new_size);
for (i = array_size; i < new_size; i++)
{
bbd[i].start_of_trace = -1;
edge is traversed frequently enough. */
if (try_copy
&& copy_bb_p (best->dest,
- !optimize_size
+ optimize_edge_for_speed_p (best)
&& EDGE_FREQUENCY (best) >= freq_threshold
&& best->count >= count_threshold))
{
basic_block bb;
fprintf (dump_file, "Final order:\n");
- for (bb = traces[0].first; bb; bb = bb->aux)
+ for (bb = traces[0].first; bb; bb = (basic_block) bb->aux)
fprintf (dump_file, "%d ", bb->index);
fprintf (dump_file, "\n");
fflush (dump_file);
if (EDGE_COUNT (bb->succs) > 8)
return false;
- if (code_may_grow && maybe_hot_bb_p (bb))
+ if (code_may_grow && optimize_bb_for_speed_p (bb))
max_size *= PARAM_VALUE (PARAM_MAX_GROW_COPY_BB_INSNS);
FOR_BB_INSNS (bb, insn)
if (i == *max_idx)
{
*max_idx *= 2;
- *crossing_edges = xrealloc (*crossing_edges,
- (*max_idx) * sizeof (edge));
+ *crossing_edges = XRESIZEVEC (edge, *crossing_edges, *max_idx);
}
(*crossing_edges)[i++] = e;
}
{
label = block_label (dest);
- /* Make sure source block ends with a jump. */
+ /* Make sure source block ends with a jump. If the
+ source block does not end with a jump it might end
+ with a call_insn; this case will be handled in
+ fix_up_fall_thru_edges function. */
if (src && (src != ENTRY_BLOCK_PTR))
{
- if (!JUMP_P (BB_END (src)))
+ if (!JUMP_P (BB_END (src))
+ && !block_ends_with_call_p (src)
+ && !can_throw_internal (BB_END (src)))
/* bb just falls through. */
{
/* make sure there's only one successor */
src->il.rtl->footer = unlink_insn_chain (barrier, barrier);
/* Mark edge as non-fallthru. */
crossing_edges[i]->flags &= ~EDGE_FALLTHRU;
- } /* end: 'if (GET_CODE ... ' */
- } /* end: 'if (src && src->index...' */
- } /* end: 'if (dest && dest->index...' */
+ } /* end: 'if (!JUMP_P ... ' */
+ } /* end: 'if (src && src !=...' */
+ } /* end: 'if (dest && dest !=...' */
} /* end: 'if (crossing_edges[i]...' */
} /* end for loop */
}
/* Find any bb's where the fall-through edge is a crossing edge (note that
- these bb's must also contain a conditional jump; we've already
- dealt with fall-through edges for blocks that didn't have a
- conditional jump in the call to add_labels_and_missing_jumps).
- Convert the fall-through edge to non-crossing edge by inserting a
- new bb to fall-through into. The new bb will contain an
- unconditional jump (crossing edge) to the original fall through
- destination. */
+ these bb's must also contain a conditional jump or end with a call
+ instruction; we've already dealt with fall-through edges for blocks
+ that didn't have a conditional jump or didn't end with call instruction
+ in the call to add_labels_and_missing_jumps). Convert the fall-through
+ edge to non-crossing edge by inserting a new bb to fall-through into.
+ The new bb will contain an unconditional jump (crossing edge) to the
+ original fall through destination. */
static void
fix_up_fall_thru_edges (void)
fall_thru = succ2;
cond_jump = succ1;
}
+ else if (succ1
+ && (block_ends_with_call_p (cur_bb)
+ || can_throw_internal (BB_END (cur_bb))))
+ {
+ edge e;
+ edge_iterator ei;
+
+ /* Find EDGE_CAN_FALLTHRU edge. */
+ FOR_EACH_EDGE (e, ei, cur_bb->succs)
+ if (e->flags & EDGE_CAN_FALLTHRU)
+ {
+ fall_thru = e;
+ break;
+ }
+ }
if (fall_thru && (fall_thru->dest != EXIT_BLOCK_PTR))
{
fall_thru_label = block_label (fall_thru->dest);
- if (old_jump && fall_thru_label)
+ if (old_jump && JUMP_P (old_jump) && fall_thru_label)
invert_worked = invert_jump (old_jump,
fall_thru_label,0);
if (invert_worked)
/* This is the case where both edges out of the basic
block are crossing edges. Here we will fix up the
fall through edge. The jump edge will be taken care
- of later. */
-
+ of later. The EDGE_CROSSING flag of fall_thru edge
+ is unset before the call to force_nonfallthru
+ function because if a new basic-block is created
+ this edge remains in the current section boundary
+ while the edge between new_bb and the fall_thru->dest
+ becomes EDGE_CROSSING. */
+
+ fall_thru->flags &= ~EDGE_CROSSING;
new_bb = force_nonfallthru (fall_thru);
if (new_bb)
BB_COPY_PARTITION (new_bb, cur_bb);
single_succ_edge (new_bb)->flags |= EDGE_CROSSING;
}
+ else
+ {
+ /* If a new basic-block was not created; restore
+ the EDGE_CROSSING flag. */
+ fall_thru->flags |= EDGE_CROSSING;
+ }
/* Add barrier after new jump */
}
}
-/* This function checks the destination blockof a "crossing jump" to
+/* This function checks the destination block of a "crossing jump" to
see if it has any crossing predecessors that begin with a code label
and end with an unconditional jump. If so, it returns that predecessor
block. (This is to avoid creating lots of new basic blocks that all
FOR_EACH_EDGE (e, ei, bb->succs)
if ((e->flags & EDGE_CROSSING)
&& JUMP_P (BB_END (e->src)))
- REG_NOTES (BB_END (e->src)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
- NULL_RTX,
- REG_NOTES (BB_END
- (e->src)));
+ add_reg_note (BB_END (e->src), REG_CROSSING_JUMP, NULL_RTX);
}
/* Hot and cold basic blocks are partitioned and put in separate
{
if (targetm.cannot_modify_jumps_p ())
return false;
- return (optimize > 0 && flag_expensive_optimizations && !optimize_size);
+ return (optimize > 0
+ && flag_expensive_optimizations
+ && ! optimize_function_for_size_p (cfun));
}
return 0;
}
-struct tree_opt_pass pass_duplicate_computed_gotos =
+struct rtl_opt_pass pass_duplicate_computed_gotos =
{
+ {
+ RTL_PASS,
"compgotos", /* name */
gate_duplicate_computed_gotos, /* gate */
duplicate_computed_gotos, /* execute */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
- 0 /* letter */
+ }
};
static void
partition_hot_cold_basic_blocks (void)
{
- basic_block cur_bb;
edge *crossing_edges;
int n_crossing_edges;
int max_edges = 2 * last_basic_block;
crossing_edges = XCNEWVEC (edge, max_edges);
- cfg_layout_initialize (0);
-
- FOR_EACH_BB (cur_bb)
- if (cur_bb->index >= NUM_FIXED_BLOCKS
- && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
- cur_bb->aux = cur_bb->next_bb;
-
find_rarely_executed_basic_blocks_and_crossing_edges (&crossing_edges,
&n_crossing_edges,
&max_edges);
fix_edges_for_rarely_executed_code (crossing_edges, n_crossing_edges);
free (crossing_edges);
-
- cfg_layout_finalize ();
}
\f
static bool
splitting possibly introduced more crossjumping opportunities. */
cfg_layout_initialize (CLEANUP_EXPENSIVE);
- if (flag_reorder_blocks || flag_reorder_blocks_and_partition)
+ if ((flag_reorder_blocks || flag_reorder_blocks_and_partition)
+ /* Don't reorder blocks when optimizing for size because extra jump insns may
+ be created; also barrier may create extra padding.
+
+ More correctly we should have a block reordering mode that tried to
+ minimize the combined size of all the jumps. This would more or less
+ automatically remove extra jumps, but would also try to use more short
+ jumps instead of long jumps. */
+ && optimize_function_for_speed_p (cfun))
{
reorder_basic_blocks ();
cleanup_cfg (CLEANUP_EXPENSIVE);
return 0;
}
-struct tree_opt_pass pass_reorder_blocks =
+struct rtl_opt_pass pass_reorder_blocks =
{
+ {
+ RTL_PASS,
"bbro", /* name */
gate_handle_reorder_blocks, /* gate */
rest_of_handle_reorder_blocks, /* execute */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
- 'B' /* letter */
+ }
};
static bool
return 0;
}
-struct tree_opt_pass pass_partition_blocks =
+struct rtl_opt_pass pass_partition_blocks =
{
+ {
+ RTL_PASS,
"bbpart", /* name */
gate_handle_partition_blocks, /* gate */
rest_of_handle_partition_blocks, /* execute */
NULL, /* next */
0, /* static_pass_number */
TV_REORDER_BLOCKS, /* tv_id */
- 0, /* properties_required */
+ PROP_cfglayout, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func | TODO_verify_rtl_sharing,/* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */
+ }
};
-
-