# 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
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 == COLD_PARTITION);
|| bb->count < count_th
|| 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))
return true;
else
/* Duplicate HEADER if it is a small block containing cond jump
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);
}
basic_block new_bb;
new_bb = duplicate_block (old_bb, e);
+ new_bb->partition = old_bb->partition;
+
if (e->dest != new_bb)
abort ();
if (e->dest->rbi->visited)
{
basic_block bb;
+ /* Add the UNLIKELY_EXECUTED_NOTES to each cold basic block. */
+
FOR_EACH_BB (bb)
if (bb->partition == COLD_PARTITION)
mark_bb_for_unlikely_executed_section (bb);
int *max_idx)
{
basic_block bb;
+ bool has_hot_blocks = false;
edge e;
int i;
if (probably_never_executed_bb_p (bb))
bb->partition = COLD_PARTITION;
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. */
i = 0;
- FOR_EACH_BB (bb)
- for (e = bb->succ; e; e = e->succ_next)
- {
- if (e->src != ENTRY_BLOCK_PTR
- && e->dest != EXIT_BLOCK_PTR
- && e->src->partition != e->dest->partition)
+ if (targetm.have_named_sections)
+ {
+ FOR_EACH_BB (bb)
+ for (e = bb->succ; e; e = e->succ_next)
{
- e->crossing_edge = true;
- if (i == *max_idx)
+ if (e->src != ENTRY_BLOCK_PTR
+ && e->dest != EXIT_BLOCK_PTR
+ && e->src->partition != e->dest->partition)
{
- *max_idx *= 2;
- crossing_edges = xrealloc (crossing_edges,
- (*max_idx) * sizeof (edge));
+ e->crossing_edge = true;
+ if (i == *max_idx)
+ {
+ *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;
}
rtx insert_insn = NULL;
rtx new_note;
- /* Find first non-note instruction and insert new NOTE before it (as
- long as new NOTE is not first instruction in basic block). */
-
- for (cur_insn = BB_HEAD (bb); cur_insn != NEXT_INSN (BB_END (bb));
+ /* 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 (!NOTE_P (cur_insn)
- && !LABEL_P (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. */
+
+ if (!insert_insn)
+ abort ();
+
/* Insert note and assign basic block number to it. */
- if (insert_insn)
- {
- new_note = emit_note_before (NOTE_INSN_UNLIKELY_EXECUTED_CODE,
- 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;
- }
+ 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;
rtx new_reg;
rtx cur_insn;
edge succ;
-
+
FOR_EACH_BB (cur_bb)
{
last_insn = BB_END (cur_bb);
fix_up_fall_thru_edges ();
- /* If the architecture does not have conditional branches that can
- span all of memory, convert crossing conditional branches into
- crossing unconditional branches. */
-
- if (!HAS_LONG_COND_BRANCH)
- fix_crossing_conditional_branches ();
+ /* Only do the parts necessary for writing separate sections if
+ the target architecture has the ability to write separate sections
+ (i.e. it has named sections). Otherwise, the hot/cold partitioning
+ information will be used when reordering blocks to try to put all
+ the hot blocks together, then all the cold blocks, but no actual
+ 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
- can span all of memory, convert crossing unconditional 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_COND_BRANCH)
+ fix_crossing_conditional_branches ();
- if (!HAS_LONG_UNCOND_BRANCH)
- {
- fix_crossing_unconditional_branches ();
- reg_scan (get_insns(), max_reg_num (), 1);
- }
+ /* If the architecture does not have unconditional branches that
+ can span all of memory, convert crossing unconditional 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)
+ {
+ 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
if (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 ();
cfg_layout_finalize ();
if (targetm.have_named_sections)
{
+ user_defined_section_attribute = true;
+
if ((TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
target = first = e->dest;
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)
{
basic_block new_target = NULL;
may_thread |= target->flags & BB_DIRTY;
if (FORWARDER_BLOCK_P (target)
+ && !target->succ->crossing_edge
&& target->succ->dest != EXIT_BLOCK_PTR)
{
/* Bypass trivial infinite loops. */
/* Make sure new bb is tagged for correct section (same as
fall-thru source). */
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)
{
insn ? get_last_insn () : NULL,
EXIT_BLOCK_PTR->prev_bb);
+ new_bb->partition = bb->partition;
if (bb->rbi->header)
{
insn = bb->rbi->header;
#include "insn-config.h"
#include "cfglayout.h"
#include "expr.h"
+#include "target.h"
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
/* Create the new basic block. */
new_bb = create_basic_block (NEXT_INSN (insn), BB_END (bb), bb);
+ new_bb->partition = bb->partition;
BB_END (bb) = insn;
/* Redirect the outgoing edges. */
and cold sections. */
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;
/* Verify that all targets will be TARGET. */
/* Make sure new block ends up in correct hot/cold section. */
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)
{
&& NOTE_LINE_NUMBER (before) == NOTE_INSN_LOOP_END)
before = NEXT_INSN (before);
bb = create_basic_block (before, NULL, edge_in->src);
+ bb->partition = edge_in->src->partition;
}
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. */
if (edge_in->dest->global_live_at_start)
bb = split_edge (e);
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
+ && targetm.have_named_sections
&& 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;
if (e->flags & EDGE_FALLTHRU)
{
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)",
e->src->index);
err = 1;
switch (section) \
{ \
case in_text: text_section (); break; \
+ case in_unlikely_executed_text: unlikely_text_section (); break; \
case in_data: data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \
case in_readonly_data: readonly_data_section (); break; \
void
darwin_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
{
- if (flag_reorder_blocks_and_partition)
- fprintf (asm_out_file, SECTION_FORMAT_STRING, name);
- else
- fprintf (asm_out_file, ".section %s\n", name);
+ fprintf (asm_out_file, ".section %s\n", name);
}
unsigned int
switch (section) \
{ \
case in_text: text_section (); break; \
+ case in_unlikely_text_section: unlikely_text_section (); break; \
case in_data: data_section (); break; \
case in_readonly_data: readonly_data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \
/* These are used by -fbranch-probabilities */
#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 \
"__TEXT,__unlikely,regular,pure_instructions"
-#define SECTION_FORMAT_STRING ".section %s\n\t.align 2\n"
/* Assembler pseudos to introduce constants of various size. */
switch (section) \
{ \
case in_text: text_section (); break; \
+ case in_unlikely_executed_text: unlikely_text_section (); break; \
case in_data: data_section (); break; \
case in_named: named_section (decl, NULL, 0); break; \
SUBTARGET_SWITCH_SECTIONS \
/* These are used by -fbranch-probabilities */
#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 \
"__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.
Currently on Darwin, always use inline stores. */
#define HOT_TEXT_SECTION_NAME ".text.hot"
#endif
-#ifndef NORMAL_TEXT_SECTION_NAME
-#define NORMAL_TEXT_SECTION_NAME ".text"
-#endif
-
#ifndef UNLIKELY_EXECUTED_TEXT_SECTION_NAME
#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME ".text.unlikely"
#endif
are writing to appropriately. */
if (flag_reorder_blocks_and_partition
- && in_unlikely_text_section()
&& !scan_ahead_for_unlikely_executed_note (insn))
- text_section ();
+ function_section (current_function_decl);
#ifdef TARGET_UNWIND_INFO
targetm.asm_out.unwind_emit (asm_out_file, insn);
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)
+ if (flag_reorder_blocks_and_partition
+ && targetm.have_named_sections)
{
rtx tmp_table, tmp_label;
if (LABEL_P (insn)
}
else if (scan_ahead_for_unlikely_executed_note (insn))
unlikely_text_section ();
- else
- {
- if (in_unlikely_text_section ())
- text_section ();
- }
+ else if (in_unlikely_text_section ())
+ function_section (current_function_decl);
}
if (app_on)
{
new_bb->index = then_bb_index;
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
later. */
life_data_ok = (x_life_data_ok != 0);
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 ();
/* Compute postdominators if we think we'll use them. */
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 == 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
/* The first weak object in the file. */
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
(ignoring the prologue and epilogue). This is set prior to
local register allocation and is valid for the remaining
extern bool decl_readonly_section (tree, 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
given a constant expression. */
extern int compute_reloc_for_constant (tree);
output_function_exception_table ();
#endif
+ user_defined_section_attribute = false;
+
if (! quiet_flag)
fflush (asm_out_file);
sections of the .o file does not work well with exception handling.
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 ();
if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
of all instances. For now just never set frequency for these. */
|| DECL_ONE_ONLY (current_function_decl))
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)
DECL_SECTION_NAME (current_function_decl) =
build_string (strlen (HOT_TEXT_SECTION_NAME), HOT_TEXT_SECTION_NAME);
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)))
{
to optimize, debug_info_level and debug_hooks in process_options (). */
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.
0 means `use default', 1 means `don't align'.
For each variable, there is an _log variant which is the power
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. */
extern int flag_loop_optimize;
extern int flag_crossjumping;
void
unlikely_text_section (void)
{
- if ((in_section != in_unlikely_executed_text)
- && (in_section != in_named
- || strcmp (in_named_name, UNLIKELY_EXECUTED_TEXT_SECTION_NAME) != 0))
+ const char *name;
+ int len;
+
+ if (! unlikely_text_section_name)
{
- if (targetm.have_named_sections)
- named_section (NULL_TREE, UNLIKELY_EXECUTED_TEXT_SECTION_NAME, 0);
+ if (DECL_SECTION_NAME (current_function_decl)
+ && (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
{
- in_section = in_unlikely_executed_text;
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
+ 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);
}
-
+ }
+
+ 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)
{
ASM_OUTPUT_LABEL (asm_out_file, unlikely_section_label);
int
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. */
if (name == NULL)
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);
/* Sanity check user variables for flag changes. Non-user
{
if (scan_ahead_for_unlikely_executed_note (get_insns()))
unlikely_text_section ();
+ else if (decl != NULL_TREE
+ && DECL_SECTION_NAME (decl) != NULL_TREE)
+ named_section (decl, (char *) 0, 0);
else
- {
- if (decl != NULL_TREE
- && DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0, 0);
- else
- text_section ();
- }
+ text_section ();
}
/* Switch to read-only data section associated with function DECL. */
free (unlikely_section_label);
unlikely_section_label = xmalloc ((strlen (fnname) + 18) * sizeof (char));
sprintf (unlikely_section_label, "%s_unlikely_section", fnname);
-
+
/* The following code does not need preprocessing in the assembler. */
app_disable ();
flags = SECTION_CODE;
else if (decl && decl_readonly_section_1 (decl, reloc, shlib))
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;
else
flags = SECTION_WRITE;