aboutsummaryrefslogtreecommitdiff
path: root/gcc/toplev.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2019-11-06 10:57:18 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2019-11-06 10:57:18 +0000
commit3cf3da88be453f3fceaa596ee78be8d1e5aa21ca (patch)
treeead0ae87adfe46ab5e364107f3cfe9d60d9d3761 /gcc/toplev.c
parent5d183d1740d8d8b84991f186ce4d992ee799536f (diff)
downloadgcc-3cf3da88be453f3fceaa596ee78be8d1e5aa21ca.zip
gcc-3cf3da88be453f3fceaa596ee78be8d1e5aa21ca.tar.gz
gcc-3cf3da88be453f3fceaa596ee78be8d1e5aa21ca.tar.bz2
introduce -fcallgraph-info option
This was first submitted many years ago https://gcc.gnu.org/ml/gcc-patches/2010-10/msg02468.html The command line option -fcallgraph-info is added and makes the compiler generate another output file (xxx.ci) for each compilation unit (or LTO partitoin), which is a valid VCG file (you can launch your favorite VCG viewer on it unmodified) and contains the "final" callgraph of the unit. "final" is a bit of a misnomer as this is actually the callgraph at RTL expansion time, but since most high-level optimizations are done at the Tree level and RTL doesn't usually fiddle with calls, it's final in almost all cases. Moreover, the nodes can be decorated with additional info: -fcallgraph-info=su adds stack usage info and -fcallgraph-info=da dynamic allocation info. for gcc/ChangeLog From Eric Botcazou <ebotcazou@adacore.com>, Alexandre Oliva <oliva@adacore.com> * common.opt (-fcallgraph-info[=]): New option. * doc/invoke.texi (Developer options): Document it. * opts.c (common_handle_option): Handle it. * builtins.c (expand_builtin_alloca): Record allocation if -fcallgraph-info=da. * calls.c (expand_call): If -fcallgraph-info, record the call. (emit_library_call_value_1): Likewise. * flag-types.h (enum callgraph_info_type): New type. * explow.c: Include stringpool.h. (set_stack_check_libfunc): Set SET_SYMBOL_REF_DECL on the symbol. * function.c (allocate_stack_usage_info): New. (allocate_struct_function): Call it for -fcallgraph-info. (prepare_function_start): Call it otherwise. (record_final_call, record_dynamic_alloc): New. * function.h (struct callinfo_callee): New. (CALLEE_FROM_CGRAPH_P): New. (struct callinfo_dalloc): New. (struct stack_usage): Add callees and dallocs. (record_final_call, record_dynamic_alloc): Declare. * gimplify.c (gimplify_decl_expr): Record dynamically-allocated object if -fcallgraph-info=da. * optabs-libfuncs.c (build_libfunc_function): Keep SYMBOL_REF_DECL. * print-tree.h (print_decl_identifier): Declare. (PRINT_DECL_ORIGIN, PRINT_DECL_NAME, PRINT_DECL_UNIQUE_NAME): New. * print-tree.c: Include print-tree.h. (print_decl_identifier): New function. * toplev.c: Include print-tree.h. (callgraph_info_file): New global variable. (callgraph_info_external_printed): Likewise. (output_stack_usage): Rename to... (output_stack_usage_1): ... this. Make it static, add cf parameter. If -fcallgraph-info=su, print stack usage to cf. If -fstack-usage, use print_decl_identifier for pretty-printing. (INDIRECT_CALL_NAME): New. (dump_final_node_vcg_start): New. (dump_final_callee_vcg, dump_final_node_vcg): New. (output_stack_usage): New. (lang_dependent_init): Open and start file if -fcallgraph-info. Allocated callgraph_info_external_printed. (finalize): If callgraph_info_file is not null, finish it, close it, and release callgraph_info_external_printed. for gcc/ada/ChangeLog * gcc-interface/misc.c (callgraph_info_file): Delete. Co-Authored-By: Alexandre Oliva <oliva@adacore.com> From-SVN: r277876
Diffstat (limited to 'gcc/toplev.c')
-rw-r--r--gcc/toplev.c178
1 files changed, 143 insertions, 35 deletions
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 00a5e83..18fea1c 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see
#include "dumpfile.h"
#include "ipa-fnsummary.h"
#include "dump-context.h"
+#include "print-tree.h"
#include "optinfo-emit-json.h"
#if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
@@ -174,6 +175,8 @@ const char *user_label_prefix;
FILE *asm_out_file;
FILE *aux_info_file;
+FILE *callgraph_info_file = NULL;
+static bitmap callgraph_info_external_printed;
FILE *stack_usage_file = NULL;
/* The current working directory of a translation. It's generally the
@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len)
}
/* Output stack usage information. */
-void
-output_stack_usage (void)
+static void
+output_stack_usage_1 (FILE *cf)
{
static bool warning_issued = false;
enum stack_usage_kind_type { STATIC = 0, DYNAMIC, DYNAMIC_BOUNDED };
@@ -970,41 +973,17 @@ output_stack_usage (void)
stack_usage += current_function_dynamic_stack_size;
}
+ if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE)
+ fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)",
+ stack_usage,
+ stack_usage_kind_str[stack_usage_kind]);
+
if (stack_usage_file)
{
- expanded_location loc
- = expand_location (DECL_SOURCE_LOCATION (current_function_decl));
- /* We don't want to print the full qualified name because it can be long,
- so we strip the scope prefix, but we may need to deal with the suffix
- created by the compiler. */
- const char *suffix
- = strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), '.');
- const char *name
- = lang_hooks.decl_printable_name (current_function_decl, 2);
- if (suffix)
- {
- const char *dot = strchr (name, '.');
- while (dot && strcasecmp (dot, suffix) != 0)
- {
- name = dot + 1;
- dot = strchr (name, '.');
- }
- }
- else
- {
- const char *dot = strrchr (name, '.');
- if (dot)
- name = dot + 1;
- }
-
- fprintf (stack_usage_file,
- "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
- loc.file == NULL ? "(artificial)" : lbasename (loc.file),
- loc.line,
- loc.column,
- name,
- stack_usage,
- stack_usage_kind_str[stack_usage_kind]);
+ print_decl_identifier (stack_usage_file, current_function_decl,
+ PRINT_DECL_ORIGIN | PRINT_DECL_NAME);
+ fprintf (stack_usage_file, "\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n",
+ stack_usage, stack_usage_kind_str[stack_usage_kind]);
}
if (warn_stack_usage >= 0 && warn_stack_usage < HOST_WIDE_INT_MAX)
@@ -1026,6 +1005,115 @@ output_stack_usage (void)
}
}
+/* Dump placeholder node for indirect calls in VCG format. */
+
+#define INDIRECT_CALL_NAME "__indirect_call"
+
+static void
+dump_final_node_vcg_start (FILE *f, tree decl)
+{
+ fputs ("node: { title: \"", f);
+ if (decl)
+ print_decl_identifier (f, decl, PRINT_DECL_UNIQUE_NAME);
+ else
+ fputs (INDIRECT_CALL_NAME, f);
+ fputs ("\" label: \"", f);
+ if (decl)
+ {
+ print_decl_identifier (f, decl, PRINT_DECL_NAME);
+ fputs ("\\n", f);
+ print_decl_identifier (f, decl, PRINT_DECL_ORIGIN);
+ }
+ else
+ fputs ("Indirect Call Placeholder", f);
+}
+
+/* Dump final cgraph edge in VCG format. */
+
+static void
+dump_final_callee_vcg (FILE *f, location_t location, tree callee)
+{
+ if ((!callee || DECL_EXTERNAL (callee))
+ && bitmap_set_bit (callgraph_info_external_printed,
+ callee ? DECL_UID (callee) + 1 : 0))
+ {
+ dump_final_node_vcg_start (f, callee);
+ fputs ("\" shape : ellipse }\n", f);
+ }
+
+ fputs ("edge: { sourcename: \"", f);
+ print_decl_identifier (f, current_function_decl, PRINT_DECL_UNIQUE_NAME);
+ fputs ("\" targetname: \"", f);
+ if (callee)
+ print_decl_identifier (f, callee, PRINT_DECL_UNIQUE_NAME);
+ else
+ fputs (INDIRECT_CALL_NAME, f);
+ if (LOCATION_LOCUS (location) != UNKNOWN_LOCATION)
+ {
+ expanded_location loc;
+ fputs ("\" label: \"", f);
+ loc = expand_location (location);
+ fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column);
+ }
+ fputs ("\" }\n", f);
+}
+
+/* Dump final cgraph node in VCG format. */
+
+static void
+dump_final_node_vcg (FILE *f)
+{
+ dump_final_node_vcg_start (f, current_function_decl);
+
+ if (flag_stack_usage_info
+ || (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE))
+ output_stack_usage_1 (f);
+
+ if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
+ {
+ fprintf (f, "\\n%u dynamic objects", vec_safe_length (cfun->su->dallocs));
+
+ unsigned i;
+ callinfo_dalloc *cda;
+ FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda)
+ {
+ expanded_location loc = expand_location (cda->location);
+ fprintf (f, "\\n %s", cda->name);
+ fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column);
+ }
+
+ vec_free (cfun->su->dallocs);
+ cfun->su->dallocs = NULL;
+ }
+
+ fputs ("\" }\n", f);
+
+ unsigned i;
+ callinfo_callee *c;
+ FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c)
+ dump_final_callee_vcg (f, c->location, c->decl);
+ vec_free (cfun->su->callees);
+ cfun->su->callees = NULL;
+
+ cgraph_node *cnode = cgraph_node::get (current_function_decl);
+ for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
+ if (CALLEE_FROM_CGRAPH_P (e->callee->decl))
+ dump_final_callee_vcg (f, gimple_location (e->call_stmt),
+ e->callee->decl);
+ for (cgraph_edge *e = cnode->indirect_calls; e; e = e->next_callee)
+ dump_final_callee_vcg (f, gimple_location (e->call_stmt), NULL);
+}
+
+/* Output stack usage and callgraph info, as requested. */
+void
+output_stack_usage (void)
+{
+ if (flag_callgraph_info)
+ dump_final_node_vcg (callgraph_info_file);
+ else
+ output_stack_usage_1 (NULL);
+}
+
/* Open an auxiliary output file. */
static FILE *
open_auxiliary_file (const char *ext)
@@ -1900,6 +1988,17 @@ lang_dependent_init (const char *name)
/* If stack usage information is desired, open the output file. */
if (flag_stack_usage && !flag_generate_lto)
stack_usage_file = open_auxiliary_file ("su");
+
+ /* If call graph information is desired, open the output file. */
+ if (flag_callgraph_info && !flag_generate_lto)
+ {
+ callgraph_info_file = open_auxiliary_file ("ci");
+ /* Write the file header. */
+ fprintf (callgraph_info_file,
+ "graph: { title: \"%s\"\n", main_input_filename);
+ bitmap_obstack_initialize (NULL);
+ callgraph_info_external_printed = BITMAP_ALLOC (NULL);
+ }
}
/* This creates various _DECL nodes, so needs to be called after the
@@ -2053,6 +2152,15 @@ finalize (bool no_backend)
stack_usage_file = NULL;
}
+ if (callgraph_info_file)
+ {
+ fputs ("}\n", callgraph_info_file);
+ fclose (callgraph_info_file);
+ callgraph_info_file = NULL;
+ BITMAP_FREE (callgraph_info_external_printed);
+ bitmap_obstack_release (NULL);
+ }
+
if (seen_error ())
coverage_remove_note_file ();