From 87c8b4bed31dbbf4708549e10814197cac4d8249 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Thu, 31 Mar 2005 06:59:59 -0800 Subject: Fix problems with hot/cold partitioning optimization. From-SVN: r97322 --- gcc/Makefile.in | 6 +- gcc/bb-reorder.c | 311 +++++++++++++++++++---------------------- gcc/cfgcleanup.c | 30 ++-- gcc/cfglayout.c | 48 +------ gcc/cfglayout.h | 1 - gcc/cfgrtl.c | 62 +++----- gcc/config/darwin.c | 7 +- gcc/config/darwin.h | 8 +- gcc/config/sparc/sparc.c | 2 +- gcc/config/stormy16/stormy16.c | 2 +- gcc/config/xtensa/xtensa.c | 9 ++ gcc/dbxout.c | 22 ++- gcc/debug.c | 1 + gcc/debug.h | 4 + gcc/dwarf2out.c | 172 +++++++++++++++++++---- gcc/except.c | 2 +- gcc/final.c | 83 +++-------- gcc/ifcvt.c | 26 ++-- gcc/insn-notes.def | 7 +- gcc/opts.c | 15 +- gcc/output.h | 35 +++++ gcc/passes.c | 2 + gcc/print-rtl.c | 2 +- gcc/reg-stack.c | 2 - gcc/sdbout.c | 1 + gcc/varasm.c | 266 ++++++++++++++++++++++------------- gcc/vmsdbgout.c | 1 + 27 files changed, 617 insertions(+), 510 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index fb8e6cb..5e7e495 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index b7223d7..b0c99b1 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -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 diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index 49cbb44..70bd28d 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -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 diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c index 655c9a1..6b60062 100644 --- a/gcc/cfglayout.c +++ b/gcc/cfglayout.c @@ -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; diff --git a/gcc/cfglayout.h b/gcc/cfglayout.h index 69c9d56..1410509 100644 --- a/gcc/cfglayout.h +++ b/gcc/cfglayout.h @@ -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 */ diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c index 9239906..d11db10 100644 --- a/gcc/cfgrtl.c +++ b/gcc/cfgrtl.c @@ -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. */ diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index 6a54738..e6f41a2 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -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)) diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index b26715e..25d1bca 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -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," \ diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 6823915..340a377 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -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) diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c index ec40cd9..a15051f 100644 --- a/gcc/config/stormy16/stormy16.c +++ b/gcc/config/stormy16/stormy16.c @@ -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++) diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c index cdba18c..b6084c9 100644 --- a/gcc/config/xtensa/xtensa.c +++ b/gcc/config/xtensa/xtensa.c @@ -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; + } } diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 92538b8..ea830a6 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -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 diff --git a/gcc/debug.c b/gcc/debug.c index ab26bc1..e34b7b9 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -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 */ }; diff --git a/gcc/debug.h b/gcc/debug.h index ca0ad77..5b4074b 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -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; diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 70ad887..43ab1b5 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -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); - - add_pubname (decl, subr_die); - add_arange (decl, subr_die); + 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_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) diff --git a/gcc/except.c b/gcc/except.c index d774bf3..0583424 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -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" diff --git a/gcc/final.c b/gcc/final.c index 7f5c664..7633724 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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; } diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index b0df6da..7a934ee 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -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. */ diff --git a/gcc/insn-notes.def b/gcc/insn-notes.def index 3894dda..58f264d 100644 --- a/gcc/insn-notes.def +++ b/gcc/insn-notes.def @@ -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 diff --git a/gcc/opts.c b/gcc/opts.c index 3befb1d..bd971c8 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -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 diff --git a/gcc/output.h b/gcc/output.h index dbc2d47..4d9eabb 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -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 diff --git a/gcc/passes.c b/gcc/passes.c index 988f4f2..2ded2b3 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -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 (); diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c index 32ef01c..4f8c9a9 100644 --- a/gcc/print-rtl.c +++ b/gcc/print-rtl.c @@ -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); diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 6f58341..f126d98 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -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))) { diff --git a/gcc/sdbout.c b/gcc/sdbout.c index fb09847..d596432 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -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 */ }; diff --git a/gcc/varasm.c b/gcc/varasm.c index 9210c41..d2aeac6 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -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) -{ - 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) +static void +initialize_cold_section_name (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 (); + 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)); +#else + if (decl != NULL_TREE + && DECL_SECTION_NAME (decl) != NULL_TREE) + named_section (decl, (char *) 0, 0); 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); + text_section (); +#endif +} +void +current_function_section (tree decl) +{ #ifdef USE_SELECT_SECTION_FOR_FUNCTIONS - targetm.asm_out.select_section (decl, unlikely, DECL_ALIGN (decl)); + 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 (unlikely) - unlikely_text_section (); - else if (DECL_SECTION_NAME (decl)) - named_section (decl, 0, 0); - else - text_section (); + 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. */ diff --git a/gcc/vmsdbgout.c b/gcc/vmsdbgout.c index d0f4abe..d612479 100644 --- a/gcc/vmsdbgout.c +++ b/gcc/vmsdbgout.c @@ -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 */ }; -- cgit v1.1