From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17166 invoked by alias); 26 Oct 2019 07:53:00 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 17158 invoked by uid 89); 26 Oct 2019 07:53:00 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-17.6 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,KAM_STOCKGEN,SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx1.suse.de Received: from mx2.suse.de (HELO mx1.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sat, 26 Oct 2019 07:52:56 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 79B95AC7B; Sat, 26 Oct 2019 07:52:53 +0000 (UTC) Date: Sat, 26 Oct 2019 08:12:00 -0000 User-Agent: K-9 Mail for Android In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: introduce -fcallgraph-info option To: Alexandre Oliva ,gcc-patches@gcc.gnu.org CC: ebotcazou@adacore.com,joseph@codesourcery.com From: Richard Biener Message-ID: <84223B6B-F6F0-4B94-835E-6661E1E1EB6A@suse.de> X-SW-Source: 2019-10/txt/msg01884.txt.bz2 On October 26, 2019 6:35:43 AM GMT+02:00, Alexandre Oliva wrote: >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, 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=3Dsu adds >stack usage info and -fcallgraph-info=3Dda dynamic allocation info. > >Compared with the earlier version, this patch does not modify cgraph, >and instead adds the required information next to the stage usage >function data structure, so we only hold one of those at at time. I've >switched to vecs from linked lists, for more compact edges and dynamic >allocation annotations, and arranged for them to be released as soon as >we've printed out the information. I have NOT changed the file format, >because existing tools such as gnatstack consume the current format. > >Regstrapped on x86_64-linux-gnu. Ok to install? How does it relate to the LTO-dump utility we have now which can in theory = provide a more complete view? Maybe some infrastructure can be shared here = (the actual dumping of the cgraph?)=20 Thanks,=20 Richard.=20 > >for gcc/ChangeLog >From Eric Botcazou , Alexandre Oliva=20 > > > * common.opt (-fcallgraph-info[=3D]): New option. > * doc/invoke.texi (Debugging options): Document it. > * opts.c (common_handle_option): Handle it. > * builtins.c (expand_builtin_alloca): Record allocation if > -fcallgraph-info=3Dda. > * 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. > (rest_of_handle_thread_prologue_and_epilogue): Release callees > and dallocs after output_stack_usage. > (record_final_call, record_dynamic_alloc): New. > * function.h (struct callee, struct 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=3Dda. > * 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_indirect_emitted): Likewise. > (output_stack_usage): Rename to... > (output_stack_usage_1): ... this. Make it static, add cf > parameter. If -fcallgraph-info=3Dsu, print stack usage to cf. > If -fstack-usage, use print_decl_identifier for > pretty-printing. > (INDIRECT_CALL_NAME): New. > (dump_final_indirect_call_node_vcg): New. > (dump_final_callee_vcg, dump_final_node_vcg): New. > (output_stack_usage): New. > (lang_dependent_init): Open and start file if > -fcallgraph-info. > (finalize): If callgraph_info_file is not null, finish it, > close it, and reset callgraph info state. > >for gcc/ada/ChangeLog > > * gcc-interface/misc.c (callgraph_info_file): Delete. >--- > gcc/ada/gcc-interface/misc.c | 3 - > gcc/builtins.c | 4 + > gcc/calls.c | 6 + > gcc/common.opt | 8 ++ > gcc/doc/invoke.texi | 17 ++++ > gcc/explow.c | 5 + > gcc/flag-types.h | 16 ++++ > gcc/function.c | 63 ++++++++++++++-- > gcc/function.h | 25 ++++++ > gcc/gimplify.c | 4 + > gcc/optabs-libfuncs.c | 4 - > gcc/opts.c | 26 ++++++ > gcc/output.h | 2=20 > gcc/print-tree.c | 76 +++++++++++++++++++ > gcc/print-tree.h | 4 + >gcc/toplev.c | 169 >++++++++++++++++++++++++++++++++++-------- > 16 files changed, 381 insertions(+), 51 deletions(-) > >diff --git a/gcc/ada/gcc-interface/misc.c >b/gcc/ada/gcc-interface/misc.c >index 4abd4d5708a54..d68b37384ff7f 100644 >--- a/gcc/ada/gcc-interface/misc.c >+++ b/gcc/ada/gcc-interface/misc.c >@@ -54,9 +54,6 @@ > #include "ada-tree.h" > #include "gigi.h" >=20 >-/* This symbol needs to be defined for the front-end. */ >-void *callgraph_info_file =3D NULL; >- >/* Command-line argc and argv. These variables are global since they >are > imported in back_end.adb. */ > unsigned int save_argc; >diff --git a/gcc/builtins.c b/gcc/builtins.c >index 5d811f113c907..bd302383377ba 100644 >--- a/gcc/builtins.c >+++ b/gcc/builtins.c >@@ -5406,6 +5406,10 @@ expand_builtin_alloca (tree exp) >=3D allocate_dynamic_stack_space (op0, 0, align, max_size, >alloca_for_var); > result =3D convert_memory_address (ptr_mode, result); >=20 >+ /* Dynamic allocations for variables are recorded during >gimplification. */ >+ if (!alloca_for_var && (flag_callgraph_info & >CALLGRAPH_INFO_DYNAMIC_ALLOC)) >+ record_dynamic_alloc (exp); >+ > return result; > } >=20 >diff --git a/gcc/calls.c b/gcc/calls.c >index ae904473d0dc6..67c7c77598a3f 100644 >--- a/gcc/calls.c >+++ b/gcc/calls.c >@@ -3759,6 +3759,9 @@ expand_call (tree exp, rtx target, int ignore) >=20 >preferred_unit_stack_boundary =3D preferred_stack_boundary / >BITS_PER_UNIT; >=20 >+ if (flag_callgraph_info) >+ record_final_call (fndecl, EXPR_LOCATION (exp)); >+ > /* We want to make two insn chains; one for a sibling call, the other > for a normal call. We will select one of the two chains after > initial RTL generation is complete. */ >@@ -5343,6 +5346,9 @@ emit_library_call_value_1 (int retval, rtx >orgfun, rtx value, >=20 > before_call =3D get_last_insn (); >=20 >+ if (flag_callgraph_info) >+ record_final_call (SYMBOL_REF_DECL (orgfun), UNKNOWN_LOCATION); >+ >/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which > will set inhibit_defer_pop to that value. */ >/* The return type is needed to decide how many bytes the function >pops. >diff --git a/gcc/common.opt b/gcc/common.opt >index cc279f411d796..63d646fba2b42 100644 >--- a/gcc/common.opt >+++ b/gcc/common.opt >@@ -1091,6 +1091,14 @@ fbtr-bb-exclusive > Common Ignore > Does nothing. Preserved for backward compatibility. >=20 >+fcallgraph-info >+Common Report RejectNegative Var(flag_callgraph_info) >Init(NO_CALLGRAPH_INFO); >+Output callgraph information on a per-file basis >+ >+fcallgraph-info=3D >+Common Report RejectNegative Joined >+Output callgraph information on a per-file basis with decorations >+ > fcall-saved- > Common Joined RejectNegative Var(common_deferred_options) Defer >-fcall-saved- Mark as being preserved across >functions. >diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi >index 1407d019d1404..545b842eade71 100644 >--- a/gcc/doc/invoke.texi >+++ b/gcc/doc/invoke.texi >@@ -583,8 +583,9 @@ Objective-C and Objective-C++ Dialects}. > @item Developer Options > @xref{Developer Options,,GCC Developer Options}. >@gccoptlist{-d@var{letters} -dumpspecs -dumpmachine -dumpversion >@gol >--dumpfullversion -fchecking -fchecking=3D@var{n} -fdbg-cnt-list @gol >--fdbg-cnt=3D@var{counter-value-list} @gol >+-dumpfullversion -fcallgraph-info@r{[}=3Dsu,da@r{]} >+-fchecking -fchecking=3D@var{n} >+-fdbg-cnt-list @gol -fdbg-cnt=3D@var{counter-value-list} @gol > -fdisable-ipa-@var{pass_name} @gol > -fdisable-rtl-@var{pass_name} @gol > -fdisable-rtl-@var{pass-name}=3D@var{range-list} @gol >@@ -14533,6 +14534,18 @@ The files are created in the directory of the >output file. >=20 > @table @gcctabopt >=20 >+@item -fcallgraph-info >+@itemx -fcallgraph-info=3D@var{MARKERS} >+@opindex fcallgraph-info >+Makes the compiler output callgraph information for the program, on a >+per-file basis. The information is generated in the common VCG >format. >+It can be decorated with additional, per-node and/or per-edge >information, >+if a list of comma-separated markers is additionally specified. When >the >+@code{su} marker is specified, the callgraph is decorated with stack >usage >+information; it is equivalent to @option{-fstack-usage}. When the >@code{da} >+marker is specified, the callgraph is decorated with information about >+dynamically allocated objects. >+ > @item -d@var{letters} > @itemx -fdump-rtl-@var{pass} > @itemx -fdump-rtl-@var{pass}=3D@var{filename} >diff --git a/gcc/explow.c b/gcc/explow.c >index 7eb854bca4a6d..83c786366c1aa 100644 >--- a/gcc/explow.c >+++ b/gcc/explow.c >@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see > #include "dojump.h" > #include "explow.h" > #include "expr.h" >+#include "stringpool.h" > #include "common/common-target.h" > #include "output.h" > #include "params.h" >@@ -1611,6 +1612,10 @@ set_stack_check_libfunc (const char >*libfunc_name) > { > gcc_assert (stack_check_libfunc =3D=3D NULL_RTX); > stack_check_libfunc =3D gen_rtx_SYMBOL_REF (Pmode, libfunc_name); >+ tree decl =3D build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, >+ get_identifier (libfunc_name), void_type_node); >+ DECL_EXTERNAL (decl) =3D 1; >+ SET_SYMBOL_REF_DECL (stack_check_libfunc, decl); > } > > /* Emit one stack probe at ADDRESS, an address within the stack. */ >diff --git a/gcc/flag-types.h b/gcc/flag-types.h >index a2103282d469d..b23d3a271f1ee 100644 >--- a/gcc/flag-types.h >+++ b/gcc/flag-types.h >@@ -200,6 +200,22 @@ enum stack_check_type > FULL_BUILTIN_STACK_CHECK > }; >=20 >+/* Type of callgraph information. */ >+enum callgraph_info_type >+{ >+ /* No information. */ >+ NO_CALLGRAPH_INFO =3D 0, >+ >+ /* Naked callgraph. */ >+ CALLGRAPH_INFO_NAKED =3D 1, >+ >+ /* Callgraph decorated with stack usage information. */ >+ CALLGRAPH_INFO_STACK_USAGE =3D 2, >+ >+ /* Callgraph decoration with dynamic allocation information. */ >+ CALLGRAPH_INFO_DYNAMIC_ALLOC =3D 4 >+}; >+ > /* Floating-point contraction mode. */ > enum fp_contract_mode { > FP_CONTRACT_OFF =3D 0, >diff --git a/gcc/function.c b/gcc/function.c >index a1c76a4dd7a84..152f927097c47 100644 >--- a/gcc/function.c >+++ b/gcc/function.c >@@ -4725,6 +4725,16 @@ get_last_funcdef_no (void) > return funcdef_no; > } >=20 >+/* Allocate and initialize the stack usage info data structure for the >+ current function. */ >+static void >+allocate_stack_usage_info (void) >+{ >+ gcc_assert (!cfun->su); >+ cfun->su =3D ggc_cleared_alloc (); >+ cfun->su->static_stack_size =3D -1; >+} >+ > /* Allocate a function structure for FNDECL and set its contents > to the defaults. Set cfun to the newly-allocated object. > Some of the helper functions invoked during initialization assume >@@ -4802,6 +4812,9 @@ allocate_struct_function (tree fndecl, bool >abstract_p) >=20 > if (!profile_flag && !flag_instrument_function_entry_exit) > DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl) =3D 1; >+ >+ if (flag_callgraph_info) >+ allocate_stack_usage_info (); > } >=20 > /* Don't enable begin stmt markers if var-tracking at assignments is >@@ -4846,11 +4859,8 @@ prepare_function_start (void) > init_expr (); > default_rtl_profile (); >=20 >- if (flag_stack_usage_info) >- { >- cfun->su =3D ggc_cleared_alloc (); >- cfun->su->static_stack_size =3D -1; >- } >+ if (flag_stack_usage_info && !flag_callgraph_info) >+ allocate_stack_usage_info (); >=20 > cse_not_expected =3D ! optimize; >=20 >@@ -6373,12 +6383,51 @@ rest_of_handle_thread_prologue_and_epilogue >(void) > cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0); >=20 > /* The stack usage info is finalized during prologue expansion. */ >- if (flag_stack_usage_info) >- output_stack_usage (); >+ if (flag_stack_usage_info || flag_callgraph_info) >+ { >+ output_stack_usage (); >+ vec_free (cfun->su->dallocs); >+ cfun->su->dallocs =3D NULL; >+ vec_free (cfun->su->callees); >+ cfun->su->callees =3D NULL; >+ } >=20 > return 0; > } >=20 >+/* Record a final call to CALLEE at LOCATION. */ >+ >+void >+record_final_call (tree callee, location_t location) >+{ >+ struct callee datum =3D { location, callee }; >+ vec_safe_push (cfun->su->callees, datum); >+} >+ >+/* Record a dynamic allocation made for DECL_OR_EXP. */ >+ >+void >+record_dynamic_alloc (tree decl_or_exp) >+{ >+ struct dalloc datum; >+ >+ if (DECL_P (decl_or_exp)) >+ { >+ datum.location =3D DECL_SOURCE_LOCATION (decl_or_exp); >+ const char *name =3D lang_hooks.decl_printable_name (decl_or_exp, >2); >+ const char *dot =3D strrchr (name, '.'); >+ if (dot) >+ name =3D dot + 1; >+ datum.name =3D ggc_strdup (name); >+ } >+ else >+ { >+ datum.location =3D EXPR_LOCATION (decl_or_exp); >+ datum.name =3D NULL; >+ } >+ vec_safe_push (cfun->su->dallocs, datum); >+} >+ > namespace { >=20 > const pass_data pass_data_thread_prologue_and_epilogue =3D >diff --git a/gcc/function.h b/gcc/function.h >index 43ac5dffd2457..ec523765d6eec 100644 >--- a/gcc/function.h >+++ b/gcc/function.h >@@ -192,6 +192,18 @@ public: > poly_int64 length; > }; >=20 >+struct GTY(()) callee >+{ >+ location_t location; >+ tree decl; >+}; >+ >+struct GTY(()) dalloc >+{ >+ location_t location; >+ char const *name; >+}; >+ > class GTY(()) stack_usage > { > public: >@@ -210,6 +222,13 @@ public: > /* Nonzero if the amount of stack space allocated dynamically cannot > be bounded at compile-time. */ > unsigned int has_unbounded_dynamic_stack_size : 1; >+ >+ /* Functions called within the function, if callgraph is enabled.=20 >*/ >+ vec *callees; >+ >+ /* Dynamic allocations enocuntered within the function, if callgraph >+ da is enabled. */ >+ vec *dallocs; > }; >=20 >#define current_function_static_stack_size >(cfun->su->static_stack_size) >@@ -406,6 +425,12 @@ void add_local_decl (struct function *fun, tree >d); > #define FOR_EACH_LOCAL_DECL(FUN, I, D) \ > FOR_EACH_VEC_SAFE_ELT_REVERSE ((FUN)->local_decls, I, D) >=20 >+/* Record a final call to CALLEE at LOCATION. */ >+void record_final_call (tree callee, location_t location); >+ >+/* Record a dynamic allocation made for DECL_OR_EXP. */ >+void record_dynamic_alloc (tree decl_or_exp); >+ > /* If va_list_[gf]pr_size is set to this, it means we don't know how > many units need to be saved. */ > #define VA_LIST_MAX_GPR_SIZE 255 >diff --git a/gcc/gimplify.c b/gcc/gimplify.c >index 914bb8eb8d699..394f0fda9c98c 100644 >--- a/gcc/gimplify.c >+++ b/gcc/gimplify.c >@@ -1697,6 +1697,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p) > t =3D build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t); >=20 > gimplify_and_add (t, seq_p); >+ >+ /* Record the dynamic allocation associated with DECL if requested.=20 >*/ >+ if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC) >+ record_dynamic_alloc (decl); > } >=20 >/* A helper function to be called via walk_tree. Mark all labels under >*TP >diff --git a/gcc/optabs-libfuncs.c b/gcc/optabs-libfuncs.c >index ef43dae12fb64..8916f7e4da0bb 100644 >--- a/gcc/optabs-libfuncs.c >+++ b/gcc/optabs-libfuncs.c >@@ -735,10 +735,6 @@ build_libfunc_function_visibility (const char >*name, symbol_visibility vis) > DECL_VISIBILITY_SPECIFIED (decl) =3D 1; > gcc_assert (DECL_ASSEMBLER_NAME (decl)); >=20 >- /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left >with >- are the flags assigned by targetm.encode_section_info. */ >- SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL); >- > return decl; > } >=20 >diff --git a/gcc/opts.c b/gcc/opts.c >index 10b9f108f8d06..f46b468a968e7 100644 >--- a/gcc/opts.c >+++ b/gcc/opts.c >@@ -2433,6 +2433,32 @@ common_handle_option (struct gcc_options *opts, > /* Deferred. */ > break; >=20 >+ case OPT_fcallgraph_info: >+ opts->x_flag_callgraph_info =3D CALLGRAPH_INFO_NAKED; >+ break; >+ >+ case OPT_fcallgraph_info_: >+ { >+ char *my_arg, *p; >+ my_arg =3D xstrdup (arg); >+ p =3D strtok (my_arg, ","); >+ while (p) >+ { >+ if (strcmp (p, "su") =3D=3D 0) >+ { >+ opts->x_flag_callgraph_info |=3D CALLGRAPH_INFO_STACK_USAGE; >+ opts->x_flag_stack_usage_info =3D true; >+ } >+ else if (strcmp (p, "da") =3D=3D 0) >+ opts->x_flag_callgraph_info |=3D CALLGRAPH_INFO_DYNAMIC_ALLOC; >+ else >+ return 0; >+ p =3D strtok (NULL, ","); >+ } >+ free (my_arg); >+ } >+ break; >+ > case OPT_fdiagnostics_show_location_: > diagnostic_prefixing_rule (dc) =3D (diagnostic_prefixing_rule_t) value; > break; >diff --git a/gcc/output.h b/gcc/output.h >index 835d63556e6a8..6cccada4aeb1d 100644 >--- a/gcc/output.h >+++ b/gcc/output.h >@@ -604,7 +604,7 @@ extern int maybe_assemble_visibility (tree); >=20 >extern int default_address_cost (rtx, machine_mode, addr_space_t, >bool); >=20 >-/* Output stack usage information. */ >+/* Stack usage. */ > extern void output_stack_usage (void); >=20 > #endif /* ! GCC_OUTPUT_H */ >diff --git a/gcc/print-tree.c b/gcc/print-tree.c >index 6dcbb2dcb1369..bd09ec4d7a7af 100644 >--- a/gcc/print-tree.c >+++ b/gcc/print-tree.c >@@ -1035,6 +1035,82 @@ print_node (FILE *file, const char *prefix, tree >node, int indent, > fprintf (file, ">"); > } >=20 >+/* Print the identifier for DECL according to FLAGS. */ >+ >+void >+print_decl_identifier (FILE *file, tree decl, int flags) >+{ >+ bool needs_colon =3D false; >+ const char *name; >+ char c; >+ >+ if (flags & PRINT_DECL_ORIGIN) >+ { >+ if (DECL_IS_BUILTIN (decl)) >+ fputs ("", file); >+ else >+ { >+ expanded_location loc >+ =3D expand_location (DECL_SOURCE_LOCATION (decl)); >+ fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column); >+ } >+ needs_colon =3D true; >+ } >+ >+ if (flags & PRINT_DECL_UNIQUE_NAME) >+ { >+ name =3D IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); >+ if (!TREE_PUBLIC (decl) >+ || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl))) >+ /* The symbol has internal or weak linkage so its assembler name >+ is not necessarily unique among the compilation units of the >+ program. We therefore have to further mangle it. But we can't >+ simply use DECL_SOURCE_FILE because it contains the name of the >+ file the symbol originates from so, e.g. for function templates >+ in C++ where the templates are defined in a header file, we can >+ have symbols with the same assembler name and DECL_SOURCE_FILE. >+ That's why we use the name of the top-level source file of the >+ compilation unit. ??? Unnecessary for Ada. */ >+ name =3D ACONCAT ((main_input_filename, ":", name, NULL)); >+ } >+ else if (flags & PRINT_DECL_NAME) >+ { >+ /* 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 =3D strchr (IDENTIFIER_POINTER (DECL_NAME >(decl)), '.'); >+ name =3D lang_hooks.decl_printable_name (decl, 2); >+ if (suffix) >+ { >+ const char *dot =3D strchr (name, '.'); >+ while (dot && strcasecmp (dot, suffix) !=3D 0) >+ { >+ name =3D dot + 1; >+ dot =3D strchr (name, '.'); >+ } >+ } >+ else >+ { >+ const char *dot =3D strrchr (name, '.'); >+ if (dot) >+ name =3D dot + 1; >+ } >+ } >+ else >+ return; >+ >+ if (needs_colon) >+ fputc (':', file); >+ >+ while ((c =3D *name++) !=3D '\0') >+ { >+ /* Strip double-quotes because of VCG. */ >+ if (c =3D=3D '"') >+ continue; >+ fputc (c, file); >+ } >+} >+ >=20 > /* Print the node NODE on standard error, for debugging. > Most nodes referred to by this one are printed recursively >diff --git a/gcc/print-tree.h b/gcc/print-tree.h >index 1d4fe6e8950cc..cbea48c486e3c 100644 >--- a/gcc/print-tree.h >+++ b/gcc/print-tree.h >@@ -42,5 +42,9 @@ extern void print_node (FILE *, const char *, tree, >int, > extern void print_node_brief (FILE *, const char *, const_tree, int); > extern void indent_to (FILE *, int); > #endif >+#define PRINT_DECL_ORIGIN 0x1 >+#define PRINT_DECL_NAME 0x2 >+#define PRINT_DECL_UNIQUE_NAME 0x4 >+extern void print_decl_identifier (FILE *, tree, int flags); >=20 > #endif // GCC_PRINT_TREE_H >diff --git a/gcc/toplev.c b/gcc/toplev.c >index 1c7002f5c37cd..016f6d688f324 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" >=20 > #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO) >@@ -174,6 +175,8 @@ const char *user_label_prefix; >=20 > FILE *asm_out_file; > FILE *aux_info_file; >+FILE *callgraph_info_file =3D NULL; >+static bool callgraph_info_indirect_emitted =3D false; > FILE *stack_usage_file =3D NULL; >=20 > /* The current working directory of a translation. It's generally the >@@ -913,8 +916,8 @@ alloc_for_identifier_to_locale (size_t len) > } >=20 > /* Output stack usage information. */ >-void >-output_stack_usage (void) >+static void >+output_stack_usage_1 (FILE *cf) > { > static bool warning_issued =3D false; > enum stack_usage_kind_type { STATIC =3D 0, DYNAMIC, DYNAMIC_BOUNDED }; >@@ -970,41 +973,22 @@ output_stack_usage (void) > stack_usage +=3D current_function_dynamic_stack_size; > } >=20 >- if (stack_usage_file) >+ if (flag_callgraph_info & CALLGRAPH_INFO_STACK_USAGE) > { >- expanded_location loc >- =3D 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 >- =3D strchr (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), >'.'); >- const char *name >- =3D lang_hooks.decl_printable_name (current_function_decl, 2); >- if (suffix) >- { >- const char *dot =3D strchr (name, '.'); >- while (dot && strcasecmp (dot, suffix) !=3D 0) >- { >- name =3D dot + 1; >- dot =3D strchr (name, '.'); >- } >- } >+ if (stack_usage) >+ fprintf (cf, "\\n" HOST_WIDE_INT_PRINT_DEC " bytes (%s)", >+ stack_usage, >+ stack_usage_kind_str[stack_usage_kind]); > else >- { >- const char *dot =3D strrchr (name, '.'); >- if (dot) >- name =3D dot + 1; >- } >+ fputs ("\\n0 bytes", cf); >+ } >=20 >- fprintf (stack_usage_file, >- "%s:%d:%d:%s\t" HOST_WIDE_INT_PRINT_DEC"\t%s\n", >- loc.file =3D=3D NULL ? "(artificial)" : lbasename (loc.file), >- loc.line, >- loc.column, >- name, >- stack_usage, >- stack_usage_kind_str[stack_usage_kind]); >+ if (stack_usage_file) >+ { >+ 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]); > } >=20 > if (warn_stack_usage >=3D 0 && warn_stack_usage < HOST_WIDE_INT_MAX) >@@ -1026,6 +1010,106 @@ output_stack_usage (void) > } > } >=20 >+/* Dump placeholder node for indirect calls in VCG format. */ >+ >+#define INDIRECT_CALL_NAME "__indirect_call" >+ >+static void >+dump_final_indirect_call_node_vcg (FILE *f) >+{ >+ if (callgraph_info_indirect_emitted) >+ return; >+ >+ fputs ("node: { title: \"", f); >+ fputs (INDIRECT_CALL_NAME, f); >+ fputs ("\" label: \"", f); >+ fputs ("Indirect Call Placeholder", f); >+ fputs ("\" shape : ellipse }\n", f); >+ callgraph_info_indirect_emitted =3D true; >+} >+ >+/* Dump final cgraph edge in VCG format. */ >+ >+static void >+dump_final_callee_vcg (FILE *f, struct callee *callee) >+{ >+ fputs ("edge: { sourcename: \"", f); >+ print_decl_identifier (f, current_function_decl, >PRINT_DECL_UNIQUE_NAME); >+ fputs ("\" targetname: \"", f); >+ if (callee->decl) >+ print_decl_identifier (f, callee->decl, PRINT_DECL_UNIQUE_NAME); >+ else >+ fputs (INDIRECT_CALL_NAME, f); >+ if (LOCATION_LOCUS (callee->location) !=3D UNKNOWN_LOCATION) >+ { >+ expanded_location loc; >+ fputs ("\" label: \"", f); >+ loc =3D expand_location (callee->location); >+ fprintf (f, "%s:%d:%d", loc.file, loc.line, loc.column); >+ } >+ fputs ("\" }\n", f); >+ >+ if (!callee->decl) >+ dump_final_indirect_call_node_vcg (f); >+} >+ >+/* Dump final cgraph node in VCG format. */ >+ >+static void >+dump_final_node_vcg (FILE *f) >+{ >+ fputs ("node: { title: \"", f); >+ print_decl_identifier (f, current_function_decl, >PRINT_DECL_UNIQUE_NAME); >+ fputs ("\" label: \"", f); >+ print_decl_identifier (f, current_function_decl, PRINT_DECL_NAME); >+ fputs ("\\n", f); >+ print_decl_identifier (f, current_function_decl, PRINT_DECL_ORIGIN); >+ >+ if (DECL_EXTERNAL (current_function_decl)) >+ { >+ fputs ("\" shape : ellipse }\n", f); >+ return; >+ } >+ >+ 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; >+ dalloc *cda; >+ FOR_EACH_VEC_SAFE_ELT (cfun->su->dallocs, i, cda) >+ { >+ expanded_location loc =3D expand_location (cda->location); >+ fprintf (f, "\\n %s", cda->name); >+ fprintf (f, " %s:%d:%d", loc.file, loc.line, loc.column); >+ } >+ } >+ >+ fputs ("\" }\n", f); >+ >+ if (flag_callgraph_info) >+ { >+ unsigned i; >+ callee *c; >+ FOR_EACH_VEC_SAFE_ELT (cfun->su->callees, i, c) >+ dump_final_callee_vcg (f, c); >+ } >+} >+ >+/* 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 +1984,15 @@ 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 =3D open_auxiliary_file ("su"); >+ >+ /* If call graph information is desired, open the output file.=20 >*/ >+ if (flag_callgraph_info && !flag_generate_lto) >+ { >+ callgraph_info_file =3D open_auxiliary_file ("ci"); >+ /* Write the file header. */ >+ fprintf (callgraph_info_file, >+ "graph: { title: \"%s\"\n", main_input_filename); >+ } > } >=20 > /* This creates various _DECL nodes, so needs to be called after the >@@ -2044,6 +2137,14 @@ finalize (bool no_backend) > stack_usage_file =3D NULL; > } >=20 >+ if (callgraph_info_file) >+ { >+ fputs ("}\n", callgraph_info_file); >+ fclose (callgraph_info_file); >+ callgraph_info_file =3D NULL; >+ callgraph_info_indirect_emitted =3D false; >+ } >+ > if (seen_error ()) > coverage_remove_note_file (); >=20