Commit 9fb32434 by Caroline Tice

Hot/cold partitioning update patch.

Hot/cold partitioning update patch.  The problems that this patch
attemptd to address/fix are:

- Fix places where adding in_unlikely_executed_text to the enum data
  type "in_section"  threw off switch case statements.
- Make it work correctly (by turning it off) for functions where user
  specifies "__attribute__ section"
- Make it work correctly (by turning it off) for linkonce sections
- Make it work correctly with -ffunction-sections flag
- Make it output correct cold section labels
- Undo some changes to original assembly code generation
- Turn off hot/cold partitioning in the presence of DWARF debugging (for
  the moment)
- Turn off hot/cold partitioning for architectures that do not support
  named sections
- Use variables rather than constants for cold section labels and names (to
  work correctly with -ffunction-sections, among other things)


2004-08-18  Caroline Tice  <ctice@apple.com>

        * Makefile.in (STAGEFEEDBACK_FLAGS_TO_PASS) Add
        "-freorder-blocks-and-partition" to the flags used in second
        stage of profiledbootstrap.
        * bb-reorder.c (push_to_next_round_p): Add new variable,
        next_round_is_last; set and use variable to make sure, when
        partitioning, that the last trace construction round consists
        of all (and only) cold basic blocks.
        (rotate_loop): Don't copy blocks that end in a section
        crossing jump.
        (copy_bb): Correctly initialize "partition" of duplicated bb.
        (add_unlikely_executed_notes): Add a comment.
        (find_rarely_executed_basic_blocks_and_crossing_edges): Modify
        to make sure, if function contains hot blocks, that the
        successors of ENTRY_BLOCK_PTR are hot; also, only look for
        crossing edges if the architecture supports named sections.
        (mark_bb_for_unlikely_executed_section): Modify to always
        insert the NOTE_INSN_UNLIKELY_EXECUTED_CODE immediately after
        the basic block note insn.
        (fix_crossing_unconditional_branches): Remove extra space.
        (fix_edges_for_rarely_executed_code): Modify to only do
        partitioning work if the architecture supports named sections.
        (reorder_basic_blocks): Modify to only add
        NOTE_INSN_UNLIKELY_EXECUTED_CODE notes if the architecture
        supports named sections.
        * c-common.c (handle_section_attribute): Initialize new global
        variable, user_defined_section_attribute, to true if user has
        specified one.
        * cfgcleanup.c (try_forward_edges): Modify to not attempt to
        forward edges that cross section boundaries.
        * cfglayout.c (fixup_reorder_chain): Modify to only fix up
        partitioning information if the architecture supports named
        sections.
        * cfgrtl.c (target.h): Add statement to include this.
        (rtl_split_block): Make sure newly created bb gets correct
        partition.
        (try_redirect_by_replacing_jump): Make sure redirection isn't
        attempting to cross section boundaries.
        (force_nonfallthru_and_redirect): Only do partition fix up if
        architecture supports named sections.
        (rtl_split_edge): Make sure newly created bb ends up in
        correct partition.
        (commit_one_edge_insertion): Remove code that incorrectly
        updated basic block partition; Make sure partition fix up only
        happens if architecture supports named sections and it's not
        already done.
        (rtl_verify_flow_info_1): Fix if-condition on test/error
        condition that fallthru edges are not allowed to cross section
        boundaries.
        * defaults.h (NORMAL_TEXT_SECTION_NAME): Remove this.
        * final.c (final_scan_insn): Remove redundant test from if-statement;
        change calls to text_section into calls to function_section; add code
        to only to partitioning fix up if architecture supports named
        sections.
        * ifcvt.c (find_if_case_1): Make sure newly created bb has correct
        partition.
        (if_convert): Add targetm.have_named_sections to test.
        * output.h (unlikely_section_label): Extern declaration for new global
        variable.
        (unlikely_text_section_name): Likewise.
        * opts.c (decode_options): If both partitioning and DWARF debugging
        are turned on, issue a warning that this doesn't work, and change
        partitiong to basic block reordering (without hot/cold partitions).
        * passes.c (rest_of_handle_final): Re-set new global variable,
        user_defined_section_attribute, to false.
        (rest_of_compilation): Change options for calling partitioning
        function: Don't call if the user defined the section attribute, and
        don't call if DECL_ONE_ONLY is true for the current function.
        * predict.c (choose_function_section): Return immediately if we
        are doing hot/cold partitioning (i.e. let the basic block partitioning
        determine where the function belongs).
        * reg-stack.c (emit_swap_insn): Add condition to step over
        NOTE_INSN_UNLIKELY_EXECUTED_CODE notes.
        * toplev.c (user_defined_section_attribute): New global variable.
        * toplev.h (user_defined_section_attribute): Extern declaration for new
        global variable.
        * varasm.c (unlikely_section_label): New global variable.
        (unlikely_text_section_name): New global variable.
        (unlikely_text_section): Add code to initialize unlikely_text_section_name
        if necessary; modify to use unlikely_text_section_name and
        unlikely_section_label; also to use named_section properly.
        (in_unlikely_text_section):  Modify to work correctly with named_section
        and to use unlikely_text_section_name.
        (named_section):  Add code to work properly with cold section.
        (function_section): Clean up if-statement.
        * config/darwin.c (darwin_asm_named_section): Return to original code,
        removing use of SECTION_FORMAT_STRING.
        * config/arm/pe.h (switch_to_section):  Add case for
        in_unlikely_executed_text to switch statement.
        * config/i386/cygming.h (switch_to_section): Likewise.
        * config/i386/darwin.h (NORMAL_TEXT_SECTION_NAME): Remove.
        (SECTION_FORMAT_STRING): Likewise.
        * config/mcore/mcore.h (switch_to_section): Likewise.
        * config/rs6000/darwin.h (NORMAL_TEXT_SECTION_NAME): Remove.

From-SVN: r86189
parent b4b3435e
...@@ -3593,7 +3593,7 @@ STAGEPROFILE_FLAGS_TO_PASS = \ ...@@ -3593,7 +3593,7 @@ STAGEPROFILE_FLAGS_TO_PASS = \
# Files never linked into the final executable produces warnings about missing # Files never linked into the final executable produces warnings about missing
# profile. # profile.
STAGEFEEDBACK_FLAGS_TO_PASS = \ 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 # 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 # we can guarantee will build with the native compiler, and also it is the
......
...@@ -197,8 +197,10 @@ push_to_next_round_p (basic_block bb, int round, int number_of_rounds, ...@@ -197,8 +197,10 @@ push_to_next_round_p (basic_block bb, int round, int number_of_rounds,
bool there_exists_another_round; bool there_exists_another_round;
bool cold_block; bool cold_block;
bool block_not_hot_enough; bool block_not_hot_enough;
bool next_round_is_last;
there_exists_another_round = round < number_of_rounds - 1; 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 cold_block = (flag_reorder_blocks_and_partition
&& bb->partition == COLD_PARTITION); && bb->partition == COLD_PARTITION);
...@@ -207,7 +209,11 @@ push_to_next_round_p (basic_block bb, int round, int number_of_rounds, ...@@ -207,7 +209,11 @@ push_to_next_round_p (basic_block bb, int round, int number_of_rounds,
|| bb->count < count_th || bb->count < count_th
|| probably_never_executed_bb_p (bb)); || probably_never_executed_bb_p (bb));
if (there_exists_another_round if (flag_reorder_blocks_and_partition
&& next_round_is_last
&& bb->partition != COLD_PARTITION)
return false;
else if (there_exists_another_round
&& (cold_block || block_not_hot_enough)) && (cold_block || block_not_hot_enough))
return true; return true;
else else
...@@ -383,7 +389,9 @@ rotate_loop (edge back_edge, struct trace *trace, int trace_n) ...@@ -383,7 +389,9 @@ rotate_loop (edge back_edge, struct trace *trace, int trace_n)
/* Duplicate HEADER if it is a small block containing cond jump /* Duplicate HEADER if it is a small block containing cond jump
in the end. */ in the end. */
if (any_condjump_p (BB_END (header)) && copy_bb_p (header, 0)) if (any_condjump_p (BB_END (header)) && copy_bb_p (header, 0)
&& !find_reg_note (BB_END (header), REG_CROSSING_JUMP,
NULL_RTX))
{ {
copy_bb (header, prev_bb->succ, prev_bb, trace_n); copy_bb (header, prev_bb->succ, prev_bb, trace_n);
} }
...@@ -750,6 +758,8 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace) ...@@ -750,6 +758,8 @@ copy_bb (basic_block old_bb, edge e, basic_block bb, int trace)
basic_block new_bb; basic_block new_bb;
new_bb = duplicate_block (old_bb, e); new_bb = duplicate_block (old_bb, e);
new_bb->partition = old_bb->partition;
if (e->dest != new_bb) if (e->dest != new_bb)
abort (); abort ();
if (e->dest->rbi->visited) if (e->dest->rbi->visited)
...@@ -1236,6 +1246,8 @@ add_unlikely_executed_notes (void) ...@@ -1236,6 +1246,8 @@ add_unlikely_executed_notes (void)
{ {
basic_block bb; basic_block bb;
/* Add the UNLIKELY_EXECUTED_NOTES to each cold basic block. */
FOR_EACH_BB (bb) FOR_EACH_BB (bb)
if (bb->partition == COLD_PARTITION) if (bb->partition == COLD_PARTITION)
mark_bb_for_unlikely_executed_section (bb); mark_bb_for_unlikely_executed_section (bb);
...@@ -1251,6 +1263,7 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges, ...@@ -1251,6 +1263,7 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges,
int *max_idx) int *max_idx)
{ {
basic_block bb; basic_block bb;
bool has_hot_blocks = false;
edge e; edge e;
int i; int i;
...@@ -1261,32 +1274,49 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges, ...@@ -1261,32 +1274,49 @@ find_rarely_executed_basic_blocks_and_crossing_edges (edge *crossing_edges,
if (probably_never_executed_bb_p (bb)) if (probably_never_executed_bb_p (bb))
bb->partition = COLD_PARTITION; bb->partition = COLD_PARTITION;
else else
bb->partition = HOT_PARTITION; {
bb->partition = HOT_PARTITION;
has_hot_blocks = true;
}
} }
/* 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 (e = ENTRY_BLOCK_PTR->succ; e; e = e->succ_next)
if (e->dest->index >= 0)
{
e->dest->partition = HOT_PARTITION;
break;
}
/* Mark every edge that crosses between sections. */ /* Mark every edge that crosses between sections. */
i = 0; i = 0;
FOR_EACH_BB (bb) if (targetm.have_named_sections)
for (e = bb->succ; e; e = e->succ_next) {
{ FOR_EACH_BB (bb)
if (e->src != ENTRY_BLOCK_PTR for (e = bb->succ; e; e = e->succ_next)
&& e->dest != EXIT_BLOCK_PTR
&& e->src->partition != e->dest->partition)
{ {
e->crossing_edge = true; if (e->src != ENTRY_BLOCK_PTR
if (i == *max_idx) && e->dest != EXIT_BLOCK_PTR
&& e->src->partition != e->dest->partition)
{ {
*max_idx *= 2; e->crossing_edge = true;
crossing_edges = xrealloc (crossing_edges, if (i == *max_idx)
(*max_idx) * sizeof (edge)); {
*max_idx *= 2;
crossing_edges = xrealloc (crossing_edges,
(*max_idx) * sizeof (edge));
}
crossing_edges[i++] = e;
} }
crossing_edges[i++] = e; else
e->crossing_edge = false;
} }
else }
e->crossing_edge = false;
}
*n_crossing_edges = i; *n_crossing_edges = i;
} }
...@@ -1301,32 +1331,28 @@ mark_bb_for_unlikely_executed_section (basic_block bb) ...@@ -1301,32 +1331,28 @@ mark_bb_for_unlikely_executed_section (basic_block bb)
rtx insert_insn = NULL; rtx insert_insn = NULL;
rtx new_note; rtx new_note;
/* Find first non-note instruction and insert new NOTE before it (as /* Insert new NOTE immediately after BASIC_BLOCK note. */
long as new NOTE is not first instruction in basic block). */
for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
cur_insn = NEXT_INSN (cur_insn)) cur_insn = NEXT_INSN (cur_insn))
if (!NOTE_P (cur_insn) if (GET_CODE (cur_insn) == NOTE
&& !LABEL_P (cur_insn)) && NOTE_LINE_NUMBER (cur_insn) == NOTE_INSN_BASIC_BLOCK)
{ {
insert_insn = cur_insn; insert_insn = cur_insn;
break; break;
} }
/* If basic block does not contain a NOTE_INSN_BASIC_BLOCK, there is
a major problem. */
if (!insert_insn)
abort ();
/* Insert note and assign basic block number to it. */ /* Insert note and assign basic block number to it. */
if (insert_insn) new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
{ insert_insn);
new_note = emit_note_before (NOTE_INSN_UNLIKELY_EXECUTED_CODE, NOTE_BASIC_BLOCK (new_note) = bb;
insert_insn);
NOTE_BASIC_BLOCK (new_note) = bb;
}
else
{
new_note = emit_note_after (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
BB_END (bb));
NOTE_BASIC_BLOCK (new_note) = bb;
}
} }
/* If any destination of a crossing edge does not have a label, add label; /* If any destination of a crossing edge does not have a label, add label;
...@@ -1754,7 +1780,7 @@ fix_crossing_unconditional_branches (void) ...@@ -1754,7 +1780,7 @@ fix_crossing_unconditional_branches (void)
rtx new_reg; rtx new_reg;
rtx cur_insn; rtx cur_insn;
edge succ; edge succ;
FOR_EACH_BB (cur_bb) FOR_EACH_BB (cur_bb)
{ {
last_insn = BB_END (cur_bb); last_insn = BB_END (cur_bb);
...@@ -1886,26 +1912,36 @@ fix_edges_for_rarely_executed_code (edge *crossing_edges, ...@@ -1886,26 +1912,36 @@ fix_edges_for_rarely_executed_code (edge *crossing_edges,
fix_up_fall_thru_edges (); fix_up_fall_thru_edges ();
/* If the architecture does not have conditional branches that can /* Only do the parts necessary for writing separate sections if
span all of memory, convert crossing conditional branches into the target architecture has the ability to write separate sections
crossing unconditional branches. */ (i.e. it has named sections). Otherwise, the hot/cold partitioning
information will be used when reordering blocks to try to put all
if (!HAS_LONG_COND_BRANCH) the hot blocks together, then all the cold blocks, but no actual
fix_crossing_conditional_branches (); section partitioning will be done. */
if (targetm.have_named_sections)
{
/* If the architecture does not have conditional branches that can
span all of memory, convert crossing conditional branches into
crossing unconditional branches. */
/* If the architecture does not have unconditional branches that if (!HAS_LONG_COND_BRANCH)
can span all of memory, convert crossing unconditional branches fix_crossing_conditional_branches ();
into indirect jumps. Since adding an indirect jump also adds
a new register usage, update the register usage information as
well. */
if (!HAS_LONG_UNCOND_BRANCH) /* If the architecture does not have unconditional branches that
{ can span all of memory, convert crossing unconditional branches
fix_crossing_unconditional_branches (); into indirect jumps. Since adding an indirect jump also adds
reg_scan (get_insns(), max_reg_num (), 1); a new register usage, update the register usage information as
} well. */
if (!HAS_LONG_UNCOND_BRANCH)
{
fix_crossing_unconditional_branches ();
reg_scan (get_insns(), max_reg_num (), 1);
}
add_reg_crossing_jump_notes (); add_reg_crossing_jump_notes ();
}
} }
/* Reorder basic blocks. The main entry point to this file. FLAGS is /* Reorder basic blocks. The main entry point to this file. FLAGS is
...@@ -1957,7 +1993,8 @@ reorder_basic_blocks (unsigned int flags) ...@@ -1957,7 +1993,8 @@ reorder_basic_blocks (unsigned int flags)
if (dump_file) if (dump_file)
dump_flow_info (dump_file); dump_flow_info (dump_file);
if (flag_reorder_blocks_and_partition) if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
add_unlikely_executed_notes (); add_unlikely_executed_notes ();
cfg_layout_finalize (); cfg_layout_finalize ();
......
...@@ -4357,6 +4357,8 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args, ...@@ -4357,6 +4357,8 @@ handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
if (targetm.have_named_sections) if (targetm.have_named_sections)
{ {
user_defined_section_attribute = true;
if ((TREE_CODE (decl) == FUNCTION_DECL if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL) || TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST) && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
......
...@@ -446,6 +446,14 @@ try_forward_edges (int mode, basic_block b) ...@@ -446,6 +446,14 @@ try_forward_edges (int mode, basic_block b)
target = first = e->dest; target = first = e->dest;
counter = 0; counter = 0;
/* If we are partitioning hot/cold basic_blocks, we don't want to mess
up jumps that cross between hot/cold sections. */
if (flag_reorder_blocks_and_partition
&& first != EXIT_BLOCK_PTR
&& find_reg_note (BB_END (first), REG_CROSSING_JUMP, NULL_RTX))
return false;
while (counter < n_basic_blocks) while (counter < n_basic_blocks)
{ {
basic_block new_target = NULL; basic_block new_target = NULL;
...@@ -453,6 +461,7 @@ try_forward_edges (int mode, basic_block b) ...@@ -453,6 +461,7 @@ try_forward_edges (int mode, basic_block b)
may_thread |= target->flags & BB_DIRTY; may_thread |= target->flags & BB_DIRTY;
if (FORWARDER_BLOCK_P (target) if (FORWARDER_BLOCK_P (target)
&& !target->succ->crossing_edge
&& target->succ->dest != EXIT_BLOCK_PTR) && target->succ->dest != EXIT_BLOCK_PTR)
{ {
/* Bypass trivial infinite loops. */ /* Bypass trivial infinite loops. */
......
...@@ -795,7 +795,8 @@ fixup_reorder_chain (void) ...@@ -795,7 +795,8 @@ fixup_reorder_chain (void)
/* Make sure new bb is tagged for correct section (same as /* Make sure new bb is tagged for correct section (same as
fall-thru source). */ fall-thru source). */
e_fall->src->partition = bb->pred->src->partition; e_fall->src->partition = bb->pred->src->partition;
if (flag_reorder_blocks_and_partition) if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{ {
if (bb->pred->src->partition == COLD_PARTITION) if (bb->pred->src->partition == COLD_PARTITION)
{ {
...@@ -1107,6 +1108,7 @@ cfg_layout_duplicate_bb (basic_block bb) ...@@ -1107,6 +1108,7 @@ cfg_layout_duplicate_bb (basic_block bb)
insn ? get_last_insn () : NULL, insn ? get_last_insn () : NULL,
EXIT_BLOCK_PTR->prev_bb); EXIT_BLOCK_PTR->prev_bb);
new_bb->partition = bb->partition;
if (bb->rbi->header) if (bb->rbi->header)
{ {
insn = bb->rbi->header; insn = bb->rbi->header;
......
...@@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -56,6 +56,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "insn-config.h" #include "insn-config.h"
#include "cfglayout.h" #include "cfglayout.h"
#include "expr.h" #include "expr.h"
#include "target.h"
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */ /* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
...@@ -488,6 +489,7 @@ rtl_split_block (basic_block bb, void *insnp) ...@@ -488,6 +489,7 @@ rtl_split_block (basic_block bb, void *insnp)
/* Create the new basic block. */ /* Create the new basic block. */
new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb); new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
new_bb->partition = bb->partition;
BB_END (bb) = insn; BB_END (bb) = insn;
/* Redirect the outgoing edges. */ /* Redirect the outgoing edges. */
...@@ -681,7 +683,8 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout) ...@@ -681,7 +683,8 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
and cold sections. */ and cold sections. */
if (flag_reorder_blocks_and_partition if (flag_reorder_blocks_and_partition
&& find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)) && (find_reg_note (insn, REG_CROSSING_JUMP, NULL_RTX)
|| (src->partition != target->partition)))
return NULL; return NULL;
/* Verify that all targets will be TARGET. */ /* Verify that all targets will be TARGET. */
...@@ -1092,7 +1095,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target) ...@@ -1092,7 +1095,8 @@ force_nonfallthru_and_redirect (edge e, basic_block target)
/* Make sure new block ends up in correct hot/cold section. */ /* Make sure new block ends up in correct hot/cold section. */
jump_block->partition = e->src->partition; jump_block->partition = e->src->partition;
if (flag_reorder_blocks_and_partition) if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{ {
if (e->src->partition == COLD_PARTITION) if (e->src->partition == COLD_PARTITION)
{ {
...@@ -1350,9 +1354,13 @@ rtl_split_edge (edge edge_in) ...@@ -1350,9 +1354,13 @@ rtl_split_edge (edge edge_in)
&& NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END) && NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END)
before = NEXT_INSN (before); before = NEXT_INSN (before);
bb = create_basic_block (before, NULL, edge_in->src); bb = create_basic_block (before, NULL, edge_in->src);
bb->partition = edge_in->src->partition;
} }
else else
bb = create_basic_block (before, NULL, edge_in->dest->prev_bb); {
bb = create_basic_block (before, NULL, edge_in->dest->prev_bb);
bb->partition = edge_in->dest->partition;
}
/* ??? This info is likely going to be out of date very soon. */ /* ??? This info is likely going to be out of date very soon. */
if (edge_in->dest->global_live_at_start) if (edge_in->dest->global_live_at_start)
...@@ -1590,13 +1598,11 @@ commit_one_edge_insertion (edge e, int watch_calls) ...@@ -1590,13 +1598,11 @@ commit_one_edge_insertion (edge e, int watch_calls)
bb = split_edge (e); bb = split_edge (e);
after = BB_END (bb); after = BB_END (bb);
/* If we are partitioning hot/cold basic blocks, we must make sure
that the new basic block ends up in the correct section. */
bb->partition = e->src->partition;
if (flag_reorder_blocks_and_partition if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections
&& e->src != ENTRY_BLOCK_PTR && e->src != ENTRY_BLOCK_PTR
&& e->src->partition == COLD_PARTITION) && e->src->partition == COLD_PARTITION
&& !e->crossing_edge)
{ {
rtx bb_note, new_note, cur_insn; rtx bb_note, new_note, cur_insn;
...@@ -1980,8 +1986,11 @@ rtl_verify_flow_info_1 (void) ...@@ -1980,8 +1986,11 @@ rtl_verify_flow_info_1 (void)
if (e->flags & EDGE_FALLTHRU) if (e->flags & EDGE_FALLTHRU)
{ {
n_fallthru++, fallthru = e; n_fallthru++, fallthru = e;
if (e->crossing_edge) if (e->crossing_edge
{ || (e->src->partition != e->dest->partition
&& e->src != ENTRY_BLOCK_PTR
&& e->dest != EXIT_BLOCK_PTR))
{
error ("Fallthru edge crosses section boundary (bb %i)", error ("Fallthru edge crosses section boundary (bb %i)",
e->src->index); e->src->index);
err = 1; err = 1;
......
...@@ -198,6 +198,7 @@ switch_to_section (enum in_section section, tree decl) \ ...@@ -198,6 +198,7 @@ switch_to_section (enum in_section section, tree decl) \
switch (section) \ switch (section) \
{ \ { \
case in_text: text_section (); break; \ case in_text: text_section (); break; \
case in_unlikely_executed_text: unlikely_text_section (); break; \
case in_data: data_section (); break; \ case in_data: data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \ case in_named: named_section (decl, NULL, 0); break; \
case in_readonly_data: readonly_data_section (); break; \ case in_readonly_data: readonly_data_section (); break; \
......
...@@ -1077,10 +1077,7 @@ darwin_globalize_label (FILE *stream, const char *name) ...@@ -1077,10 +1077,7 @@ darwin_globalize_label (FILE *stream, const char *name)
void void
darwin_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED) darwin_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
{ {
if (flag_reorder_blocks_and_partition) fprintf (asm_out_file, ".section %s\n", name);
fprintf (asm_out_file, SECTION_FORMAT_STRING, name);
else
fprintf (asm_out_file, ".section %s\n", name);
} }
unsigned int unsigned int
......
...@@ -162,6 +162,7 @@ switch_to_section (enum in_section section, tree decl) \ ...@@ -162,6 +162,7 @@ switch_to_section (enum in_section section, tree decl) \
switch (section) \ switch (section) \
{ \ { \
case in_text: text_section (); break; \ case in_text: text_section (); break; \
case in_unlikely_text_section: unlikely_text_section (); break; \
case in_data: data_section (); break; \ case in_data: data_section (); break; \
case in_readonly_data: readonly_data_section (); break; \ case in_readonly_data: readonly_data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \ case in_named: named_section (decl, NULL, 0); break; \
......
...@@ -98,10 +98,8 @@ Boston, MA 02111-1307, USA. */ ...@@ -98,10 +98,8 @@ Boston, MA 02111-1307, USA. */
/* These are used by -fbranch-probabilities */ /* These are used by -fbranch-probabilities */
#define HOT_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions" #define HOT_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions"
#define NORMAL_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions"
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \ #define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \
"__TEXT,__unlikely,regular,pure_instructions" "__TEXT,__unlikely,regular,pure_instructions"
#define SECTION_FORMAT_STRING ".section %s\n\t.align 2\n"
/* Assembler pseudos to introduce constants of various size. */ /* Assembler pseudos to introduce constants of various size. */
......
...@@ -968,6 +968,7 @@ switch_to_section (enum in_section section, tree decl) \ ...@@ -968,6 +968,7 @@ switch_to_section (enum in_section section, tree decl) \
switch (section) \ switch (section) \
{ \ { \
case in_text: text_section (); break; \ case in_text: text_section (); break; \
case in_unlikely_executed_text: unlikely_text_section (); break; \
case in_data: data_section (); break; \ case in_data: data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \ case in_named: named_section (decl, NULL, 0); break; \
SUBTARGET_SWITCH_SECTIONS \ SUBTARGET_SWITCH_SECTIONS \
......
...@@ -168,10 +168,8 @@ do { \ ...@@ -168,10 +168,8 @@ do { \
/* These are used by -fbranch-probabilities */ /* These are used by -fbranch-probabilities */
#define HOT_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions" #define HOT_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions"
#define NORMAL_TEXT_SECTION_NAME "__TEXT,__text,regular,pure_instructions"
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \ #define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \
"__TEXT,__unlikely,regular,pure_instructions" "__TEXT,__unlikely,regular,pure_instructions"
#define SECTION_FORMAT_STRING ".section %s\n\t.align 2\n"
/* Define cutoff for using external functions to save floating point. /* Define cutoff for using external functions to save floating point.
Currently on Darwin, always use inline stores. */ Currently on Darwin, always use inline stores. */
......
...@@ -654,10 +654,6 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE! ...@@ -654,10 +654,6 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
#define HOT_TEXT_SECTION_NAME ".text.hot" #define HOT_TEXT_SECTION_NAME ".text.hot"
#endif #endif
#ifndef NORMAL_TEXT_SECTION_NAME
#define NORMAL_TEXT_SECTION_NAME ".text"
#endif
#ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME #ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME ".text.unlikely" #define UNLIKELY_EXECUTED_TEXT_SECTION_NAME ".text.unlikely"
#endif #endif
......
...@@ -1728,9 +1728,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ...@@ -1728,9 +1728,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
are writing to appropriately. */ are writing to appropriately. */
if (flag_reorder_blocks_and_partition if (flag_reorder_blocks_and_partition
&& in_unlikely_text_section()
&& !scan_ahead_for_unlikely_executed_note (insn)) && !scan_ahead_for_unlikely_executed_note (insn))
text_section (); function_section (current_function_decl);
#ifdef TARGET_UNWIND_INFO #ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn); targetm.asm_out.unwind_emit (asm_out_file, insn);
...@@ -1923,7 +1922,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ...@@ -1923,7 +1922,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
basic blocks into separate sections of the .o file, we need basic blocks into separate sections of the .o file, we need
to ensure the jump table ends up in the correct section... */ to ensure the jump table ends up in the correct section... */
if (flag_reorder_blocks_and_partition) if (flag_reorder_blocks_and_partition
&& targetm.have_named_sections)
{ {
rtx tmp_table, tmp_label; rtx tmp_table, tmp_label;
if (LABEL_P (insn) if (LABEL_P (insn)
...@@ -1933,11 +1933,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, ...@@ -1933,11 +1933,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED,
} }
else if (scan_ahead_for_unlikely_executed_note (insn)) else if (scan_ahead_for_unlikely_executed_note (insn))
unlikely_text_section (); unlikely_text_section ();
else else if (in_unlikely_text_section ())
{ function_section (current_function_decl);
if (in_unlikely_text_section ())
text_section ();
}
} }
if (app_on) if (app_on)
......
...@@ -2909,6 +2909,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge) ...@@ -2909,6 +2909,7 @@ find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
{ {
new_bb->index = then_bb_index; new_bb->index = then_bb_index;
BASIC_BLOCK (then_bb_index) = new_bb; BASIC_BLOCK (then_bb_index) = new_bb;
new_bb->partition = test_bb->partition;
} }
/* We've possibly created jump to next insn, cleanup_cfg will solve that /* We've possibly created jump to next insn, cleanup_cfg will solve that
later. */ later. */
...@@ -3288,7 +3289,8 @@ if_convert (int x_life_data_ok) ...@@ -3288,7 +3289,8 @@ if_convert (int x_life_data_ok)
life_data_ok = (x_life_data_ok != 0); life_data_ok = (x_life_data_ok != 0);
if ((! targetm.cannot_modify_jumps_p ()) if ((! targetm.cannot_modify_jumps_p ())
&& (!flag_reorder_blocks_and_partition || !no_new_pseudos)) && (!flag_reorder_blocks_and_partition || !no_new_pseudos
|| !targetm.have_named_sections))
mark_loop_exit_edges (); mark_loop_exit_edges ();
/* Compute postdominators if we think we'll use them. */ /* Compute postdominators if we think we'll use them. */
......
...@@ -641,6 +641,21 @@ decode_options (unsigned int argc, const char **argv) ...@@ -641,6 +641,21 @@ decode_options (unsigned int argc, const char **argv)
flag_reorder_blocks_and_partition = 0; flag_reorder_blocks_and_partition = 0;
flag_reorder_blocks = 1; 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 == DWARF_DEBUG
|| 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 /* Handle target- and language-independent options. Return zero to
......
...@@ -392,6 +392,10 @@ extern const char *first_global_object_name; ...@@ -392,6 +392,10 @@ extern const char *first_global_object_name;
/* The first weak object in the file. */ /* The first weak object in the file. */
extern const char *weak_global_object_name; extern const char *weak_global_object_name;
/* Label at start of unlikely section, when partitioning hot/cold basic
blocks. */
extern char *unlikely_section_label;
/* Nonzero if function being compiled doesn't contain any calls /* Nonzero if function being compiled doesn't contain any calls
(ignoring the prologue and epilogue). This is set prior to (ignoring the prologue and epilogue). This is set prior to
local register allocation and is valid for the remaining local register allocation and is valid for the remaining
...@@ -438,6 +442,12 @@ extern tree last_assemble_variable_decl; ...@@ -438,6 +442,12 @@ extern tree last_assemble_variable_decl;
extern bool decl_readonly_section (tree, int); extern bool decl_readonly_section (tree, int);
extern bool decl_readonly_section_1 (tree, int, int); extern bool decl_readonly_section_1 (tree, int, int);
/* The following global variable indicates the section name to be used
for the current cold section, when partitioning hot and cold basic
blocks into separate sections. */
extern char *unlikely_text_section_name;
/* This can be used to compute RELOC for the function above, when /* This can be used to compute RELOC for the function above, when
given a constant expression. */ given a constant expression. */
extern int compute_reloc_for_constant (tree); extern int compute_reloc_for_constant (tree);
......
...@@ -454,6 +454,8 @@ rest_of_handle_final (void) ...@@ -454,6 +454,8 @@ rest_of_handle_final (void)
output_function_exception_table (); output_function_exception_table ();
#endif #endif
user_defined_section_attribute = false;
if (! quiet_flag) if (! quiet_flag)
fflush (asm_out_file); fflush (asm_out_file);
...@@ -1857,7 +1859,9 @@ rest_of_compilation (void) ...@@ -1857,7 +1859,9 @@ rest_of_compilation (void)
sections of the .o file does not work well with exception handling. sections of the .o file does not work well with exception handling.
Don't call it if there are exceptions. */ Don't call it if there are exceptions. */
if (optimize > 0 && flag_reorder_blocks_and_partition && !flag_exceptions) if (flag_reorder_blocks_and_partition
&& !DECL_ONE_ONLY (current_function_decl)
&& !user_defined_section_attribute)
rest_of_handle_partition_blocks (); rest_of_handle_partition_blocks ();
if (optimize > 0 && (flag_regmove || flag_expensive_optimizations)) if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
......
...@@ -1441,6 +1441,13 @@ choose_function_section (void) ...@@ -1441,6 +1441,13 @@ choose_function_section (void)
of all instances. For now just never set frequency for these. */ of all instances. For now just never set frequency for these. */
|| DECL_ONE_ONLY (current_function_decl)) || DECL_ONE_ONLY (current_function_decl))
return; return;
/* If we are doing the partitioning optimization, let the optimization
choose the correct section into which to put things. */
if (flag_reorder_blocks_and_partition)
return;
if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT) if (cfun->function_frequency == FUNCTION_FREQUENCY_HOT)
DECL_SECTION_NAME (current_function_decl) = DECL_SECTION_NAME (current_function_decl) =
build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME); build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME);
......
...@@ -989,6 +989,8 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg) ...@@ -989,6 +989,8 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
if (LABEL_P (tmp) if (LABEL_P (tmp)
|| CALL_P (tmp) || CALL_P (tmp)
|| NOTE_INSN_BASIC_BLOCK_P (tmp) || NOTE_INSN_BASIC_BLOCK_P (tmp)
|| (NOTE_P (tmp)
&& NOTE_LINE_NUMBER (tmp) == NOTE_INSN_UNLIKELY_EXECUTED_CODE)
|| (NONJUMP_INSN_P (tmp) || (NONJUMP_INSN_P (tmp)
&& stack_regs_mentioned (tmp))) && stack_regs_mentioned (tmp)))
{ {
......
...@@ -340,6 +340,11 @@ enum pta_type flag_tree_points_to = PTA_NONE; ...@@ -340,6 +340,11 @@ enum pta_type flag_tree_points_to = PTA_NONE;
to optimize, debug_info_level and debug_hooks in process_options (). */ to optimize, debug_info_level and debug_hooks in process_options (). */
int flag_var_tracking = AUTODETECT_FLAG_VAR_TRACKING; int flag_var_tracking = AUTODETECT_FLAG_VAR_TRACKING;
/* True if the user has tagged the function with the 'section'
attribute. */
bool user_defined_section_attribute = false;
/* Values of the -falign-* flags: how much to align labels in code. /* Values of the -falign-* flags: how much to align labels in code.
0 means `use default', 1 means `don't align'. 0 means `use default', 1 means `don't align'.
For each variable, there is an _log variant which is the power For each variable, there is an _log variant which is the power
......
...@@ -116,6 +116,11 @@ extern bool exit_after_options; ...@@ -116,6 +116,11 @@ extern bool exit_after_options;
extern int target_flags_explicit; extern int target_flags_explicit;
/* True if the user has tagged the function with the 'section'
attribute. */
extern bool user_defined_section_attribute;
/* See toplev.c. */ /* See toplev.c. */
extern int flag_loop_optimize; extern int flag_loop_optimize;
extern int flag_crossjumping; extern int flag_crossjumping;
......
...@@ -222,18 +222,42 @@ text_section (void) ...@@ -222,18 +222,42 @@ text_section (void)
void void
unlikely_text_section (void) unlikely_text_section (void)
{ {
if ((in_section != in_unlikely_executed_text) const char *name;
&& (in_section != in_named int len;
|| strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
if (! unlikely_text_section_name)
{ {
if (targetm.have_named_sections) if (DECL_SECTION_NAME (current_function_decl)
named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0); && (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
(current_function_decl)),
HOT_TEXT_SECTION_NAME) != 0)
&& (strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME
(current_function_decl)),
UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
{
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");
}
else else
{ {
in_section = in_unlikely_executed_text; len = strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); unlikely_text_section_name = xmalloc (len+1 * sizeof (char));
strcpy (unlikely_text_section_name,
UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
} }
}
if ((in_section != in_unlikely_executed_text)
&& (in_section != in_named
|| strcmp (in_named_name, unlikely_text_section_name) != 0))
{
named_section (NULL_TREE, unlikely_text_section_name, 0);
in_section = in_unlikely_executed_text;
if (!unlikely_section_label_printed) if (!unlikely_section_label_printed)
{ {
ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label); ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
...@@ -289,7 +313,14 @@ in_text_section (void) ...@@ -289,7 +313,14 @@ in_text_section (void)
int int
in_unlikely_text_section (void) in_unlikely_text_section (void)
{ {
return in_section == in_unlikely_executed_text; bool ret_val;
ret_val = ((in_section == in_unlikely_executed_text)
|| (in_section == in_named
&& unlikely_text_section_name
&& strcmp (in_named_name, unlikely_text_section_name) == 0));
return ret_val;
} }
/* Determine if we're in the data section. */ /* Determine if we're in the data section. */
...@@ -423,6 +454,16 @@ named_section (tree decl, const char *name, int reloc) ...@@ -423,6 +454,16 @@ named_section (tree decl, const char *name, int reloc)
if (name == NULL) if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl)); name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0
&& !unlikely_text_section_name)
{
unlikely_text_section_name = xmalloc
(strlen (UNLIKELY_EXECUTED_TEXT_SECTION_NAME) + 1
* sizeof (char));
strcpy (unlikely_text_section_name,
UNLIKELY_EXECUTED_TEXT_SECTION_NAME);
}
flags = targetm.section_type_flags (decl, name, reloc); flags = targetm.section_type_flags (decl, name, reloc);
/* Sanity check user variables for flag changes. Non-user /* Sanity check user variables for flag changes. Non-user
...@@ -533,14 +574,11 @@ function_section (tree decl) ...@@ -533,14 +574,11 @@ function_section (tree decl)
{ {
if (scan_ahead_for_unlikely_executed_note (get_insns())) if (scan_ahead_for_unlikely_executed_note (get_insns()))
unlikely_text_section (); unlikely_text_section ();
else if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
named_section (decl, (char *) 0, 0);
else else
{ text_section ();
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
named_section (decl, (char *) 0, 0);
else
text_section ();
}
} }
/* Switch to read-only data section associated with function DECL. */ /* Switch to read-only data section associated with function DECL. */
...@@ -1153,7 +1191,7 @@ assemble_start_function (tree decl, const char *fnname) ...@@ -1153,7 +1191,7 @@ assemble_start_function (tree decl, const char *fnname)
free (unlikely_section_label); free (unlikely_section_label);
unlikely_section_label = xmalloc ((strlen (fnname) + 18) * sizeof (char)); unlikely_section_label = xmalloc ((strlen (fnname) + 18) * sizeof (char));
sprintf (unlikely_section_label, "%s_unlikely_section", fnname); sprintf (unlikely_section_label, "%s_unlikely_section", fnname);
/* The following code does not need preprocessing in the assembler. */ /* The following code does not need preprocessing in the assembler. */
app_disable (); app_disable ();
...@@ -4481,7 +4519,8 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc, ...@@ -4481,7 +4519,8 @@ default_section_type_flags_1 (tree decl, const char *name, int reloc,
flags = SECTION_CODE; flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib)) else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
flags = 0; flags = 0;
else if (strcmp (name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) == 0) else if (unlikely_text_section_name
&& strcmp (name, unlikely_text_section_name) == 0)
flags = SECTION_CODE; flags = SECTION_CODE;
else else
flags = SECTION_WRITE; flags = SECTION_WRITE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment