Fix problems with hot/cold partitioning optimization.

From-SVN: r97322
This commit is contained in:
Caroline Tice 2005-03-31 06:59:59 -08:00
parent 68ec3111c0
commit 87c8b4bed3
27 changed files with 618 additions and 511 deletions

View File

@ -1874,7 +1874,7 @@ rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \
$(FLAGS_H) function.h $(EXPR_H) hard-reg-set.h $(REGS_H) \
output.h $(C_PRAGMA_H) toplev.h xcoffout.h debug.h $(GGC_H) $(TM_P_H) \
$(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h real.h
$(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h real.h $(BASIC_BLOCK_H)
function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) $(CFGLAYOUT_H) $(TREE_GIMPLE_H) \
$(FLAGS_H) function.h $(EXPR_H) $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h \
@ -2174,7 +2174,7 @@ lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
$(RTL_H) $(GGC_H) gt-lists.h
bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(RTL_H) $(BASIC_BLOCK_H) $(FLAGS_H) $(TIMEVAR_H) output.h $(CFGLAYOUT_H) $(FIBHEAP_H) \
$(TARGET_H) function.h $(TM_P_H) $(OBSTACK_H) $(EXPR_H) $(REGS_H)
$(TARGET_H) function.h $(TM_P_H) $(OBSTACK_H) $(EXPR_H) $(REGS_H) errors.h
tracer.o : tracer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
$(BASIC_BLOCK_H) hard-reg-set.h output.h $(CFGLAYOUT_H) $(FLAGS_H) $(TIMEVAR_H) \
$(PARAMS_H) $(COVERAGE_H)
@ -3731,7 +3731,7 @@ STAGEPROFILE_FLAGS_TO_PASS = \
# Files never linked into the final executable produces warnings about missing
# profile.
STAGEFEEDBACK_FLAGS_TO_PASS = \
CFLAGS="$(BOOT_CFLAGS) -fprofile-use"
CFLAGS="$(BOOT_CFLAGS) -fprofile-use -freorder-blocks-and-partition"
# Only build the C compiler for stage1, because that is the only one that
# we can guarantee will build with the native compiler, and also it is the

View File

@ -81,6 +81,7 @@
#include "tm_p.h"
#include "obstack.h"
#include "expr.h"
#include "errors.h"
#include "params.h"
/* The number of rounds. In most cases there will only be 4 rounds, but
@ -119,6 +120,9 @@ typedef struct bbro_basic_block_data_def
/* Which trace is the bb end of (-1 means it is not an end of a trace). */
int end_of_trace;
/* Which trace is the bb in? */
int in_trace;
/* Which heap is BB in (if any)? */
fibheap_t heap;
@ -169,11 +173,9 @@ static void connect_traces (int, struct trace *);
static bool copy_bb_p (basic_block, int);
static int get_uncond_jump_length (void);
static bool push_to_next_round_p (basic_block, int, int, int, gcov_type);
static void add_unlikely_executed_notes (void);
static void find_rarely_executed_basic_blocks_and_crossing_edges (edge *,
int *,
int *);
static void mark_bb_for_unlikely_executed_section (basic_block);
static void add_labels_and_missing_jumps (edge *, int);
static void add_reg_crossing_jump_notes (void);
static void fix_up_fall_thru_edges (void);
@ -194,26 +196,16 @@ push_to_next_round_p (basic_block bb, int round, int number_of_rounds,
int exec_th, gcov_type count_th)
{
bool there_exists_another_round;
bool cold_block;
bool block_not_hot_enough;
bool next_round_is_last;
there_exists_another_round = round < number_of_rounds - 1;
next_round_is_last = round + 1 == number_of_rounds - 1;
cold_block = (flag_reorder_blocks_and_partition
&& BB_PARTITION (bb) == BB_COLD_PARTITION);
block_not_hot_enough = (bb->frequency < exec_th
|| bb->count < count_th
|| probably_never_executed_bb_p (bb));
if (flag_reorder_blocks_and_partition
&& next_round_is_last
&& BB_PARTITION (bb) != BB_COLD_PARTITION)
return false;
else if (there_exists_another_round
&& (cold_block || block_not_hot_enough))
if (there_exists_another_round
&& block_not_hot_enough)
return true;
else
return false;
@ -237,8 +229,6 @@ find_traces (int *n_traces, struct trace *traces)
cold blocks (and ONLY the cold blocks). */
number_of_rounds = N_ROUNDS - 1;
if (flag_reorder_blocks_and_partition)
number_of_rounds = N_ROUNDS;
/* Insert entry points of function into heap. */
heap = fibheap_new ();
@ -434,11 +424,6 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
struct trace *traces, int *n_traces, int round,
fibheap_t *heap, int number_of_rounds)
{
/* The following variable refers to the last round in which non-"cold"
blocks may be collected into a trace. */
int last_round = N_ROUNDS - 1;
/* Heap for discarded basic blocks which are possible starting points for
the next round. */
fibheap_t new_heap = fibheap_new ();
@ -481,6 +466,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
trace->first = bb;
trace->round = round;
trace->length = 0;
bbd[bb->index].in_trace = *n_traces;
(*n_traces)++;
do
@ -514,8 +500,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
&& e->dest->rbi->visited != *n_traces)
continue;
if (BB_PARTITION (e->dest) == BB_COLD_PARTITION
&& round < last_round)
if (BB_PARTITION (e->dest) != BB_PARTITION (bb))
continue;
prob = e->probability;
@ -646,6 +631,8 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
best_edge->dest->index, bb->index);
}
bb->rbi->next = best_edge->dest;
bbd[best_edge->dest->index].in_trace =
(*n_traces) - 1;
bb = rotate_loop (best_edge, trace, *n_traces);
}
}
@ -658,6 +645,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
{
bb = copy_bb (best_edge->dest, best_edge, bb,
*n_traces);
trace->length++;
}
}
}
@ -695,7 +683,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
&& !e->dest->rbi->visited
&& single_pred_p (e->dest)
&& !(e->flags & EDGE_CROSSING)
&& single_succ_p (e->dest) == 1
&& single_succ_p (e->dest)
&& (single_succ_edge (e->dest)->flags
& EDGE_CAN_FALLTHRU)
&& !(single_succ_edge (e->dest)->flags & EDGE_COMPLEX)
@ -710,6 +698,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
}
bb->rbi->next = best_edge->dest;
bbd[best_edge->dest->index].in_trace = (*n_traces) - 1;
bb = best_edge->dest;
}
}
@ -788,6 +777,7 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace)
for (i = array_size; i < new_size; i++)
{
bbd[i].start_of_trace = -1;
bbd[i].in_trace = -1;
bbd[i].end_of_trace = -1;
bbd[i].heap = NULL;
bbd[i].node = NULL;
@ -802,6 +792,8 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace)
}
}
bbd[new_bb->index].in_trace = trace;
return new_bb;
}
@ -899,11 +891,11 @@ static void
connect_traces (int n_traces, struct trace *traces)
{
int i;
int unconnected_hot_trace_count = 0;
bool cold_connected = true;
bool *connected;
bool *cold_traces;
bool two_passes;
int last_trace;
int current_pass;
int current_partition;
int freq_threshold;
gcov_type count_threshold;
@ -915,66 +907,47 @@ connect_traces (int n_traces, struct trace *traces)
connected = xcalloc (n_traces, sizeof (bool));
last_trace = -1;
/* If we are partitioning hot/cold basic blocks, mark the cold
traces as already connected, to remove them from consideration
for connection to the hot traces. After the hot traces have all
been connected (determined by "unconnected_hot_trace_count"), we
will go back and connect the cold traces. */
cold_traces = xcalloc (n_traces, sizeof (bool));
current_pass = 1;
current_partition = BB_PARTITION (traces[0].first);
two_passes = false;
if (flag_reorder_blocks_and_partition)
for (i = 0; i < n_traces; i++)
{
if (BB_PARTITION (traces[i].first) == BB_COLD_PARTITION)
{
connected[i] = true;
cold_traces[i] = true;
cold_connected = false;
}
else
unconnected_hot_trace_count++;
}
for (i = 0; i < n_traces || !cold_connected ; i++)
for (i = 0; i < n_traces && !two_passes; i++)
if (BB_PARTITION (traces[0].first)
!= BB_PARTITION (traces[i].first))
two_passes = true;
for (i = 0; i < n_traces || (two_passes && current_pass == 1) ; i++)
{
int t = i;
int t2;
edge e, best;
int best_len;
/* If we are partitioning hot/cold basic blocks, check to see
if all the hot traces have been connected. If so, go back
and mark the cold traces as unconnected so we can connect
them up too. Re-set "i" to the first (unconnected) cold
trace. Use flag "cold_connected" to make sure we don't do
this step more than once. */
if (flag_reorder_blocks_and_partition
&& (i >= n_traces || unconnected_hot_trace_count <= 0)
&& !cold_connected)
if (i >= n_traces)
{
int j;
int first_cold_trace = -1;
for (j = 0; j < n_traces; j++)
if (cold_traces[j])
{
connected[j] = false;
if (first_cold_trace == -1)
first_cold_trace = j;
}
i = t = first_cold_trace;
cold_connected = true;
if (two_passes && current_pass == 1)
{
i = 0;
t = i;
current_pass = 2;
if (current_partition == BB_HOT_PARTITION)
current_partition = BB_COLD_PARTITION;
else
current_partition = BB_HOT_PARTITION;
}
else
abort ();
}
if (connected[t])
continue;
if (two_passes
&& BB_PARTITION (traces[t].first) != current_partition)
continue;
connected[t] = true;
if (unconnected_hot_trace_count > 0)
unconnected_hot_trace_count--;
/* Find the predecessor traces. */
for (t2 = t; t2 > 0;)
@ -991,6 +964,7 @@ connect_traces (int n_traces, struct trace *traces)
&& !(e->flags & EDGE_COMPLEX)
&& bbd[si].end_of_trace >= 0
&& !connected[bbd[si].end_of_trace]
&& (BB_PARTITION (e->src) == current_partition)
&& (!best
|| e->probability > best->probability
|| (e->probability == best->probability
@ -1006,9 +980,6 @@ connect_traces (int n_traces, struct trace *traces)
t2 = bbd[best->src->index].end_of_trace;
connected[t2] = true;
if (unconnected_hot_trace_count > 0)
unconnected_hot_trace_count--;
if (dump_file)
{
fprintf (dump_file, "Connection: %d %d\n",
@ -1039,6 +1010,7 @@ connect_traces (int n_traces, struct trace *traces)
&& !(e->flags & EDGE_COMPLEX)
&& bbd[di].start_of_trace >= 0
&& !connected[bbd[di].start_of_trace]
&& (BB_PARTITION (e->dest) == current_partition)
&& (!best
|| e->probability > best->probability
|| (e->probability == best->probability
@ -1059,8 +1031,6 @@ connect_traces (int n_traces, struct trace *traces)
t = bbd[best->dest->index].start_of_trace;
traces[last_trace].last->rbi->next = traces[t].first;
connected[t] = true;
if (unconnected_hot_trace_count > 0)
unconnected_hot_trace_count--;
last_trace = t;
}
else
@ -1101,6 +1071,7 @@ connect_traces (int n_traces, struct trace *traces)
&& !(e2->flags & EDGE_COMPLEX)
&& bbd[di].start_of_trace >= 0
&& !connected[bbd[di].start_of_trace]
&& (BB_PARTITION (e2->dest) == current_partition)
&& (EDGE_FREQUENCY (e2) >= freq_threshold)
&& (e2->count >= count_threshold)
&& (!best2
@ -1153,8 +1124,6 @@ connect_traces (int n_traces, struct trace *traces)
t = bbd[next_bb->index].start_of_trace;
traces[last_trace].last->rbi->next = traces[t].first;
connected[t] = true;
if (unconnected_hot_trace_count > 0)
unconnected_hot_trace_count--;
last_trace = t;
}
else
@ -1178,7 +1147,6 @@ connect_traces (int n_traces, struct trace *traces)
}
FREE (connected);
FREE (cold_traces);
}
/* Return true when BB can and should be copied. CODE_MAY_GROW is true
@ -1242,18 +1210,6 @@ get_uncond_jump_length (void)
return length;
}
static void
add_unlikely_executed_notes (void)
{
basic_block bb;
/* Add the UNLIKELY_EXECUTED_NOTES to each cold basic block. */
FOR_EACH_BB (bb)
if (BB_PARTITION (bb) == BB_COLD_PARTITION)
mark_bb_for_unlikely_executed_section (bb);
}
/* Find the basic blocks that are rarely executed and need to be moved to
a separate section of the .o file (to cut down on paging and improve
cache locality). */
@ -1282,18 +1238,6 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges,
}
}
/* Since all "hot" basic blocks will eventually be scheduled before all
cold basic blocks, make *sure* the real function entry block is in
the hot partition (if there is one). */
if (has_hot_blocks)
FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
if (e->dest->index >= 0)
{
BB_SET_PARTITION (e->dest, BB_HOT_PARTITION);
break;
}
/* Mark every edge that crosses between sections. */
i = 0;
@ -1322,39 +1266,6 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges,
*n_crossing_edges = i;
}
/* Add NOTE_INSN_UNLIKELY_EXECUTED_CODE to top of basic block. This note
is later used to mark the basic block to be put in the
unlikely-to-be-executed section of the .o file. */
static void
mark_bb_for_unlikely_executed_section (basic_block bb)
{
rtx cur_insn;
rtx insert_insn = NULL;
rtx new_note;
/* Insert new NOTE immediately after BASIC_BLOCK note. */
for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
cur_insn = NEXT_INSN (cur_insn))
if (GET_CODE (cur_insn) == NOTE
&& NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_BASIC_BLOCK)
{
insert_insn = cur_insn;
break;
}
/* If basic block does not contain a NOTE_INSN_BASIC_BLOCK, there is
a major problem. */
gcc_assert (insert_insn);
/* Insert note and assign basic block number to it. */
new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
insert_insn);
NOTE_BASIC_BLOCK (new_note) = bb;
}
/* If any destination of a crossing edge does not have a label, add label;
Convert any fall-through crossing edges (for blocks that do not contain
a jump) to unconditional jumps. */
@ -1782,6 +1693,10 @@ fix_crossing_unconditional_branches (void)
FOR_EACH_BB (cur_bb)
{
last_insn = BB_END (cur_bb);
if (EDGE_COUNT (cur_bb->succs) < 1)
continue;
succ = EDGE_SUCC (cur_bb, 0);
/* Check to see if bb ends in a crossing (unconditional) jump. At
@ -1864,19 +1779,19 @@ add_reg_crossing_jump_notes (void)
(e->src)));
}
/* Basic blocks containing NOTE_INSN_UNLIKELY_EXECUTED_CODE will be
put in a separate section of the .o file, to reduce paging and
improve cache performance (hopefully). This can result in bits of
code from the same function being widely separated in the .o file.
However this is not obvious to the current bb structure. Therefore
we must take care to ensure that: 1). There are no fall_thru edges
that cross between sections; 2). For those architectures which
have "short" conditional branches, all conditional branches that
attempt to cross between sections are converted to unconditional
branches; and, 3). For those architectures which have "short"
unconditional branches, all unconditional branches that attempt
to cross between sections are converted to indirect jumps.
/* Hot and cold basic blocks are partitioneed and put in separate
sections of the .o file, to reduce paging and improve cache
performance (hopefully). This can result in bits of code from the
same function being widely separated in the .o file. However this
is not obvious to the current bb structure. Therefore we must take
care to ensure that: 1). There are no fall_thru edges that cross
between sections; 2). For those architectures which have "short"
conditional branches, all conditional branches that attempt to
cross between sections are converted to unconditional branches;
and, 3). For those architectures which have "short" unconditional
branches, all unconditional branches that attempt to cross between
sections are converted to indirect jumps.
The code for fixing up fall_thru edges that cross between hot and
cold basic blocks does so by creating new basic blocks containing
unconditional branches to the appropriate label in the "other"
@ -1942,6 +1857,44 @@ fix_edges_for_rarely_executed_code (edge *crossing_edges,
}
}
/* Verify, in the basic block chain, that there is at most one switch
between hot/cold partitions. This is modelled on
rtl_verify_flow_info_1, but it cannot go inside that function
because this condition will not be true until after
reorder_basic_blocks is called. */
static void
verify_hot_cold_block_grouping (void)
{
basic_block bb;
int err = 0;
bool switched_sections = false;
int current_partition = 0;
FOR_EACH_BB (bb)
{
if (!current_partition)
current_partition = BB_PARTITION (bb);
if (BB_PARTITION (bb) != current_partition)
{
if (switched_sections)
{
error ("Multiple hot/cold transitions found (bb %i)",
bb->index);
err = 1;
}
else
{
switched_sections = true;
current_partition = BB_PARTITION (bb);
}
}
}
if (err)
internal_error ("verify_hot_cold_block_grouping failed");
}
/* Reorder basic blocks. The main entry point to this file. FLAGS is
the set of flags to pass to cfg_layout_initialize(). */
@ -1976,6 +1929,7 @@ reorder_basic_blocks (unsigned int flags)
for (i = 0; i < array_size; i++)
{
bbd[i].start_of_trace = -1;
bbd[i].in_trace = -1;
bbd[i].end_of_trace = -1;
bbd[i].heap = NULL;
bbd[i].node = NULL;
@ -1991,15 +1945,42 @@ reorder_basic_blocks (unsigned int flags)
if (dump_file)
dump_flow_info (dump_file);
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
add_unlikely_executed_notes ();
cfg_layout_finalize ();
verify_hot_cold_block_grouping ();
timevar_pop (TV_REORDER_BLOCKS);
}
/* Determine which partition the first basic block in the function
belongs to, then find the first basic block in the current function
that belongs to a different section, and insert a
NOTE_INSN_SWITCH_TEXT_SECTIONS note immediately before it in the
instruction stream. When writing out the assembly code,
encountering this note will make the compiler switch between the
hot and cold text sections. */
void
insert_section_boundary_note (void)
{
basic_block bb;
rtx new_note;
int first_partition = 0;
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
FOR_EACH_BB (bb)
{
if (!first_partition)
first_partition = BB_PARTITION (bb);
if (BB_PARTITION (bb) != first_partition)
{
new_note = emit_note_before (NOTE_INSN_SWITCH_TEXT_SECTIONS,
BB_HEAD (bb));
break;
}
}
}
/* Duplicate the blocks containing computed gotos. This basically unfactors
computed gotos that were factored early on in the compilation process to
speed up edge based data flow. We used to not unfactoring them again,
@ -2041,7 +2022,8 @@ duplicate_computed_gotos (void)
/* If the block ends in a computed jump and it is small enough,
make it a candidate for duplication. */
if (computed_jump_p (BB_END (bb)))
if (computed_jump_p (BB_END (bb))
&& !find_reg_note (BB_END (bb), REG_CROSSING_JUMP, NULL_RTX))
{
rtx insn;
int size = 0;
@ -2110,15 +2092,14 @@ done:
function above).
This optimization checks the feedback information to determine
which basic blocks are hot/cold and causes reorder_basic_blocks to
add NOTE_INSN_UNLIKELY_EXECUTED_CODE to non-hot basic blocks. The
presence or absence of this note is later used for writing out
sections in the .o file. Because hot and cold sections can be
arbitrarily large (within the bounds of memory), far beyond the
size of a single function, it is necessary to fix up all edges that
cross section boundaries, to make sure the instructions used can
actually span the required distance. The fixes are described
below.
which basic blocks are hot/cold, updates flags on the basic blocks
to indicate which section they belong in. This information is
later used for writing out sections in the .o file. Because hot
and cold sections can be arbitrarily large (within the bounds of
memory), far beyond the size of a single function, it is necessary
to fix up all edges that cross section boundaries, to make sure the
instructions used can actually span the required distance. The
fixes are described below.
Fall-through edges must be changed into jumps; it is not safe or
legal to fall through across a section boundary. Whenever a

View File

@ -155,9 +155,8 @@ try_simplify_condjump (basic_block cbranch_block)
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
&& (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
|| (cbranch_jump_edge->flags & EDGE_CROSSING)))
if (BB_PARTITION (jump_block) != BB_PARTITION (jump_dest_block)
|| (cbranch_jump_edge->flags & EDGE_CROSSING))
return false;
/* The conditional branch must target the block after the
@ -435,8 +434,7 @@ try_forward_edges (int mode, basic_block b)
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
&& find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
if (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX))
return false;
for (ei = ei_start (b->succs); (e = ei_safe_edge (ei)); )
@ -471,8 +469,7 @@ try_forward_edges (int mode, basic_block b)
bb-reorder.c:partition_hot_cold_basic_blocks for complete
details. */
if (flag_reorder_blocks_and_partition
&& first != EXIT_BLOCK_PTR
if (first != EXIT_BLOCK_PTR
&& find_reg_note (BB_END (first), REG_CROSSING_JUMP, NULL_RTX))
return false;
@ -684,9 +681,7 @@ merge_blocks_move_predecessor_nojumps (basic_block a, basic_block b)
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
&& (BB_PARTITION (a) != BB_PARTITION (b)
|| find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)))
if (BB_PARTITION (a) != BB_PARTITION (b))
return;
barrier = next_nonnote_insn (BB_END (a));
@ -742,9 +737,7 @@ merge_blocks_move_successor_nojumps (basic_block a, basic_block b)
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
&& (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (a) != BB_PARTITION (b)))
if (BB_PARTITION (a) != BB_PARTITION (b))
return;
real_b_end = BB_END (b);
@ -814,10 +807,7 @@ merge_blocks_move (edge e, basic_block b, basic_block c, int mode)
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
&& (find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
|| find_reg_note (BB_END (c), REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (b) != BB_PARTITION (c)))
if (BB_PARTITION (b) != BB_PARTITION (c))
return NULL;
@ -1725,9 +1715,9 @@ try_crossjump_bb (int mode, basic_block bb)
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
&& (BB_PARTITION (EDGE_PRED (bb, 0)->src) != BB_PARTITION (EDGE_PRED (bb, 1)->src)
|| (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING)))
if (BB_PARTITION (EDGE_PRED (bb, 0)->src) !=
BB_PARTITION (EDGE_PRED (bb, 1)->src)
|| (EDGE_PRED (bb, 0)->flags & EDGE_CROSSING))
return false;
/* It is always cheapest to redirect a block that ends in a branch to

View File

@ -51,7 +51,6 @@ static void change_scope (rtx, tree, tree);
void verify_insn_chain (void);
static void fixup_fallthru_exit_predecessor (void);
static tree insn_scope (rtx);
static void update_unlikely_executed_notes (basic_block);
rtx
unlink_insn_chain (rtx first, rtx last)
@ -784,28 +783,12 @@ fixup_reorder_chain (void)
section boundaries). */
BB_COPY_PARTITION (e_fall->src, single_pred (bb));
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{
if (BB_PARTITION (single_pred (bb)) == BB_COLD_PARTITION)
{
rtx new_note;
rtx note = BB_HEAD (e_fall->src);
while (!INSN_P (note)
&& note != BB_END (e_fall->src))
note = NEXT_INSN (note);
new_note = emit_note_before
(NOTE_INSN_UNLIKELY_EXECUTED_CODE,
note);
NOTE_BASIC_BLOCK (new_note) = bb;
}
if (JUMP_P (BB_END (bb))
&& !any_condjump_p (BB_END (bb))
&& (single_succ_edge (bb)->flags & EDGE_CROSSING))
REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
(REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
}
&& targetm.have_named_sections
&& JUMP_P (BB_END (bb))
&& !any_condjump_p (BB_END (bb))
&& (EDGE_SUCC (bb, 0)->flags & EDGE_CROSSING))
REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
(REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
}
}
@ -840,8 +823,6 @@ fixup_reorder_chain (void)
bb->index = index;
BASIC_BLOCK (index) = bb;
update_unlikely_executed_notes (bb);
bb->prev_bb = prev_bb;
prev_bb->next_bb = bb;
}
@ -863,21 +844,6 @@ fixup_reorder_chain (void)
}
}
/* Update the basic block number information in any
NOTE_INSN_UNLIKELY_EXECUTED_CODE notes within the basic block. */
static void
update_unlikely_executed_notes (basic_block bb)
{
rtx cur_insn;
for (cur_insn = BB_HEAD (bb); cur_insn != BB_END (bb);
cur_insn = NEXT_INSN (cur_insn))
if (NOTE_P (cur_insn)
&& NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
NOTE_BASIC_BLOCK (cur_insn) = bb;
}
/* Perform sanity checks on the insn chain.
1. Check that next/prev pointers are consistent in both the forward and
reverse direction.
@ -1046,7 +1012,7 @@ duplicate_insn_chain (rtx from, rtx to)
break;
case NOTE_INSN_REPEATED_LINE_NUMBER:
case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
emit_note_copy (insn);
break;

View File

@ -32,7 +32,6 @@ extern void reemit_insn_block_notes (void);
extern bool can_copy_bbs_p (basic_block *, unsigned);
extern void copy_bbs (basic_block *, unsigned, basic_block *,
edge *, unsigned, edge *, struct loop *);
extern bool scan_ahead_for_unlikely_executed_note (rtx);
extern rtx duplicate_insn_chain (rtx, rtx);
#endif /* GCC_CFGLAYOUT_H */

View File

@ -92,8 +92,7 @@ static int
can_delete_note_p (rtx note)
{
return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_UNLIKELY_EXECUTED_CODE);
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
}
/* True if a given label can be deleted. */
@ -616,10 +615,7 @@ rtl_can_merge_blocks (basic_block a,basic_block b)
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
&& (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
|| find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (a) != BB_PARTITION (b)))
if (BB_PARTITION (a) != BB_PARTITION (b))
return false;
/* There must be exactly one edge in between the blocks. */
@ -678,9 +674,8 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
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
&& (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (src) != BB_PARTITION (target)))
if (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (src) != BB_PARTITION (target))
return NULL;
/* We can replace or remove a complex jump only when we have exactly
@ -1108,29 +1103,16 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
BB_COPY_PARTITION (jump_block, e->src);
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{
if (BB_PARTITION (jump_block) == BB_COLD_PARTITION)
{
rtx bb_note, new_note;
for (bb_note = BB_HEAD (jump_block);
bb_note && bb_note != NEXT_INSN (BB_END (jump_block));
bb_note = NEXT_INSN (bb_note))
if (NOTE_P (bb_note)
&& NOTE_LINE_NUMBER (bb_note) == NOTE_INSN_BASIC_BLOCK)
break;
new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
bb_note);
NOTE_BASIC_BLOCK (new_note) = jump_block;
}
if (JUMP_P (BB_END (jump_block))
&& !any_condjump_p (BB_END (jump_block))
&& (single_succ_edge (jump_block)->flags & EDGE_CROSSING))
REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST
(REG_CROSSING_JUMP, NULL_RTX,
REG_NOTES (BB_END (jump_block)));
}
&& targetm.have_named_sections
&& JUMP_P (BB_END (jump_block))
&& !any_condjump_p (BB_END (jump_block))
&& (EDGE_SUCC (jump_block, 0)->flags & EDGE_CROSSING))
REG_NOTES (BB_END (jump_block)) = gen_rtx_EXPR_LIST (REG_CROSSING_JUMP,
NULL_RTX,
REG_NOTES
(BB_END
(jump_block)));
/* Wire edge in. */
new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
new_edge->probability = e->probability;
@ -1576,10 +1558,6 @@ commit_one_edge_insertion (edge e, int watch_calls)
tmp = NEXT_INSN (tmp);
if (NOTE_INSN_BASIC_BLOCK_P (tmp))
tmp = NEXT_INSN (tmp);
if (tmp
&& NOTE_P (tmp)
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
tmp = NEXT_INSN (tmp);
if (tmp == BB_HEAD (bb))
before = tmp;
else if (tmp)
@ -1629,7 +1607,7 @@ commit_one_edge_insertion (edge e, int watch_calls)
&& BB_PARTITION (e->src) == BB_COLD_PARTITION
&& !(e->flags & EDGE_CROSSING))
{
rtx bb_note, new_note, cur_insn;
rtx bb_note, cur_insn;
bb_note = NULL_RTX;
for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
@ -1641,16 +1619,11 @@ commit_one_edge_insertion (edge e, int watch_calls)
break;
}
new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
bb_note);
NOTE_BASIC_BLOCK (new_note) = bb;
if (JUMP_P (BB_END (bb))
&& !any_condjump_p (BB_END (bb))
&& (single_succ_edge (bb)->flags & EDGE_CROSSING))
REG_NOTES (BB_END (bb)) = gen_rtx_EXPR_LIST
(REG_CROSSING_JUMP, NULL_RTX, REG_NOTES (BB_END (bb)));
if (after == bb_note)
after = new_note;
}
}
}
@ -2717,10 +2690,7 @@ cfg_layout_can_merge_blocks_p (basic_block a, basic_block b)
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
&& (find_reg_note (BB_END (a), REG_CROSSING_JUMP, NULL_RTX)
|| find_reg_note (BB_END (b), REG_CROSSING_JUMP, NULL_RTX)
|| BB_PARTITION (a) != BB_PARTITION (b)))
if (BB_PARTITION (a) != BB_PARTITION (b))
return false;
/* There must be exactly one edge in between the blocks. */

View File

@ -1016,12 +1016,17 @@ machopic_select_section (tree exp, int reloc,
bool weak_p = DECL_P (exp) && DECL_WEAK (exp);
static void (* const base_funs[][2])(void) = {
{ text_section, text_coal_section },
{ text_unlikely_section, text_unlikely_coal_section },
{ unlikely_text_section, text_unlikely_coal_section },
{ readonly_data_section, const_coal_section },
{ const_data_section, const_data_coal_section },
{ data_section, data_coal_section }
};
if (reloc == 0
&& (last_text_section == in_text_unlikely
|| last_text_section == in_text_unlikely_coal))
reloc = 1;
if (TREE_CODE (exp) == FUNCTION_DECL)
base_function = base_funs[reloc][weak_p];
else if (decl_readonly_section_1 (exp, reloc, MACHOPIC_INDIRECT))

View File

@ -621,6 +621,10 @@ FUNCTION (void) \
if (asm_out_file) \
fputs ("\t" DIRECTIVE "\n", asm_out_file); \
in_section = SECTION; \
if ((SECTION == in_text_coal) \
|| (SECTION == in_text_unlikely) \
|| (SECTION == in_text_unlikely_coal)) \
last_text_section = SECTION; \
} \
} \
@ -660,10 +664,6 @@ SECTION_FUNCTION (text_coal_section, \
in_text_coal, \
".section __TEXT,__textcoal_nt,coalesced," \
"pure_instructions", 0) \
SECTION_FUNCTION (text_unlikely_section, \
in_text_unlikely, \
".section __TEXT,__text_unlikely,coalesced," \
"pure_instructions", 0) \
SECTION_FUNCTION (text_unlikely_coal_section, \
in_text_unlikely_coal, \
".section __TEXT,__text_unlikely_coal," \

View File

@ -8201,7 +8201,7 @@ sparc_output_deferred_case_vectors (void)
return;
/* Align to cache line in the function's code section. */
function_section (current_function_decl);
current_function_section (current_function_decl);
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)

View File

@ -2074,7 +2074,7 @@ xstormy16_output_addr_vec (FILE *file, rtx label ATTRIBUTE_UNUSED, rtx table)
{
int vlen, idx;
function_section (current_function_decl);
current_function_section (current_function_decl);
vlen = XVECLEN (table, 0);
for (idx = 0; idx < vlen; idx++)

View File

@ -1560,6 +1560,15 @@ override_options (void)
/* There's no need for -fPIC (as opposed to -fpic) on Xtensa. */
if (flag_pic > 1)
flag_pic = 1;
/* Hot/cold partitioning does not work on this architecture, because of
constant pools (the load instruction cannot necessarily reach that far).
Therefore disable it on this architecture. */
if (flag_reorder_blocks_and_partition)
{
flag_reorder_blocks_and_partition = 0;
flag_reorder_blocks = 1;
}
}

View File

@ -275,7 +275,7 @@ static int pending_bincls = 0;
static const char *base_input_file;
#ifdef DEBUG_SYMS_TEXT
#define FORCE_TEXT function_section (current_function_decl);
#define FORCE_TEXT current_function_section (current_function_decl);
#else
#define FORCE_TEXT
#endif
@ -379,6 +379,7 @@ const struct gcc_debug_hooks dbx_debug_hooks =
debug_nothing_rtx, /* label */
dbxout_handle_pch, /* handle_pch */
debug_nothing_rtx, /* var_location */
debug_nothing_void, /* switch_text_section */
0 /* start_end_main_source_file */
};
#endif /* DBX_DEBUGGING_INFO */
@ -410,6 +411,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks =
debug_nothing_rtx, /* label */
dbxout_handle_pch, /* handle_pch */
debug_nothing_rtx, /* var_location */
debug_nothing_void, /* switch_text_section */
0 /* start_end_main_source_file */
};
#endif /* XCOFF_DEBUGGING_INFO */
@ -934,9 +936,21 @@ dbxout_function_end (tree decl)
#ifdef DBX_OUTPUT_NFUN
DBX_OUTPUT_NFUN (asm_out_file, lscope_label_name, current_function_decl);
#else
dbxout_begin_empty_stabs (N_FUN);
dbxout_stab_value_label_diff (lscope_label_name,
XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
if (flag_reorder_blocks_and_partition)
{
dbxout_begin_empty_stabs (N_FUN);
dbxout_stab_value_label_diff (hot_section_end_label, hot_section_label);
dbxout_begin_empty_stabs (N_FUN);
dbxout_stab_value_label_diff (cold_section_end_label,
unlikely_section_label);
}
else
{
dbxout_begin_empty_stabs (N_FUN);
dbxout_stab_value_label_diff (lscope_label_name,
XSTR (XEXP (DECL_RTL (current_function_decl),
0), 0));
}
#endif

View File

@ -48,6 +48,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks =
debug_nothing_rtx, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx, /* var_location */
debug_nothing_void, /* switch_text_section */
0 /* start_end_main_source_file */
};

View File

@ -120,6 +120,10 @@ struct gcc_debug_hooks
/* Called from final_scan_insn for any NOTE_INSN_VAR_LOCATION note. */
void (* var_location) (rtx);
/* Called from final_scan_insn if there is a switch between hot and cold
text sections. */
void (* switch_text_section) (void);
/* This is 1 if the debug writer wants to see start and end commands for the
main source files, and 0 otherwise. */
int start_end_main_source_file;

View File

@ -253,6 +253,11 @@ typedef struct dw_fde_struct GTY(())
const char *dw_fde_begin;
const char *dw_fde_current_label;
const char *dw_fde_end;
const char *dw_fde_hot_section_label;
const char *dw_fde_hot_section_end_label;
const char *dw_fde_unlikely_section_label;
const char *dw_fde_unlikely_section_end_label;
bool dw_fde_switched_sections;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
unsigned all_throwers_are_sibcalls : 1;
@ -2273,17 +2278,57 @@ output_call_frame_info (int for_eh)
dw2_asm_output_encoded_addr_rtx (fde_encoding,
sym_ref,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
if (fde->dw_fde_switched_sections)
{
rtx sym_ref2 = gen_rtx_SYMBOL_REF (Pmode,
fde->dw_fde_unlikely_section_label);
rtx sym_ref3= gen_rtx_SYMBOL_REF (Pmode,
fde->dw_fde_hot_section_label);
SYMBOL_REF_FLAGS (sym_ref2) |= SYMBOL_FLAG_LOCAL;
SYMBOL_REF_FLAGS (sym_ref3) |= SYMBOL_FLAG_LOCAL;
dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref3,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_hot_section_end_label,
fde->dw_fde_hot_section_label,
"FDE address range");
dw2_asm_output_encoded_addr_rtx (fde_encoding, sym_ref2,
"FDE initial location");
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_unlikely_section_end_label,
fde->dw_fde_unlikely_section_label,
"FDE address range");
}
else
dw2_asm_output_delta (size_of_encoded_value (fde_encoding),
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
}
else
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE, fde->dw_fde_begin,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
if (fde->dw_fde_switched_sections)
{
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
fde->dw_fde_hot_section_label,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_hot_section_end_label,
fde->dw_fde_hot_section_label,
"FDE address range");
dw2_asm_output_addr (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_label,
"FDE initial location");
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_unlikely_section_end_label,
fde->dw_fde_unlikely_section_label,
"FDE address range");
}
else
dw2_asm_output_delta (DWARF2_ADDR_SIZE,
fde->dw_fde_end, fde->dw_fde_begin,
"FDE address range");
}
if (augmentation[0])
@ -2409,6 +2454,11 @@ dwarf2out_begin_prologue (unsigned int line ATTRIBUTE_UNUSED,
fde->decl = current_function_decl;
fde->dw_fde_begin = dup_label;
fde->dw_fde_current_label = NULL;
fde->dw_fde_hot_section_label = NULL;
fde->dw_fde_hot_section_end_label = NULL;
fde->dw_fde_unlikely_section_label = NULL;
fde->dw_fde_unlikely_section_end_label = NULL;
fde->dw_fde_switched_sections = false;
fde->dw_fde_end = NULL;
fde->dw_fde_cfi = NULL;
fde->funcdef_number = current_function_funcdef_no;
@ -3418,6 +3468,7 @@ static void dwarf2out_imported_module_or_decl (tree, tree);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx);
static void dwarf2out_begin_function (tree);
static void dwarf2out_switch_text_section (void);
/* The debug hooks structure. */
@ -3450,6 +3501,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
debug_nothing_rtx, /* label */
debug_nothing_int, /* handle_pch */
dwarf2out_var_location,
dwarf2out_switch_text_section,
1 /* start_end_main_source_file */
};
#endif
@ -3651,6 +3703,7 @@ struct var_loc_node GTY ((chain_next ("%h.next")))
{
rtx GTY (()) var_loc_note;
const char * GTY (()) label;
const char * GTY (()) section_label;
struct var_loc_node * GTY (()) next;
};
@ -6742,6 +6795,20 @@ add_loc_descr_to_loc_list (dw_loc_list_ref *list_head, dw_loc_descr_ref descr,
*d = new_loc_list (descr, begin, end, section, 0);
}
static void
dwarf2out_switch_text_section (void)
{
dw_fde_ref fde;
fde = &fde_table[fde_table_in_use - 1];
fde->dw_fde_switched_sections = true;
fde->dw_fde_hot_section_label = xstrdup (hot_section_label);
fde->dw_fde_hot_section_end_label = xstrdup (hot_section_end_label);
fde->dw_fde_unlikely_section_label = xstrdup (unlikely_section_label);
fde->dw_fde_unlikely_section_end_label = xstrdup (cold_section_end_label);
separate_line_info_table_in_use++;
}
/* Output the location list given to us. */
static void
@ -7168,8 +7235,14 @@ output_aranges (void)
}
dw2_asm_output_addr (DWARF2_ADDR_SIZE, text_section_label, "Address");
dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
text_section_label, "Length");
if (last_text_section == in_unlikely_executed_text
|| (last_text_section == in_named
&& last_text_section_name == unlikely_text_section_name))
dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
unlikely_section_label, "Length");
else
dw2_asm_output_delta (DWARF2_ADDR_SIZE, text_end_label,
text_section_label, "Length");
for (i = 0; i < arange_table_in_use; i++)
{
@ -7259,11 +7332,24 @@ output_ranges (void)
base of the text section. */
if (separate_line_info_table_in_use == 0)
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
text_section_label,
fmt, i * 2 * DWARF2_ADDR_SIZE);
dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
text_section_label, NULL);
if (last_text_section == in_unlikely_executed_text
|| (last_text_section == in_named
&& last_text_section_name == unlikely_text_section_name))
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
unlikely_section_label,
fmt, i * 2 * DWARF2_ADDR_SIZE);
dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
unlikely_section_label, NULL);
}
else
{
dw2_asm_output_delta (DWARF2_ADDR_SIZE, blabel,
text_section_label,
fmt, i * 2 * DWARF2_ADDR_SIZE);
dw2_asm_output_delta (DWARF2_ADDR_SIZE, elabel,
text_section_label, NULL);
}
}
/* Otherwise, we add a DW_AT_entry_pc attribute to force the
@ -7648,7 +7734,12 @@ output_line_info (void)
a series of state machine operations. */
current_file = 1;
current_line = 1;
strcpy (prev_line_label, text_section_label);
if (last_text_section == in_unlikely_executed_text
|| (last_text_section == in_named
&& last_text_section_name == unlikely_text_section_name))
strcpy (prev_line_label, unlikely_section_label);
else
strcpy (prev_line_label, text_section_label);
for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
{
dw_line_info_ref line_info = &line_info_table[lt_index];
@ -10028,6 +10119,10 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
tree sectree = DECL_SECTION_NAME (current_function_decl);
secname = TREE_STRING_POINTER (sectree);
}
else if (last_text_section == in_unlikely_executed_text
|| (last_text_section == in_named
&& last_text_section_name == unlikely_text_section_name))
secname = unlikely_section_label;
else
secname = text_section_label;
@ -11334,15 +11429,33 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (!old_die || !get_AT (old_die, DW_AT_inline))
equate_decl_number_to_die (decl, subr_die);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
if (!flag_reorder_blocks_and_partition)
{
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
current_function_funcdef_no);
add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
}
else
{ /* Do nothing for now; maybe need to duplicate die, one for
hot section and ond for cold section, then use the hot/cold
section begin/end labels to generate the aranges... */
/*
add_AT_lbl_id (subr_die, DW_AT_low_pc, hot_section_label);
add_AT_lbl_id (subr_die, DW_AT_high_pc, hot_section_end_label);
add_AT_lbl_id (subr_die, DW_AT_lo_user, unlikely_section_label);
add_AT_lbl_id (subr_die, DW_AT_hi_user, cold_section_end_label);
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
add_pubname (decl, subr_die);
add_arange (decl, subr_die);
add_arange (decl, subr_die);
*/
}
#ifdef MIPS_DEBUGGING_INFO
/* Add a reference to the FDE for this routine. */
@ -12956,7 +13069,7 @@ static void
dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
unsigned int blocknum)
{
function_section (current_function_decl);
current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
}
@ -12966,7 +13079,7 @@ dwarf2out_begin_block (unsigned int line ATTRIBUTE_UNUSED,
static void
dwarf2out_end_block (unsigned int line ATTRIBUTE_UNUSED, unsigned int blocknum)
{
function_section (current_function_decl);
current_function_section (current_function_decl);
ASM_OUTPUT_DEBUG_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
}
@ -13107,6 +13220,13 @@ dwarf2out_var_location (rtx loc_note)
newloc->var_loc_note = loc_note;
newloc->next = NULL;
if (last_text_section == in_unlikely_executed_text
|| (last_text_section == in_named
&& last_text_section_name == unlikely_text_section_name))
newloc->section_label = unlikely_section_label;
else
newloc->section_label = text_section_label;
last_insn = loc_note;
last_label = newloc->label;
decl = NOTE_VAR_LOCATION_DECL (loc_note);
@ -13137,7 +13257,7 @@ dwarf2out_source_line (unsigned int line, const char *filename)
if (debug_info_level >= DINFO_LEVEL_NORMAL
&& line != 0)
{
function_section (current_function_decl);
current_function_section (current_function_decl);
/* If requested, emit something human-readable. */
if (flag_debug_asm)

View File

@ -3434,7 +3434,7 @@ output_function_exception_table (void)
dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
(i ? NULL : "Exception specification table"));
function_section (current_function_decl);
current_function_section (current_function_decl);
}
#include "gt-except.h"

View File

@ -1426,7 +1426,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
}
function_section (current_function_decl);
current_function_section (current_function_decl);
#if defined(ASM_OUTPUT_REG_PUSH)
if (sval && svrtx != NULL_RTX && REG_P (svrtx))
@ -1619,35 +1619,6 @@ output_alternate_entry_point (FILE *file, rtx insn)
}
}
/* Return boolean indicating if there is a NOTE_INSN_UNLIKELY_EXECUTED_CODE
note in the instruction chain (going forward) between the current
instruction, and the next 'executable' instruction. */
bool
scan_ahead_for_unlikely_executed_note (rtx insn)
{
rtx temp;
int bb_note_count = 0;
for (temp = insn; temp; temp = NEXT_INSN (temp))
{
if (NOTE_P (temp)
&& NOTE_LINE_NUMBER (temp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
return true;
if (NOTE_P (temp)
&& NOTE_LINE_NUMBER (temp) == NOTE_INSN_BASIC_BLOCK)
{
bb_note_count++;
if (bb_note_count > 1)
return false;
}
if (INSN_P (temp))
return false;
}
return false;
}
/* The final scan for one insn, INSN.
Args are same as in `final', except that INSN
is the insn being scanned.
@ -1691,30 +1662,27 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
case NOTE_INSN_EXPECTED_VALUE:
break;
case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
/* The presence of this note indicates that this basic block
belongs in the "cold" section of the .o file. If we are
not already writing to the cold section we need to change
to it. */
unlikely_text_section ();
if (last_text_section == in_text)
{
(*debug_hooks->switch_text_section) ();
unlikely_text_section ();
}
else
{
(*debug_hooks->switch_text_section) ();
text_section ();
}
break;
case NOTE_INSN_BASIC_BLOCK:
/* If we are performing the optimization that partitions
basic blocks into hot & cold sections of the .o file,
then at the start of each new basic block, before
beginning to write code for the basic block, we need to
check to see whether the basic block belongs in the hot
or cold section of the .o file, and change the section we
are writing to appropriately. */
if (flag_reorder_blocks_and_partition
&& !scan_ahead_for_unlikely_executed_note (insn))
function_section (current_function_decl);
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
#endif
@ -1896,25 +1864,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
if (LABEL_NAME (insn))
(*debug_hooks->label) (insn);
/* If we are doing the optimization that partitions hot & cold
basic blocks into separate sections of the .o file, we need
to ensure the jump table ends up in the correct section... */
if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{
rtx tmp_table, tmp_label;
if (LABEL_P (insn)
&& tablejump_p (NEXT_INSN (insn), &tmp_label, &tmp_table))
{
/* Do nothing; Do NOT change the current section. */
}
else if (scan_ahead_for_unlikely_executed_note (insn))
unlikely_text_section ();
else if (in_unlikely_text_section ())
function_section (current_function_decl);
}
if (app_on)
{
fputs (ASM_APP_OFF, file);
@ -1952,7 +1901,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
ASM_OUTPUT_ALIGN (file, log_align);
}
else
function_section (current_function_decl);
current_function_section (current_function_decl);
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
@ -2011,7 +1960,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
if (! JUMP_TABLES_IN_TEXT_SECTION)
targetm.asm_out.function_rodata_section (current_function_decl);
else
function_section (current_function_decl);
current_function_section (current_function_decl);
if (app_on)
{
@ -2069,7 +2018,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
#endif
#endif
function_section (current_function_decl);
current_function_section (current_function_decl);
break;
}

View File

@ -2865,12 +2865,13 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
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
&& ((BB_END (then_bb)
&& find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (else_bb)
&& find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
NULL_RTX))))
if ((BB_END (then_bb)
&& find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (test_bb)
&& find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (else_bb)
&& find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
NULL_RTX)))
return FALSE;
/* THEN has one successor. */
@ -2970,12 +2971,13 @@ find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
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
&& ((BB_END (then_bb)
&& find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (else_bb)
&& find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
NULL_RTX))))
if ((BB_END (then_bb)
&& find_reg_note (BB_END (then_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (test_bb)
&& find_reg_note (BB_END (test_bb), REG_CROSSING_JUMP, NULL_RTX))
|| (BB_END (else_bb)
&& find_reg_note (BB_END (else_bb), REG_CROSSING_JUMP,
NULL_RTX)))
return FALSE;
/* ELSE has one successor. */

View File

@ -88,9 +88,8 @@ INSN_NOTE (EXPECTED_VALUE)
now included in every insn. */
INSN_NOTE (BASIC_BLOCK)
/* Record that the current basic block is unlikely to be executed and
should be moved to the UNLIKELY_EXECUTED_TEXT_SECTION. FIXME: Make
this a bit on the basic block structure. */
INSN_NOTE (UNLIKELY_EXECUTED_CODE)
/* Mark the inflection point in the instruction stream where we switch
between hot and cold text sections. */
INSN_NOTE (SWITCH_TEXT_SECTIONS)
#undef INSN_NOTE

View File

@ -669,24 +669,11 @@ decode_options (unsigned int argc, const char **argv)
if (flag_exceptions && flag_reorder_blocks_and_partition)
{
warning
inform
("-freorder-blocks-and-partition does not work with exceptions");
flag_reorder_blocks_and_partition = 0;
flag_reorder_blocks = 1;
}
/* The optimization to partition hot and cold basic blocks into
separate sections of the .o and executable files does not currently
work correctly with DWARF debugging turned on. Until this is fixed
we will disable the optimization when DWARF debugging is set. */
if (flag_reorder_blocks_and_partition && write_symbols == DWARF2_DEBUG)
{
warning
("-freorder-blocks-and-partition does not work with -g (currently)");
flag_reorder_blocks_and_partition = 0;
flag_reorder_blocks = 1;
}
}
/* Handle target- and language-independent options. Return zero to

View File

@ -209,6 +209,9 @@ extern void named_section (tree, const char *, int);
/* Tell assembler to switch to the section for function DECL. */
extern void function_section (tree);
/* Tell assembler to switch to the most recently used text section. */
extern void current_function_section (tree);
/* Tell assembler to switch to the section for string merging. */
extern void mergeable_string_section (tree, unsigned HOST_WIDE_INT,
unsigned int);
@ -431,6 +434,34 @@ extern rtx this_is_asm_operands;
extern int size_directive_output;
extern tree last_assemble_variable_decl;
enum in_section { no_section, in_text, in_unlikely_executed_text, in_data,
in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
#ifdef CTORS_SECTION_ASM_OP
, in_ctors
#endif
#ifdef DTORS_SECTION_ASM_OP
, in_dtors
#endif
#ifdef READONLY_DATA_SECTION_ASM_OP
, in_readonly_data
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
};
extern char *unlikely_section_label;
extern char *hot_section_label;
extern char *hot_section_end_label;
extern char *cold_section_end_label;
extern char *unlikely_text_section_name;
extern const char *last_text_section_name;
extern enum in_section last_text_section;
extern bool first_function_block_is_cold;
/* Decide whether DECL needs to be in a writable section.
RELOC is the same as for SELECT_SECTION. */
extern bool decl_readonly_section (tree, int);
@ -519,6 +550,10 @@ extern bool default_valid_pointer_mode (enum machine_mode);
extern int default_address_cost (rtx);
/* When performing hot/cold basic block partitioning, insert note in
instruction stream indicating boundary between hot and cold sections. */
extern void insert_section_boundary_note (void);
/* dbxout helper functions */
#if defined DBX_DEBUGGING_INFO || defined XCOFF_DEBUGGING_INFO

View File

@ -332,6 +332,8 @@ rest_of_handle_final (void)
timevar_push (TV_SYMOUT);
(*debug_hooks->function_decl) (current_function_decl);
if (unlikely_text_section_name)
free (unlikely_text_section_name);
timevar_pop (TV_SYMOUT);
ggc_collect ();

View File

@ -319,7 +319,7 @@ print_rtx (rtx in_rtx)
}
break;
case NOTE_INSN_UNLIKELY_EXECUTED_CODE:
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
{
#ifndef GENERATOR_FILE
basic_block bb = NOTE_BASIC_BLOCK (in_rtx);

View File

@ -931,8 +931,6 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
if (LABEL_P (tmp)
|| CALL_P (tmp)
|| NOTE_INSN_BASIC_BLOCK_P (tmp)
|| (NOTE_P (tmp)
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
|| (NONJUMP_INSN_P (tmp)
&& stack_regs_mentioned (tmp)))
{

View File

@ -336,6 +336,7 @@ const struct gcc_debug_hooks sdb_debug_hooks =
sdbout_label, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx, /* var_location */
debug_nothing_void, /* switch_text_section */
0 /* start_end_main_source_file */
};

View File

@ -52,6 +52,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-mudflap.h"
#include "cgraph.h"
#include "cfglayout.h"
#include "basic-block.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h" /* Needed for external data
@ -95,25 +96,44 @@ int size_directive_output;
tree last_assemble_variable_decl;
/* The following global variable indicates if the section label for the
"cold" section of code has been output yet to the assembler. The
label is useful when running gdb. This is part of the optimization that
partitions hot and cold basic blocks into separate sections of the .o
file. */
/* The following global variable indicates if the first basic block
in a function belongs to the cold partition or not. */
static bool unlikely_section_label_printed = false;
bool first_function_block_is_cold;
/* The following global variable indicates the label name to be put at
the start of the first cold section within each function, when
partitioning basic blocks into hot and cold sections. */
partitioning basic blocks into hot and cold sections. Used for
debug info. */
static char *unlikely_section_label = NULL;
char *unlikely_section_label;
/* The following global variable indicates the label name to be put at
the start of the first hot section within each function, when
partitioning basic blocks into hot and cold sections. Used for
debug info. */
char *hot_section_label;
/* The following global variable indicates the label name to be put at
the end of the last hot section within each function, when
partitioning basic blocks into hot and cold sections. Used for
debug info. */
char *hot_section_end_label;
/* The following global variable indicates the label name to be put at
the end of the last cold section within each function, when
partitioning basic blocks into hot and cold sections. Used for
debug info.*/
char *cold_section_end_label;
/* The following global variable indicates the section name to be used
for the current cold section, when partitioning hot and cold basic
/* The following global variable indicates the seciton name to be used
for the current cold section, when partitiong hot and cold basic
blocks into separate sections. */
static char *unlikely_text_section_name = NULL;
char *unlikely_text_section_name;
/* We give all constants their own alias set. Perhaps redundant with
MEM_READONLY_P, but pre-dates it. */
@ -140,6 +160,7 @@ static void globalize_decl (tree);
static void maybe_assemble_visibility (tree);
static int in_named_entry_eq (const void *, const void *);
static hashval_t in_named_entry_hash (const void *);
static void initialize_cold_section_name (void);
#ifdef BSS_SECTION_ASM_OP
#ifdef ASM_OUTPUT_BSS
static void asm_output_bss (FILE *, tree, const char *,
@ -156,25 +177,8 @@ static bool asm_emit_uninitialised (tree, const char*,
unsigned HOST_WIDE_INT);
static void mark_weak (tree);
enum in_section { no_section, in_text, in_unlikely_executed_text, in_data,
in_named
#ifdef BSS_SECTION_ASM_OP
, in_bss
#endif
#ifdef CTORS_SECTION_ASM_OP
, in_ctors
#endif
#ifdef DTORS_SECTION_ASM_OP
, in_dtors
#endif
#ifdef READONLY_DATA_SECTION_ASM_OP
, in_readonly_data
#endif
#ifdef EXTRA_SECTIONS
, EXTRA_SECTIONS
#endif
};
static GTY(()) enum in_section in_section = no_section;
enum in_section last_text_section;
/* Return a nonzero value if DECL has a section attribute. */
#ifndef IN_NAMED_SECTION
@ -185,6 +189,7 @@ static GTY(()) enum in_section in_section = no_section;
/* Text of section name when in_section == in_named. */
static GTY(()) const char *in_named_name;
const char *last_text_section_name;
/* Hash table of flags that have been used for a particular named section. */
@ -202,24 +207,10 @@ static GTY((param_is (struct in_named_entry))) htab_t in_named_htab;
EXTRA_SECTION_FUNCTIONS
#endif
/* Tell assembler to switch to text section. */
void
text_section (void)
static void
initialize_cold_section_name (void)
{
if (in_section != in_text)
{
in_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
}
}
/* Tell assembler to switch to unlikely-to-be-executed text section. */
void
unlikely_text_section (void)
{
const char *name;
const char* name;
int len;
if (! unlikely_text_section_name)
@ -235,18 +226,35 @@ unlikely_text_section (void)
name = TREE_STRING_POINTER (DECL_SECTION_NAME
(current_function_decl));
len = strlen (name);
unlikely_text_section_name = xmalloc ((len + 10) * sizeof (char));
strcpy (unlikely_text_section_name, name);
strcat (unlikely_text_section_name, "_unlikely");
unlikely_text_section_name = xmalloc (len + 10);
sprintf (unlikely_text_section_name, "%s%s", name, "_unlikely");
}
else
{
len = strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
unlikely_text_section_name = xmalloc (len+1 * sizeof (char));
strcpy (unlikely_text_section_name,
UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
}
unlikely_text_section_name =
xstrdup (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
}
}
/* Tell assembler to switch to text section. */
void
text_section (void)
{
if (in_section != in_text)
{
in_section = in_text;
last_text_section = in_text;
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
}
}
/* Tell assembler to switch to unlikely-to-be-executed text section. */
void
unlikely_text_section (void)
{
if (! unlikely_text_section_name)
initialize_cold_section_name ();
if ((in_section != in_unlikely_executed_text)
&& (in_section != in_named
@ -254,12 +262,7 @@ unlikely_text_section (void)
{
named_section (NULL_TREE, unlikely_text_section_name, 0);
in_section = in_unlikely_executed_text;
if (!unlikely_section_label_printed)
{
ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
unlikely_section_label_printed = true;
}
last_text_section = in_unlikely_executed_text;
}
}
@ -437,6 +440,12 @@ named_section_real (const char *name, unsigned int flags, tree decl)
in_section = in_named;
}
}
if (in_text_section () || in_unlikely_text_section ())
{
last_text_section = in_section;
last_text_section_name = name;
}
}
/* Tell assembler to change to section NAME for DECL.
@ -565,28 +574,40 @@ asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,
void
function_section (tree decl)
{
if (decl == NULL_TREE)
text_section ();
else
{
/* ??? Typical use of this function maybe shouldn't be looking
for unlikely blocks at all - in the event that an entire
function is going into the unlikely-execute section, that
should be reflected in its DECL_SECTION_NAME. */
rtx insns = cfun && cfun->emit ? get_insns () : 0;
bool unlikely = insns && scan_ahead_for_unlikely_executed_note (insns);
bool unlikely = false;
if (first_function_block_is_cold)
unlikely = true;
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
#else
if (unlikely)
unlikely_text_section ();
else if (DECL_SECTION_NAME (decl))
named_section (decl, 0, 0);
else
text_section ();
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
named_section (decl, (char *) 0, 0);
else
text_section ();
#endif
}
void
current_function_section (tree decl)
{
#ifdef USE_SELECT_SECTION_FOR_FUNCTIONS
bool unlikely = (in_unlikely_text_section ()
|| (last_text_section == in_unlikely_executed_text));
targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl));
#else
if (last_text_section == in_unlikely_executed_text)
unlikely_text_section ();
else if (last_text_section == in_text)
text_section ();
else if (last_text_section == in_named)
named_section (NULL_TREE, last_text_section_name, 0);
else
function_section (decl);
#endif
}
}
/* Switch to read-only data section associated with function DECL. */
@ -1203,16 +1224,19 @@ void
assemble_start_function (tree decl, const char *fnname)
{
int align;
bool hot_label_written = false;
if (unlikely_text_section_name)
free (unlikely_text_section_name);
unlikely_section_label_printed = false;
unlikely_text_section_name = NULL;
first_function_block_is_cold = false;
hot_section_label = reconcat (hot_section_label, fnname, ".hot_section", NULL);
unlikely_section_label = reconcat (unlikely_section_label,
fnname, ".unlikely_section", NULL);
hot_section_end_label = reconcat (hot_section_end_label,
fnname, ".end", NULL);
cold_section_end_label = reconcat (cold_section_end_label,
fnname, ".end.cold", NULL);
/* The following code does not need preprocessing in the assembler. */
app_disable ();
@ -1220,22 +1244,67 @@ assemble_start_function (tree decl, const char *fnname)
if (CONSTANT_POOL_BEFORE_FUNCTION)
output_constant_pool (fnname, decl);
/* Make sure the cold text (code) section is properly aligned. This
is necessary here in the case where the function has both hot and
cold sections, because we don't want to re-set the alignment when the
section switch happens mid-function. We don't need to set the hot
section alignment here, because code further down in this function
sets the alignment for whichever section comes first, and if there
is a hot section it is guaranteed to be first. */
/* Make sure the not and cold text (code) sections are properly
aligned. This is necessary here in the case where the function
has both hot and cold sections, because we don't want to re-set
the alignment when the section switch happens mid-function. */
if (flag_reorder_blocks_and_partition)
{
unlikely_text_section ();
assemble_align (FUNCTION_BOUNDARY);
ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
if (BB_PARTITION (ENTRY_BLOCK_PTR->next_bb) == BB_COLD_PARTITION)
{
/* Since the function starts with a cold section, we need to
explicitly align the hot section and write out the hot
section label. */
text_section ();
assemble_align (FUNCTION_BOUNDARY);
ASM_OUTPUT_LABEL (asm_out_file, hot_section_label);
hot_label_written = true;
first_function_block_is_cold = true;
}
}
else if (DECL_SECTION_NAME (decl))
{
/* Calls to function_section rely on first_function_block_is_cold
being accurate. The first block may be cold even if we aren't
doing partitioning, if the entire function was decided by
choose_function_section (predict.c) to be cold. */
int i;
int len;
char *s;
initialize_cold_section_name ();
/* The following is necessary, because 'strcmp
(TREE_STRING_POINTER (DECL_SECTION_NAME (decl)), blah)' always
fails, presumably because TREE_STRING_POINTER is declared to
be an array of size 1 of char. */
len = TREE_STRING_LENGTH (DECL_SECTION_NAME (decl));
s = (char *) xmalloc (len + 1);
for (i = 0; i < len; i ++)
s[i] = (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)))[i];
s[len] = '\0';
if (unlikely_text_section_name
&& (strcmp (s, unlikely_text_section_name) == 0))
first_function_block_is_cold = true;
}
last_text_section = no_section;
in_section = no_section;
resolve_unique_section (decl, 0, flag_function_sections);
/* Switch to the correct text section for the start of the function. */
function_section (decl);
if (!hot_label_written)
ASM_OUTPUT_LABEL (asm_out_file, hot_section_label);
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
@ -1288,12 +1357,7 @@ assemble_start_function (tree decl, const char *fnname)
ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
if (in_unlikely_text_section ()
&& !unlikely_section_label_printed)
{
ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
unlikely_section_label_printed = true;
}
insert_section_boundary_note ();
}
/* Output assembler code associated with defining the size of the
@ -1302,6 +1366,7 @@ assemble_start_function (tree decl, const char *fnname)
void
assemble_end_function (tree decl, const char *fnname)
{
enum in_section save_text_section;
#ifdef ASM_DECLARE_FUNCTION_SIZE
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
#endif
@ -1310,6 +1375,15 @@ assemble_end_function (tree decl, const char *fnname)
output_constant_pool (fnname, decl);
function_section (decl); /* need to switch back */
}
/* Output labels for end of hot/cold text sections (to be used by
debug info.) */
save_text_section = in_section;
unlikely_text_section ();
ASM_OUTPUT_LABEL (asm_out_file, cold_section_end_label);
text_section ();
ASM_OUTPUT_LABEL (asm_out_file, hot_section_end_label);
if (save_text_section == in_unlikely_executed_text)
unlikely_text_section ();
}
/* Assemble code to leave SIZE bytes of zeros. */

View File

@ -210,6 +210,7 @@ const struct gcc_debug_hooks vmsdbg_debug_hooks
debug_nothing_rtx, /* label */
debug_nothing_int, /* handle_pch */
debug_nothing_rtx, /* var_location */
debug_nothing_void, /* switch_text_section */
0 /* start_end_main_source_file */
};