diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2019-11-06 10:57:18 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@gcc.gnu.org> | 2019-11-06 10:57:18 +0000 |
commit | 3cf3da88be453f3fceaa596ee78be8d1e5aa21ca (patch) | |
tree | ead0ae87adfe46ab5e364107f3cfe9d60d9d3761 /gcc/toplev.c | |
parent | 5d183d1740d8d8b84991f186ce4d992ee799536f (diff) | |
download | gcc-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.c | 178 |
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 (); |