aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/final.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/final.c')
-rw-r--r--gcc-4.9/gcc/final.c121
1 files changed, 109 insertions, 12 deletions
diff --git a/gcc-4.9/gcc/final.c b/gcc-4.9/gcc/final.c
index 83abee208..9af0b2bec 100644
--- a/gcc-4.9/gcc/final.c
+++ b/gcc-4.9/gcc/final.c
@@ -125,9 +125,6 @@ static int last_linenum;
/* Last discriminator written to assembly. */
static int last_discriminator;
-/* Discriminator of current block. */
-static int discriminator;
-
/* Highest line number in current block. */
static int high_block_linenum;
@@ -137,9 +134,10 @@ static int high_function_linenum;
/* Filename of last NOTE. */
static const char *last_filename;
-/* Override filename and line number. */
+/* Override filename, line number, and discriminator. */
static const char *override_filename;
static int override_linenum;
+static int override_discriminator;
/* Whether to force emission of a line note before the next insn. */
static bool force_source_line = false;
@@ -204,6 +202,9 @@ bool final_insns_dump_p;
/* True if profile_function should be called, but hasn't been called yet. */
static bool need_profile_function;
+/* True if the function has a split cold section. */
+static bool has_cold_section_p;
+
static int asm_insn_count (rtx);
static void profile_function (FILE *);
static void profile_after_prologue (FILE *);
@@ -1735,7 +1736,7 @@ final_start_function (rtx first, FILE *file,
last_filename = LOCATION_FILE (prologue_location);
last_linenum = LOCATION_LINE (prologue_location);
- last_discriminator = discriminator = 0;
+ last_discriminator = 0;
high_block_linenum = high_function_linenum = last_linenum;
@@ -1807,9 +1808,13 @@ final_start_function (rtx first, FILE *file,
if (warn_frame_larger_than
&& get_frame_size () > frame_larger_than_size)
{
- /* Issue a warning */
+ /* Issue a warning. (WARN_FRAME_LARGER_THAN_EXTRA_TEXT is
+ provided by configuration. The way extra text is added
+ here may prevent localization from working properly.
+ It's totally broken.) */
warning (OPT_Wframe_larger_than_,
- "the frame size of %wd bytes is larger than %wd bytes",
+ "the frame size of %wd bytes is larger than %wd bytes"
+ WARN_FRAME_LARGER_THAN_EXTRA_TEXT,
get_frame_size (), frame_larger_than_size);
}
@@ -1852,7 +1857,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
switch_to_section (data_section);
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
- targetm.asm_out.internal_label (file, "LP", current_function_funcdef_no);
+ targetm.asm_out.internal_label (file, "LP", FUNC_LABEL_ID (cfun));
assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
}
@@ -1865,7 +1870,7 @@ profile_function (FILE *file ATTRIBUTE_UNUSED)
ASM_OUTPUT_REG_PUSH (file, REGNO (chain));
#endif
- FUNCTION_PROFILER (file, current_function_funcdef_no);
+ FUNCTION_PROFILER (file, FUNC_LABEL_ID (cfun));
#ifdef ASM_OUTPUT_REG_PUSH
if (chain && REG_P (chain))
@@ -2174,6 +2179,7 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
ASM_OUTPUT_LABEL (asm_out_file,
IDENTIFIER_POINTER (cold_function_name));
}
+ has_cold_section_p = true;
break;
case NOTE_INSN_BASIC_BLOCK:
@@ -2186,8 +2192,6 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
if (targetm.asm_out.unwind_emit)
targetm.asm_out.unwind_emit (asm_out_file, insn);
- discriminator = NOTE_BASIC_BLOCK (insn)->discriminator;
-
break;
case NOTE_INSN_EH_REGION_BEG:
@@ -2280,6 +2284,8 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
{
override_filename = LOCATION_FILE (*locus_ptr);
override_linenum = LOCATION_LINE (*locus_ptr);
+ override_discriminator =
+ get_discriminator_from_locus (*locus_ptr);
}
}
break;
@@ -2313,11 +2319,14 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
{
override_filename = LOCATION_FILE (*locus_ptr);
override_linenum = LOCATION_LINE (*locus_ptr);
+ override_discriminator =
+ get_discriminator_from_locus (*locus_ptr);
}
else
{
override_filename = NULL;
override_linenum = 0;
+ override_discriminator = 0;
}
}
break;
@@ -3000,6 +3009,17 @@ final_scan_insn (rtx insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED,
}
return NEXT_INSN (insn);
}
+
+/* Return discriminator of the statement that produced this insn. */
+int
+insn_discriminator (const_rtx insn)
+{
+ location_t loc = INSN_LOCATION (insn);
+ if (!loc)
+ return 0;
+ return get_discriminator_from_locus (loc);
+}
+
/* Return whether a source line note needs to be emitted before INSN.
Sets IS_STMT to TRUE if the line should be marked as a possible
@@ -3010,16 +3030,19 @@ notice_source_line (rtx insn, bool *is_stmt)
{
const char *filename;
int linenum;
+ int discriminator;
if (override_filename)
{
filename = override_filename;
linenum = override_linenum;
+ discriminator = override_discriminator;
}
else
{
filename = insn_file (insn);
linenum = insn_line (insn);
+ discriminator = insn_discriminator (insn);
}
if (filename == NULL)
@@ -4405,13 +4428,55 @@ leaf_renumber_regs_insn (rtx in_rtx)
}
}
#endif
-
+
+/* List the call graph profiled edges whise value is greater than
+ PARAM_NOTE_CGRAPH_SECTION_EDGE_THRESHOLD in the
+ "gnu.callgraph.text" section. */
+static void
+dump_cgraph_profiles (void)
+{
+ struct cgraph_node *node = cgraph_get_node (current_function_decl);
+ struct cgraph_edge *e;
+ struct cgraph_node *callee;
+
+ for (e = node->callees; e != NULL; e = e->next_callee)
+ {
+ if (e->count <= PARAM_VALUE (PARAM_GNU_CGRAPH_SECTION_EDGE_THRESHOLD))
+ continue;
+ callee = e->callee;
+ fprintf (asm_out_file, "\t.string \"%s\"\n",
+ IDENTIFIER_POINTER (decl_assembler_name (callee->decl)));
+ fprintf (asm_out_file, "\t.string \"" HOST_WIDEST_INT_PRINT_DEC "\"\n",
+ e->count);
+ }
+}
+
+/* Iterate through the basic blocks in DECL and get the max count.
+ If COLD is true, find the max count of the cold part of the split. */
+static gcov_type
+get_max_count (tree decl, bool cold)
+{
+ basic_block bb;
+ gcov_type max_count = cold ? 0 :(cgraph_get_node (decl))->count;
+
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ if (cold && BB_PARTITION (bb) != BB_COLD_PARTITION)
+ continue;
+ if (bb->count > max_count)
+ max_count = bb->count;
+ }
+ return max_count;
+}
+
/* Turn the RTL into assembly. */
static unsigned int
rest_of_handle_final (void)
{
rtx x;
const char *fnname;
+ char *profile_fnname;
+ unsigned int flags;
/* Get the function's name, as described by its RTL. This may be
different from the DECL_NAME name used in the source file. */
@@ -4422,6 +4487,8 @@ rest_of_handle_final (void)
gcc_assert (GET_CODE (x) == SYMBOL_REF);
fnname = XSTR (x, 0);
+ has_cold_section_p = false;
+
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize);
@@ -4471,6 +4538,36 @@ rest_of_handle_final (void)
targetm.asm_out.destructor (XEXP (DECL_RTL (current_function_decl), 0),
decl_fini_priority_lookup
(current_function_decl));
+
+ /* With -fcallgraph-profiles-sections and -freorder-functions=,
+ add ".gnu.callgraph.text" section for storing profiling information. */
+ if ((flag_reorder_functions > 1)
+ && flag_profile_use
+ && cgraph_get_node (current_function_decl) != NULL
+ && ((cgraph_get_node (current_function_decl))->callees != NULL
+ || (cgraph_get_node (current_function_decl))->count > 0))
+ {
+ flags = SECTION_DEBUG | SECTION_EXCLUDE;
+ asprintf (&profile_fnname, ".gnu.callgraph.text.%s", fnname);
+ switch_to_section (get_section (profile_fnname, flags, NULL));
+ fprintf (asm_out_file, "\t.string \"Function %s\"\n", fnname);
+ fprintf (asm_out_file, "\t.string \"Weight "
+ HOST_WIDEST_INT_PRINT_DEC
+ " "
+ HOST_WIDEST_INT_PRINT_DEC
+ "\"\n",
+ (cgraph_get_node (current_function_decl))->count,
+ get_max_count (current_function_decl, false));
+ /* If this function is split into a cold section, record that weight
+ here. */
+ if (has_cold_section_p)
+ fprintf (asm_out_file, "\t.string \"ColdWeight "
+ HOST_WIDEST_INT_PRINT_DEC
+ "\"\n",
+ get_max_count (current_function_decl, true));
+ dump_cgraph_profiles ();
+ free (profile_fnname);
+ }
return 0;
}