From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 453 invoked by alias); 25 Apr 2011 23:39:08 -0000 Received: (qmail 31142 invoked by uid 22791); 25 Apr 2011 23:38:31 -0000 X-SWARE-Spam-Status: No, hits=1.1 required=5.0 tests=BAYES_50,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_PASS,TW_BJ,TW_CP,TW_JC,TW_JL,TW_VP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 25 Apr 2011 23:37:43 +0000 Received: from kpbe12.cbf.corp.google.com (kpbe12.cbf.corp.google.com [172.25.105.76]) by smtp-out.google.com with ESMTP id p3PNbemH002726 for ; Mon, 25 Apr 2011 16:37:40 -0700 Received: from pvg11 (pvg11.prod.google.com [10.241.210.139]) by kpbe12.cbf.corp.google.com with ESMTP id p3PNbZPm007376 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Mon, 25 Apr 2011 16:37:38 -0700 Received: by pvg11 with SMTP id 11so90580pvg.13 for ; Mon, 25 Apr 2011 16:37:38 -0700 (PDT) MIME-Version: 1.0 Received: by 10.143.177.6 with SMTP id e6mr46097wfp.223.1303774657920; Mon, 25 Apr 2011 16:37:37 -0700 (PDT) Received: by 10.142.202.10 with HTTP; Mon, 25 Apr 2011 16:37:37 -0700 (PDT) In-Reply-To: References: <20110425232927.75B241B40B6@aples.mtv.corp.google.com> Date: Tue, 26 Apr 2011 02:15:00 -0000 Message-ID: Subject: Re: [google] Port LIPO support to google/main (issue4431065) From: Rong Xu To: Xinliang David Li Cc: reply@codereview.appspotmail.com, gcc-patches@gcc.gnu.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-System-Of-Record: true 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 X-SW-Source: 2011-04/txt/msg02013.txt.bz2 LGTM On Mon, Apr 25, 2011 at 4:32 PM, Xinliang David Li wro= te: > Bootstrapped on x86_64/linux with all regression tests passing. > > Additional tests: SPEC2k, SPEC06 FDO and LIPO testing. > > Note -- there will be work in move LIPO away from FE based solution, > this patch is needed to make the base for forward progress. > > David > > On Mon, Apr 25, 2011 at 4:29 PM, David Li wrote: >> 2011-04-25 =A0David Li =A0 >> >> =A0 =A0 =A0 =A0* cgraphbuild.c (rebuild_cgraph_edges): Create edges based >> =A0 =A0 =A0 =A0using resolved nodes in LIPO mode after ipa_tree_profilin= g. >> =A0 =A0 =A0 =A0* dyn-ipa.c: =A0New file. >> =A0 =A0 =A0 =A0* dbgcnt.def: New debug counters. >> =A0 =A0 =A0 =A0* c-family/c-opts.c (c_common_post_options): New option. >> =A0 =A0 =A0 =A0(c_common_parse_file): LIPO mode driver change. >> =A0 =A0 =A0 =A0(push_command_line_include): New function. >> =A0 =A0 =A0 =A0* cgraph.c (cgraph_mark_reachable_node): Handle aux modul= e nodes. >> =A0 =A0 =A0 =A0(cgraph_clone_node): New field initialization. >> =A0 =A0 =A0 =A0(cgraph_create_virtual_clone): New field initialization. >> =A0 =A0 =A0 =A0* value-prof.c (dump_histogram_value): New hist kind. >> =A0 =A0 =A0 =A0(check_counter): New function. >> =A0 =A0 =A0 =A0(gimple_value_profile_transformations): New ic kind. >> =A0 =A0 =A0 =A0(gimple_ic_transform): Changed interface. >> =A0 =A0 =A0 =A0(gimple_indirect_call_to_profile): New vpt kind. >> =A0 =A0 =A0 =A0(gimple_find_values_to_profile): New vpt kind. >> =A0 =A0 =A0 =A0* cgraphunit.c (cgraph_finalize_function): Handle LIPO mo= de. >> =A0 =A0 =A0 =A0(verify_edge_count_and_frequency): Ditto. >> =A0 =A0 =A0 =A0(verify_cgraph_node): Ditto. >> =A0 =A0 =A0 =A0(cgraph_finalize_compilation_unit): Ditto. >> =A0 =A0 =A0 =A0(cgraph_mark_functions_to_output): Ditto. >> =A0 =A0 =A0 =A0(cgraph_expand_function): Ditto. >> =A0 =A0 =A0 =A0(cgraph_output_in_order): Ditto. >> =A0 =A0 =A0 =A0(cgraph_optimize): Ditto. >> =A0 =A0 =A0 =A0(cgraph_copy_node_for_versioning): Ditto. >> =A0 =A0 =A0 =A0(cgraph_materialize_clone): Ditto. >> =A0 =A0 =A0 =A0(cgraph_redirect_edge_call_stmt_to_callee): Ditto. >> =A0 =A0 =A0 =A0* cp/decl.c (walk_namespaces): Ditto. >> =A0 =A0 =A0 =A0(duplicate_decls): Ditto. >> =A0 =A0 =A0 =A0(make_rtl_for_nonlocal_decl): Ditto. >> =A0 =A0 =A0 =A0* cp/rtti.c (get_tinfo_decl): Ditto. >> =A0 =A0 =A0 =A0(create_pseudo_type_info): Ditto. >> =A0 =A0 =A0 =A0(create_tinfo_types): Ditto. >> =A0 =A0 =A0 =A0* cp/cp-lang.c (cp_classify_record): Ditto. >> =A0 =A0 =A0 =A0* cp/pt.c (instantiate_decl): Ditto. >> =A0 =A0 =A0 =A0* cp/semantics.c (emit_associated_thunks): Ditto. >> =A0 =A0 =A0 =A0* cp/decl2.c (start_static_storage_duration_function): Di= tto. >> =A0 =A0 =A0 =A0(prune_vars_needing_no_initialization): =A0Ditto. >> =A0 =A0 =A0 =A0(cxx_callgraph_analyze_expr): Ditto. >> =A0 =A0 =A0 =A0(no_linkage_error): Ditto. >> =A0 =A0 =A0 =A0(collect_all_refs): Ditto. >> =A0 =A0 =A0 =A0(cp_write_global_declarations): Ditto. >> =A0 =A0 =A0 =A0* cp/parser.c (pragma_lex): Ditto. >> =A0 =A0 =A0 =A0* cp/cp-objcp-common.c (cp_function_decl_explicit_p): Dit= to. >> =A0 =A0 =A0 =A0* cp/mangle.c (mangle_conv_op_name_for_type): Ditto. >> =A0 =A0 =A0 =A0* cp/name-lookup.c (add_decl_to_level): Ditto. >> =A0 =A0 =A0 =A0* gcov-io.c (gcov_read_summary): Ditto. >> =A0 =A0 =A0 =A0* tree-ssa-alias.c (same_type_for_tbaa): Ditto. >> =A0 =A0 =A0 =A0(refs_may_alias_p_1): Ditto. >> =A0 =A0 =A0 =A0(walk_aliased_vdefs): Ditto. >> =A0 =A0 =A0 =A0* ipa-inline.c (cgraph_mark_inline_edge): Ditto. >> =A0 =A0 =A0 =A0(cgraph_recursive_inlining_p): Ditto. >> =A0 =A0 =A0 =A0(cgraph_edge_badness): Ditto. >> =A0 =A0 =A0 =A0(update_caller_keys): Ditto. >> =A0 =A0 =A0 =A0(cgraph_decide_recursive_inlining): Ditto. >> =A0 =A0 =A0 =A0(cgraph_decide_inlining_of_small_function): Ditto. >> =A0 =A0 =A0 =A0(cgraph_decide_inlining): Ditto. >> =A0 =A0 =A0 =A0(cgraph_decide_inlining_incrementally): Ditto. >> =A0 =A0 =A0 =A0(estimate_function_body_sizes): Ditto. >> =A0 =A0 =A0 =A0* dwarf2out.c (dwarf2out_do_cfi_startproc): Ditto. >> =A0 =A0 =A0 =A0(dwarf2out_begin_prologue): Ditto. >> =A0 =A0 =A0 =A0(dwarf2out_end_epilogue): Ditto. >> =A0 =A0 =A0 =A0(dw_loc_list): Ditto. >> =A0 =A0 =A0 =A0(gen_subprogram_die): Ditto. >> =A0 =A0 =A0 =A0(dwarf2out_source_line): Ditto. >> =A0 =A0 =A0 =A0* c-decl.c (bind): Ditto. >> =A0 =A0 =A0 =A0(pop_scope): Ditto. Ditto. >> =A0 =A0 =A0 =A0(push_file_scope): Ditto. >> =A0 =A0 =A0 =A0(pop_file_scope): Ditto. >> =A0 =A0 =A0 =A0(finish_decl): Ditto. >> =A0 =A0 =A0 =A0(c_write_global_declarations): Ditto. >> =A0 =A0 =A0 =A0* langhooks.c (lhd_do_nothing_f): Ditto. >> =A0 =A0 =A0 =A0(lhd_do_nothing_t_t_return_null_tree): Ditto. >> =A0 =A0 =A0 =A0(lhd_return_null_tree_v): Ditto. >> =A0 =A0 =A0 =A0(lhd_builtin_function): Ditto. >> =A0 =A0 =A0 =A0* function.c (pop_cfun): Ditto. >> =A0 =A0 =A0 =A0(allocate_struct_function): Ditto. >> =A0 =A0 =A0 =A0* profile.c (instrument_values): Ditto. >> =A0 =A0 =A0 =A0(is_edge_inconsistent): Ditto. >> =A0 =A0 =A0 =A0* ipa.c (process_references): Ditto. >> =A0 =A0 =A0 =A0(cgraph_remove_unreachable_nodes): Ditto. >> =A0 =A0 =A0 =A0(function_and_variable_visibility): >> =A0 =A0 =A0 =A0* c-typeck.c (tagged_types_tu_compatible_p): Ditto. >> =A0 =A0 =A0 =A0* gimplify.c (gimplify_addr_expr): Ditto. >> =A0 =A0 =A0 =A0* except.c (sjlj_emit_function_enter): Ditto. >> =A0 =A0 =A0 =A0(output_one_function_exception_table): Ditto. >> =A0 =A0 =A0 =A0* coverage.c (get_gcov_type): Ditto. >> =A0 =A0 =A0 =A0(htab_counts_entry_del): Ditto. >> =A0 =A0 =A0 =A0(read_counts_file): Ditto. >> =A0 =A0 =A0 =A0(get_coverage_counts): Ditto. >> =A0 =A0 =A0 =A0(coverage_checksum_string): Ditto. >> =A0 =A0 =A0 =A0(coverage_begin_output): Ditto. >> =A0 =A0 =A0 =A0(coverage_end_function): Ditto. >> =A0 =A0 =A0 =A0(build_fn_info_type): Ditto. >> =A0 =A0 =A0 =A0(build_fn_info_value): Ditto. >> =A0 =A0 =A0 =A0(build_ctr_info_value): Ditto. >> =A0 =A0 =A0 =A0(build_gcov_info): Ditto. >> =A0 =A0 =A0 =A0(create_coverage): Ditto. >> =A0 =A0 =A0 =A0(coverage_finish): Ditto. >> =A0 =A0 =A0 =A0* tree-sra.c (convert_callers): Ditto. >> =A0 =A0 =A0 =A0(modify_function): Ditto. >> =A0 =A0 =A0 =A0(ipa_early_sra): Ditto. >> =A0 =A0 =A0 =A0* varasm.c (notice_global_symbol): Ditto. >> =A0 =A0 =A0 =A0(assemble_external): Ditto. >> =A0 =A0 =A0 =A0(mark_decl_referenced): Ditto. >> =A0 =A0 =A0 =A0(find_decl_and_mark_needed): Ditto. >> =A0 =A0 =A0 =A0(finish_aliases_1): Ditto. >> =A0 =A0 =A0 =A0(assemble_alias): Ditto. >> =A0 =A0 =A0 =A0* tree-ssa.c (useless_type_conversion_p): Ditto. >> =A0 =A0 =A0 =A0* tree-inline.c (copy_bb): Ditto. >> =A0 =A0 =A0 =A0(copy_edges_for_bb): Ditto. >> =A0 =A0 =A0 =A0(initialize_cfun): Ditto. >> =A0 =A0 =A0 =A0(copy_cfg_body): Ditto. >> =A0 =A0 =A0 =A0(tree_inlinable_function_p): Ditto. >> =A0 =A0 =A0 =A0(optimize_inline_calls): Ditto. >> =A0 =A0 =A0 =A0(copy_tree_r): Ditto. >> =A0 =A0 =A0 =A0* tree-profile.c (init_ic_make_global_vars): Ditto. >> =A0 =A0 =A0 =A0(gimple_init_edge_profiler): Ditto. >> =A0 =A0 =A0 =A0(gimple_gen_ic_profiler): Ditto. >> =A0 =A0 =A0 =A0(gimple_gen_ic_func_profiler): Ditto. >> =A0 =A0 =A0 =A0(tree_profiling): Ditto. >> =A0 =A0 =A0 =A0* opts-global.c (lang_handle_option): Ditto. >> =A0 =A0 =A0 =A0(add_input_filename): Ditto. >> =A0 =A0 =A0 =A0(read_cmdline_options): Ditto. >> =A0 =A0 =A0 =A0* l-ipo.c: Ditto. >> =A0 =A0 =A0 =A0* libgcov.c (gcov_version): Ditto. >> =A0 =A0 =A0 =A0(gcov_exit): Ditto. >> =A0 =A0 =A0 =A0(__gcov_init): Ditto. >> =A0 =A0 =A0 =A0(__gcov_flush): Ditto. >> =A0 =A0 =A0 =A0(__gcov_merge_ior): Ditto. >> =A0 =A0 =A0 =A0(__gcov_one_value_profiler_body): Ditto. >> =A0 =A0 =A0 =A0(__gcov_indirect_call_profiler): Ditto. >> =A0 =A0 =A0 =A0* l-ipo.h: Ditto. >> =A0 =A0 =A0 =A0* tree-cfg.c: (verify_types_in_gimple_reference): Ditto. >> =A0 =A0 =A0 =A0(verify_gimple_call): Ditto. >> =A0 =A0 =A0 =A0(verify_gimple_assign_single): Ditto. >> =A0 =A0 =A0 =A0(verify_gimple_return): Ditto. >> =A0 =A0 =A0 =A0(gimple_verify_flow_info): Ditto. >> =A0 =A0 =A0 =A0* passes.c: (rest_of_decl_compilation): Ditto. >> =A0 =A0 =A0 =A0(init_optimization_passes): Ditto. >> =A0 =A0 =A0 =A0(pass_init_dump_file): Ditto. >> =A0 =A0 =A0 =A0* varpool.c (varpool_node): Ditto. >> =A0 =A0 =A0 =A0(debug_varpool): Ditto. >> =A0 =A0 =A0 =A0(varpool_node_for_asm): Ditto. >> =A0 =A0 =A0 =A0(varpool_enqueue_needed_node): Ditto. >> =A0 =A0 =A0 =A0* stmt.c (expand_asm_operands): Ditto. >> =A0 =A0 =A0 =A0* gcov-dump.c (main): Ditto. >> =A0 =A0 =A0 =A0(print_usage): Ditto. >> =A0 =A0 =A0 =A0(print_prefix): Ditto. >> =A0 =A0 =A0 =A0(dump_file): Ditto. >> =A0 =A0 =A0 =A0(tag_summary): Ditto. >> >> Index: doc/invoke.texi >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- doc/invoke.texi =A0 =A0 (revision 172880) >> +++ doc/invoke.texi =A0 =A0 (working copy) >> @@ -258,7 +258,7 @@ Objective-C and Objective-C++ Dialects}. >> =A0-Wparentheses =A0-Wpedantic-ms-format -Wno-pedantic-ms-format @gol >> =A0-Wpointer-arith =A0-Wno-pointer-to-int-cast @gol >> =A0-Wredundant-decls @gol >> --Wreturn-type =A0-Wsequence-point =A0-Wshadow @gol >> +-Wreturn-type =A0-Wripa-opt-mismatch =A0-Wsequence-point =A0-Wshadow @g= ol >> =A0-Wsign-compare =A0-Wsign-conversion =A0-Wstack-protector @gol >> =A0-Wstrict-aliasing -Wstrict-aliasing=3Dn @gol >> =A0-Wstrict-overflow -Wstrict-overflow=3D@var{n} @gol >> @@ -380,7 +380,9 @@ Objective-C and Objective-C++ Dialects}. >> =A0-freciprocal-math -fregmove -frename-registers -freorder-blocks @gol >> =A0-freorder-blocks-and-partition -freorder-functions @gol >> =A0-frerun-cse-after-loop -freschedule-modulo-scheduled-loops @gol >> --frounding-math -fsched2-use-superblocks -fsched-pressure @gol >> +-fripa -fripa-disallow-asm-modules -fripa-disallow-opt-mismatch @gol >> +-fripa-no-promote-always-inline-func -fripa-verbose -frounding-math @gol >> +-fsched2-use-superblocks -fsched-pressure @gol >> =A0-fsched-spec-load -fsched-spec-load-dangerous @gol >> =A0-fsched-stalled-insns-dep[=3D@var{n}] -fsched-stalled-insns[=3D@var{n= }] @gol >> =A0-fsched-group-heuristic -fsched-critical-path-heuristic @gol >> @@ -1364,8 +1366,8 @@ prefix. >> =A0@opindex no-canonical-prefixes >> =A0Never expand any symbolic links, resolve references to @samp{/../} >> =A0or @samp{/./}, or make the path absolute when generating a relative >> -prefix. =A0If neither @option{-canonical-prefixes} nor >> -@option{-canonical-prefixes} is given, GCC tries to set an appropriate >> +prefix. If neither @option{-canonical-prefixes} nor >> +@option{-nocanonical-prefixes} is given, GCC tries to set an appropriate >> =A0default by looking for a target-specific subdirectory alongside the >> =A0directory containing the compiler driver. >> >> @@ -2969,6 +2971,7 @@ Options} and @ref{Objective-C and Object >> =A0-Wpointer-sign =A0@gol >> =A0-Wreorder =A0 @gol >> =A0-Wreturn-type =A0@gol >> +-Wripa-opt-mismatch @gol >> =A0-Wsequence-point =A0@gol >> =A0-Wsign-compare @r{(only in C++)} =A0@gol >> =A0-Wstrict-aliasing =A0@gol >> @@ -3395,6 +3398,16 @@ exceptions are @samp{main} and functions >> >> =A0This warning is enabled by @option{-Wall}. >> >> +@item -Wripa-opt-mismatch >> +@opindex Wripa-opt-mismatch >> +@opindex Wno-ripa-opt-mismatch >> +When doing an FDO build with @option{-fprofile-use} and @option{-fripa}, >> +warn if importing an axuiliary module that was built with a different >> +GCC command line during the profile-generate phase than the primary >> +module. >> + >> +This warning is enabled by @option{-Wall}. >> + >> =A0@item -Wswitch >> =A0@opindex Wswitch >> =A0@opindex Wno-switch >> @@ -4493,6 +4506,12 @@ Suppress warnings from casts to pointer >> =A0different size. In C++, casting to a pointer type of smaller size is >> =A0an error. @option{Wint-to-pointer-cast} is enabled by default. >> >> +@item max-lipo-mem >> +When importing auxiliary modules during profile-use, check current >> +memory consumption after parsing each auxiliary module. If it exceeds >> +this limit (specified in kb), don't import any more auxiliary modules. >> +Specifying a value of 0 means don't enforce this limit. This parameter >> +is only useful when using @option{-fprofile-use} and @option{-fripa}. >> >> =A0@item -Wno-pointer-to-int-cast @r{(C and Objective-C only)} >> =A0@opindex Wno-pointer-to-int-cast >> @@ -7864,6 +7883,40 @@ code. >> >> =A0If @var{path} is specified, GCC will look at the @var{path} to find >> =A0the profile feedback data files. See @option{-fprofile-dir}. >> + >> +@item -fripa >> +@opindex fripa >> +Perform dynamic inter-procedural analysis. This is used in conjunction = with >> +the @option{-fprofile-generate} and @option{-fprofile-use} options. >> +During the @option{-fprofile-generate} phase, this flag turns on some a= dditional >> +instrumentation code that enables dynamic call-graph analysis. >> +During the @option{-fprofile-use} phase, this flag enables cross-module >> +optimizations such as inlining. >> + >> +@item -fripa-disallow-asm-modules >> +@opindex fripa-disallow-asm-modules >> +During profile-gen, if this flag is enabled, and the module has asm sta= tements, >> +arrange so that a bit recording this information will be set in the pro= file >> +feedback data file. >> +During profile-use, if this flag is enabled, and the same bit in auxili= ary >> +module's profile feedback data is set, don't import this auxiliary modu= le. >> +If this is the primary module, don't export it. >> + >> +@item -fripa-disallow-opt-mismatch >> +@opindex fripa-disallow-opt-mismatch >> +Don't import an auxiliary module, if the GCC command line options used = for this >> +auxiliary module during the profile-generate stage were different from = those used >> +for the primary module. Note that any mismatches in warning-related opt= ions are >> +ignored for this comparison. >> + >> +@item -fripa-no-promote-always-inline-func >> +@opindex fripa-no-promote-always-inline-func >> +Do not promote static functions with always inline attribute in LIPO co= mpilation. >> + >> +@item -fripa-verbose >> +@opindex fripa-verbose >> +Enable printing of verbose information about dynamic inter-procedural o= ptimizations. >> +This is used in conjunction with the @option{-fripa}. >> =A0@end table >> >> =A0The following options control compiler behavior regarding floating >> @@ -9954,6 +10007,12 @@ given to GCC, substitutes @code{Y}; else >> =A0be as many clauses as you need. =A0This may be combined with @code{.}, >> =A0@code{,}, @code{!}, @code{|}, and @code{*} as needed. >> >> +@item max-lipo-mem >> +When importing auxiliary modules during profile-use, check current >> +memory consumption after parsing each auxiliary module. If it exceeds >> +this limit (specified in kb), don't import any more auxiliary modules. >> +Specifying a value of 0 means don't enforce this limit. This parameter >> +is only useful when using @option{-fprofile-use} and @option{-fripa}. >> >> =A0@end table >> >> Index: cgraphbuild.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- cgraphbuild.c =A0 =A0 =A0 (revision 172880) >> +++ cgraphbuild.c =A0 =A0 =A0 (working copy) >> @@ -30,9 +30,13 @@ along with GCC; see the file COPYING3. >> =A0#include "cgraph.h" >> =A0#include "intl.h" >> =A0#include "gimple.h" >> +#include "toplev.h" >> +#include "gcov-io.h" >> +#include "coverage.h" >> =A0#include "tree-pass.h" >> =A0#include "ipa-utils.h" >> =A0#include "except.h" >> +#include "l-ipo.h" >> >> =A0/* Context of record_reference. =A0*/ >> =A0struct record_reference_ctx >> @@ -236,6 +240,140 @@ compute_call_stmt_bb_frequency (tree dec >> =A0 return freq; >> =A0} >> >> + >> +bool cgraph_pre_profiling_inlining_done =3D false; >> + >> +/* Return true if E is a fake indirect call edge. =A0*/ >> + >> +bool >> +cgraph_is_fake_indirect_call_edge (struct cgraph_edge *e) >> +{ >> + =A0return !e->call_stmt; >> +} >> + >> + >> +/* Add fake cgraph edges from NODE to its indirect call callees >> + =A0 using profile data. =A0*/ >> + >> +static void >> +add_fake_indirect_call_edges (struct cgraph_node *node) >> +{ >> + =A0unsigned n_counts, i; >> + =A0gcov_type *ic_counts; >> + >> + =A0/* Enable this only for LIPO for now. =A0*/ >> + =A0if (!L_IPO_COMP_MODE) >> + =A0 =A0return; >> + >> + =A0if (cgraph_pre_profiling_inlining_done) >> + =A0 =A0return; >> + >> + =A0ic_counts >> + =A0 =A0 =A0=3D get_coverage_counts_no_warn (DECL_STRUCT_FUNCTION (node= ->decl), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 GCOV_COUNTER_ICALL_TOPNV, &n_counts); >> + >> + =A0if (!ic_counts) >> + =A0 =A0return; >> + >> + =A0gcc_assert ((n_counts % GCOV_ICALL_TOPN_NCOUNTS) =3D=3D 0); >> + >> +/* After the early_inline_1 before value profile transformation, >> + =A0 functions that are indirect call targets may have their bodies >> + =A0 removed (extern inline functions or functions from aux modules, >> + =A0 functions in comdat etc) if all direct callsites are inlined. This >> + =A0 will lead to missing inline opportunities after profile based >> + =A0 indirect call promotion. The solution is to add fake edges to >> + =A0 indirect call targets. Note that such edges are not associated >> + =A0 with actual indirect call sites because it is not possible to >> + =A0 reliably match pre-early-inline indirect callsites with indirect >> + =A0 call profile counters which are from post-early inline function bo= dy. =A0*/ >> + >> + =A0for (i =3D 0; i < n_counts; >> + =A0 =A0 =A0 i +=3D GCOV_ICALL_TOPN_NCOUNTS, ic_counts +=3D GCOV_ICALL_= TOPN_NCOUNTS) >> + =A0 =A0{ >> + =A0 =A0 =A0gcov_type val1, val2, count1, count2; >> + =A0 =A0 =A0struct cgraph_node *direct_call1 =3D 0, *direct_call2 =3D 0; >> + >> + =A0 =A0 =A0val1 =3D ic_counts[1]; >> + =A0 =A0 =A0count1 =3D ic_counts[2]; >> + =A0 =A0 =A0val2 =3D ic_counts[3]; >> + =A0 =A0 =A0count2 =3D ic_counts[4]; >> + >> + =A0 =A0 =A0if (val1 =3D=3D 0 || count1 =3D=3D 0) >> + =A0 =A0 =A0 =A0continue; >> + >> + =A0 =A0 =A0direct_call1 =3D find_func_by_global_id (val1); >> + =A0 =A0 =A0if (direct_call1) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0tree decl =3D direct_call1->decl; >> + =A0 =A0 =A0 =A0 =A0cgraph_create_edge (node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cgraph_node (d= ecl), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0count1, 0, = 0); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0if (val2 =3D=3D 0 || count2 =3D=3D 0) >> + =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0direct_call2 =3D find_func_by_global_id (val2); >> + =A0 =A0 =A0if (direct_call2) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0tree decl =3D direct_call2->decl; >> + =A0 =A0 =A0 =A0 =A0cgraph_create_edge (node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 cgraph_node (d= ecl), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0NULL, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0count2, 0, = 0); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> + >> + >> +/* This can be implemented as an IPA pass that must be first one >> + =A0 before any unreachable node elimination. */ >> + >> +void >> +cgraph_add_fake_indirect_call_edges (void) >> +{ >> + =A0struct cgraph_node *node; >> + >> + =A0/* Enable this only for LIPO for now. =A0*/ >> + =A0if (!L_IPO_COMP_MODE) >> + =A0 =A0return; >> + >> + =A0for (node =3D cgraph_nodes; node; node =3D node->next) >> + =A0 =A0{ >> + =A0 =A0 =A0if (node->analyzed && (node->needed || node->reachable)) >> + =A0 =A0 =A0 =A0add_fake_indirect_call_edges (node); >> + =A0 =A0} >> +} >> + >> +/* Remove zero count fake edges added for the purpose of ensuring >> + =A0 the right processing order. =A0This should be called after all >> + =A0 small ipa passes. =A0*/ >> +void >> +cgraph_remove_zero_count_fake_edges (void) >> +{ >> + =A0struct cgraph_node *node; >> + >> + =A0/* Enable this only for LIPO for now. =A0*/ >> + =A0if (!L_IPO_COMP_MODE) >> + =A0 =A0return; >> + >> + =A0for (node =3D cgraph_nodes; node; node =3D node->next) >> + =A0 =A0{ >> + =A0 =A0 =A0if (node->analyzed && (node->needed || node->reachable)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0struct cgraph_edge *e, *f; >> + =A0 =A0 =A0 =A0 for (e =3D node->callees; e; e =3D f) >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 f =3D e->next_callee; >> + =A0 =A0 =A0 =A0 =A0 =A0 if (!e->call_stmt && !e->count && !e->loop_nest >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && !e->frequency) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cgraph_remove_edge (e); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 } >> + =A0 =A0} >> +} >> + >> =A0/* Mark address taken in STMT. =A0*/ >> >> =A0static bool >> @@ -390,6 +528,7 @@ build_cgraph_edges (void) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 mark_load, mark_store, mark_address); >> =A0 =A0} >> >> + >> =A0 /* Look for initializers of constant variables and private statics. = =A0*/ >> =A0 FOR_EACH_LOCAL_DECL (cfun, ix, decl) >> =A0 =A0 if (TREE_CODE (decl) =3D=3D VAR_DECL >> @@ -466,9 +605,24 @@ rebuild_cgraph_edges (void) >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bb); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0decl =3D gimple_call_fndecl (stmt); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (decl) >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 cgraph_create_edge (node, cgraph_node (dec= l), stmt, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bb= ->count, freq, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bb= ->loop_depth); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct cgraph_node *callee; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* In LIPO mode, before tree_profiling= , the call graph edge >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0needs to be built with the orig= inal target node to make >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sure consistent early inline de= cisions between profile generate >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0and profile use. After tree-pro= filing, the target needs to be >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0set to the resolved node so tha= t ipa-inline sees the definitions. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (L_IPO_COMP_MODE && cgraph_pre_prof= iling_inlining_done) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 callee =3D cgraph_lipo_get_resolve= d_node (decl); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 callee =3D cgraph_node (decl); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cgraph_create_edge (node, callee, s= tmt, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0bb->count, freq, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0bb->loop_depth); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (L_IPO_COMP_MODE && cgraph_pre_p= rofiling_inlining_done >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 && decl !=3D callee->decl) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gimple_call_set_fndecl (stmt, call= ee->decl); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cgraph_create_indirect_edge (node, stmt, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 gimple_call_flags (stmt), >> @@ -483,6 +637,7 @@ rebuild_cgraph_edges (void) >> =A0 =A0 =A0 =A0walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 mark_load, mark_store, mark_address); >> =A0 =A0 } >> + =A0add_fake_indirect_call_edges (node); >> =A0 record_eh_tables (node, cfun); >> =A0 gcc_assert (!node->global.inlined_to); >> >> Index: dyn-ipa.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- dyn-ipa.c =A0 (revision 0) >> +++ dyn-ipa.c =A0 (revision 0) >> @@ -0,0 +1,1476 @@ >> +/* Compile this one with gcc. =A0*/ >> +/* Copyright (C) 2009. Free Software Foundation, Inc. >> + =A0 Contributed by Xinliang David Li (davidxl@google.com) and >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Raksit Ashok =A0(raksit@google.com) >> + >> +This file is part of GCC. >> + >> +GCC is free software; you can redistribute it and/or modify it under >> +the terms of the GNU General Public License as published by the Free >> +Software Foundation; either version 3, or (at your option) any later >> +version. >> + >> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY >> +WARRANTY; without even the implied warranty of MERCHANTABILITY or >> +FITNESS FOR A PARTICULAR PURPOSE. =A0See the GNU General Public License >> +for more details. >> + >> +Under Section 7 of GPL version 3, you are granted additional >> +permissions described in the GCC Runtime Library Exception, version >> +3.1, as published by the Free Software Foundation. >> + >> +You should have received a copy of the GNU General Public License and >> +a copy of the GCC Runtime Library Exception along with this program; >> +see the files COPYING3 and COPYING.RUNTIME respectively. =A0If not, see >> +. =A0*/ >> + >> +#include "tconfig.h" >> +#include "tsystem.h" >> +#include "coretypes.h" >> +#include "tm.h" >> + >> +#if defined(inhibit_libc) >> +#define IN_LIBGCOV (-1) >> +#else >> +#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. =A0*/ >> +#include >> +#include >> +#define IN_LIBGCOV 1 >> +#if defined(L_gcov) >> +#define GCOV_LINKAGE /* nothing */ >> +#endif >> +#endif >> +#include "gcov-io.h" >> + >> +struct dyn_pointer_set; >> + >> +#define XNEWVEC(type,ne) (type *)malloc(sizeof(type) * (ne)) >> +#define XNEW(type) (type *)malloc(sizeof(type)) >> +#define XDELETEVEC(p) free(p) >> +#define XDELETE(p) free(p) >> + >> +struct dyn_cgraph_node >> +{ >> + =A0struct dyn_cgraph_edge *callees; >> + =A0struct dyn_cgraph_edge *callers; >> + =A0struct dyn_pointer_set *imported_modules; >> + >> + =A0gcov_type guid; >> + =A0gcov_type sum_in_count; >> + =A0gcov_unsigned_t visited; >> +}; >> + >> +struct dyn_cgraph_edge >> +{ >> + =A0struct dyn_cgraph_node *caller; >> + =A0struct dyn_cgraph_node *callee; >> + =A0struct dyn_cgraph_edge *next_caller; >> + =A0struct dyn_cgraph_edge *next_callee; >> + =A0gcov_type count; >> +}; >> + >> +struct dyn_module_info >> +{ >> + =A0struct dyn_pointer_set *imported_modules; >> + =A0gcov_unsigned_t max_func_ident; >> +}; >> + >> +struct dyn_cgraph >> +{ >> + =A0struct dyn_pointer_set **call_graph_nodes; >> + =A0struct gcov_info **modules; >> + =A0/* supplement module information =A0*/ >> + =A0struct dyn_module_info *sup_modules; >> + =A0const struct gcov_fn_info ***functions; >> + =A0unsigned num_modules; >> + =A0unsigned num_nodes_executed; >> +}; >> + >> +struct dyn_pointer_set >> +{ >> + =A0size_t log_slots; >> + =A0size_t n_slots; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* n_slots =3D 2^log_slo= ts */ >> + =A0size_t n_elements; >> + >> + =A0void **slots; >> + =A0unsigned (*get_key) (const void *); >> +}; >> + >> + >> +#if defined(inhibit_libc) >> +__gcov_build_callgraph (void) {} >> +#else >> + >> +void __gcov_compute_module_groups (void) ATTRIBUTE_HIDDEN; >> +void __gcov_finalize_dyn_callgraph (void) ATTRIBUTE_HIDDEN; >> +static void gcov_dump_callgraph (gcov_type); >> +static void gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node); >> +static void gcov_dump_cgraph_node (struct dyn_cgraph_node *node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0uns= igned m, unsigned f); >> +static void >> +gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned m, unsign= ed f, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gcov_type cutoff_c= ount); >> +static void >> +pointer_set_destroy (struct dyn_pointer_set *pset); >> +static void ** >> +pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key); >> +static struct dyn_pointer_set * >> +pointer_set_create (unsigned (*get_key) (const void *)); >> + >> +static struct dyn_cgraph the_dyn_call_graph; >> +static int total_zero_count =3D 0; >> +static int total_insane_count =3D 0; >> + >> +static void >> +init_dyn_cgraph_node (struct dyn_cgraph_node *node, gcov_type guid) >> +{ >> + =A0node->callees =3D 0; >> + =A0node->callers =3D 0; >> + =A0node->imported_modules =3D 0; >> + =A0node->guid =3D guid; >> + =A0node->visited =3D 0; >> +} >> + >> +/* Return (module_id - 1). FUNC_GUID is the global unique id. =A0*/ >> + >> +static inline gcov_unsigned_t >> +get_module_idx_from_func_glob_uid (gcov_type func_guid) >> +{ >> + =A0return EXTRACT_MODULE_ID_FROM_GLOBAL_ID (func_guid) - 1; >> +} >> + >> +/* Return (module_id - 1) for MODULE_INFO. =A0*/ >> + >> +static inline gcov_unsigned_t >> +get_module_idx (const struct gcov_info *module_info) >> +{ >> + =A0return module_info->mod_info->ident - 1; >> +} >> + >> +/* Return intra-module function id given function global unique id >> + =A0 FUNC_GUID. =A0*/ >> + >> +static inline gcov_unsigned_t >> +get_intra_module_func_id (gcov_type func_guid) >> +{ >> + =A0return EXTRACT_FUNC_ID_FROM_GLOBAL_ID (func_guid); >> +} >> + >> +/* Return the pointer to the dynamic call graph node for FUNC_GUID. =A0= */ >> + >> +static inline struct dyn_cgraph_node * >> +get_cgraph_node (gcov_type func_guid) >> +{ >> + =A0gcov_unsigned_t mod_id, func_id; >> + >> + =A0mod_id =3D get_module_idx_from_func_glob_uid (func_guid); >> + >> + =A0/* This is to workaround: calls in __static_initialization_and_dest= ruction >> + =A0 =A0 should not be instrumented as the module id context for the ca= llees have >> + =A0 =A0 not setup yet -- this leads to mod_id =3D=3D (unsigned) (0 - 1= ). Multithreaded >> + =A0 =A0 programs may also produce insane func_guid in the profile coun= ter. =A0*/ >> + =A0if (mod_id >=3D the_dyn_call_graph.num_modules) >> + =A0 =A0return 0; >> + >> + =A0func_id =3D get_intra_module_func_id (func_guid); >> + =A0if (func_id > the_dyn_call_graph.sup_modules[mod_id].max_func_ident) >> + =A0 =A0return 0; >> + >> + =A0return *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_nodes[mod_id], func_= id)); >> +} >> + >> +/* Return the gcov_info pointer for module with id MODULE_ID. =A0*/ >> + >> +static inline struct gcov_info * >> +get_module_info (gcov_unsigned_t module_id) >> +{ >> + =A0return the_dyn_call_graph.modules[module_id]; >> +} >> + >> +struct gcov_info *__gcov_list ATTRIBUTE_HIDDEN; >> + >> +static inline unsigned >> +cgraph_node_get_key (const void *p) >> +{ >> + =A0return get_intra_module_func_id (((const struct dyn_cgraph_node *) = p)->guid); >> +} >> + >> +/* Initialize dynamic call graph. =A0*/ >> + >> +static void >> +init_dyn_call_graph (void) >> +{ >> + =A0unsigned num_modules =3D 0; >> + =A0struct gcov_info *gi_ptr; >> + >> + =A0the_dyn_call_graph.call_graph_nodes =3D 0; >> + =A0the_dyn_call_graph.modules =3D 0; >> + =A0the_dyn_call_graph.functions =3D 0; >> + =A0the_dyn_call_graph.num_nodes_executed =3D 0; >> + >> + =A0gi_ptr =3D __gcov_list; >> + >> + =A0for (; gi_ptr; gi_ptr =3D gi_ptr->next) >> + =A0 =A0num_modules++; >> + >> + =A0the_dyn_call_graph.num_modules =3D num_modules; >> + >> + =A0the_dyn_call_graph.modules >> + =A0 =A0=3D XNEWVEC (struct gcov_info *, num_modules); >> + >> + =A0the_dyn_call_graph.sup_modules >> + =A0 =A0=3D XNEWVEC (struct dyn_module_info, num_modules); >> + =A0memset (the_dyn_call_graph.sup_modules, 0, >> + =A0 =A0 =A0 =A0 =A0num_modules * sizeof (struct dyn_module_info)); >> + >> + =A0the_dyn_call_graph.functions >> + =A0 =A0=3D XNEWVEC (const struct gcov_fn_info **, num_modules); >> + >> + =A0the_dyn_call_graph.call_graph_nodes >> + =A0 =A0=3D XNEWVEC (struct dyn_pointer_set *, num_modules); >> + >> + =A0gi_ptr =3D __gcov_list; >> + >> + =A0for (; gi_ptr; gi_ptr =3D gi_ptr->next) >> + =A0 =A0{ >> + =A0 =A0 =A0unsigned c_ix =3D 0, t_ix, j, mod_id, fi_stride, max_func_i= dent =3D 0; >> + =A0 =A0 =A0struct dyn_cgraph_node *node; >> + >> + =A0 =A0 =A0mod_id =3D get_module_idx (gi_ptr); >> + >> + =A0 =A0 =A0the_dyn_call_graph.modules[mod_id] =3D gi_ptr; >> + >> + =A0 =A0 =A0the_dyn_call_graph.functions[mod_id] >> + =A0 =A0 =A0 =A0 =A0=3D XNEWVEC (const struct gcov_fn_info *, gi_ptr->n= _functions); >> + >> + =A0 =A0 =A0for (t_ix =3D 0; t_ix < GCOV_COUNTERS; t_ix++) >> + =A0 =A0 =A0 if ((1 << t_ix) & gi_ptr->ctr_mask) >> + =A0 =A0 =A0 =A0 =A0 c_ix++; >> + >> + =A0 =A0 =A0fi_stride =3D offsetof (struct gcov_fn_info, n_ctrs) + c_ix= * sizeof (unsigned); >> + =A0 =A0 =A0if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned)) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 fi_stride +=3D __alignof__ (struct gcov_fn_info) - 1; >> + =A0 =A0 =A0 =A0 fi_stride &=3D ~(__alignof__ (struct gcov_fn_info) - 1= ); >> + =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0for (j =3D 0; j < gi_ptr->n_functions; j++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0const struct gcov_fn_info *fi_ptr =3D (const struct= gcov_fn_info *) >> + =A0 =A0 =A0 =A0 =A0 ((const char *) gi_ptr->functions + j * fi_stride); >> + =A0 =A0 =A0 =A0 =A0the_dyn_call_graph.functions[mod_id][j] =3D fi_ptr; >> + =A0 =A0 =A0 =A0 =A0if (fi_ptr->ident > max_func_ident) >> + =A0 =A0 =A0 =A0 =A0 =A0max_func_ident =3D fi_ptr->ident; >> + =A0 =A0 =A0 =A0} >> + >> + >> + =A0 =A0 =A0the_dyn_call_graph.call_graph_nodes[mod_id] >> + =A0 =A0 =A0 =3D pointer_set_create (cgraph_node_get_key); >> + >> + =A0 =A0 =A0the_dyn_call_graph.sup_modules[mod_id].max_func_ident =3D m= ax_func_ident; >> + >> + =A0 =A0 =A0for (j =3D 0; j < gi_ptr->n_functions; j++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0const struct gcov_fn_info *fi_ptr >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D the_dyn_call_graph.functions[mod_id][j]; >> + =A0 =A0 =A0 =A0 *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 (the_dyn_call_graph.call_graph_nodes[mod_id], fi_p= tr->ident)) >> + =A0 =A0 =A0 =A0 =A0 =3D node =3D XNEW (struct dyn_cgraph_node); >> + =A0 =A0 =A0 =A0 the_dyn_call_graph.call_graph_nodes[mod_id]->n_element= s++; >> + =A0 =A0 =A0 =A0 init_dyn_cgraph_node (node, GEN_FUNC_GLOBAL_ID (gi_ptr= ->mod_info->ident, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fi_ptr->ident)); >> + =A0 =A0 =A0 } >> + =A0 =A0} >> +} >> + >> +/* Free up memory allocated for dynamic call graph. =A0*/ >> + >> +void >> +__gcov_finalize_dyn_callgraph (void) >> +{ >> + =A0unsigned i; >> + =A0struct gcov_info *gi_ptr; >> + >> + =A0for (i =3D 0; i < the_dyn_call_graph.num_modules; i++) >> + =A0 =A0{ >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[i]; >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned f_ix; >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct dyn_cgraph_node *node; >> + =A0 =A0 =A0 =A0 =A0struct dyn_cgraph_edge *callees, *next_callee; >> + =A0 =A0 =A0 =A0 =A0fi_ptr =3D the_dyn_call_graph.functions[i][f_ix]; >> + =A0 =A0 =A0 =A0 =A0node =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_node= s[i], fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (node); >> + =A0 =A0 =A0 =A0 =A0callees =3D node->callees; >> + >> + =A0 =A0 =A0 =A0 =A0if (!callees) >> + =A0 =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0 =A0while (callees !=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0next_callee =3D callees->next_callee; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0XDELETE (callees); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0callees =3D next_callee; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 if (node->imported_modules) >> + =A0 =A0 =A0 =A0 =A0 pointer_set_destroy (node->imported_modules); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0if (the_dyn_call_graph.call_graph_nodes[i]) >> + =A0 =A0 =A0 =A0pointer_set_destroy (the_dyn_call_graph.call_graph_node= s[i]); >> + =A0 =A0 =A0if (the_dyn_call_graph.functions[i]) >> + =A0 =A0 =A0 =A0XDELETEVEC (the_dyn_call_graph.functions[i]); >> + =A0 =A0 =A0/* Now delete sup modules */ >> + =A0 =A0 =A0if (the_dyn_call_graph.sup_modules[i].imported_modules) >> + =A0 =A0 =A0 =A0pointer_set_destroy (the_dyn_call_graph.sup_modules[i].= imported_modules); >> + =A0 =A0} >> + =A0XDELETEVEC (the_dyn_call_graph.call_graph_nodes); >> + =A0XDELETEVEC (the_dyn_call_graph.functions); >> + =A0XDELETEVEC (the_dyn_call_graph.sup_modules); >> + =A0XDELETEVEC (the_dyn_call_graph.modules); >> +} >> + >> +/* Add outgoing edge OUT_EDGE for caller node CALLER. =A0*/ >> + >> +static void >> +gcov_add_out_edge (struct dyn_cgraph_node *caller, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct dyn_cgraph_edge *out_edge) >> +{ >> + =A0if (!caller->callees) >> + =A0 =A0caller->callees =3D out_edge; >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0out_edge->next_callee =3D caller->callees; >> + =A0 =A0 =A0caller->callees =3D out_edge; >> + =A0 =A0} >> +} >> + >> +/* Add incoming edge IN_EDGE for callee node CALLEE. =A0*/ >> + >> +static void >> +gcov_add_in_edge (struct dyn_cgraph_node *callee, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct dyn_cgraph_edge *in_edge) >> +{ >> + =A0if (!callee->callers) >> + =A0 =A0callee->callers =3D in_edge; >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0in_edge->next_caller =3D callee->callers; >> + =A0 =A0 =A0callee->callers =3D in_edge; >> + =A0 =A0} >> +} >> + >> +/* Add a call graph edge between caller CALLER and callee CALLEE. >> + =A0 The edge count is COUNT. =A0*/ >> + >> +static void >> +gcov_add_cgraph_edge (struct dyn_cgraph_node *caller, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct dyn_cgraph_node *callee, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gcov_type count) >> +{ >> + =A0struct dyn_cgraph_edge *new_edge =3D XNEW (struct dyn_cgraph_edge); >> + =A0new_edge->caller =3D caller; >> + =A0new_edge->callee =3D callee; >> + =A0new_edge->count =3D count; >> + =A0new_edge->next_caller =3D 0; >> + =A0new_edge->next_callee =3D 0; >> + >> + =A0gcov_add_out_edge (caller, new_edge); >> + =A0gcov_add_in_edge (callee, new_edge); >> +} >> + >> +/* Add call graph edges from direct calls for caller CALLER. DIR_CALL_C= OUNTERS >> + =A0 is the array of call counters. N_COUNTS is the number of counters.= =A0*/ >> + >> +static void >> +gcov_build_callgraph_dc_fn (struct dyn_cgraph_node *caller, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_type *dir_= call_counters, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned n_coun= ts) >> +{ >> + =A0unsigned i; >> + >> + =A0for (i =3D 0; i < n_counts; i +=3D 2) >> + =A0 =A0{ >> + =A0 =A0 =A0struct dyn_cgraph_node *callee; >> + =A0 =A0 =A0gcov_type count; >> + =A0 =A0 =A0gcov_type callee_guid =3D dir_call_counters[i]; >> + >> + =A0 =A0 =A0count =3D dir_call_counters[i + 1]; >> + =A0 =A0 =A0if (count =3D=3D 0) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0total_zero_count++; >> + =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0callee =3D get_cgraph_node (callee_guid); >> + =A0 =A0 =A0if (!callee) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0total_insane_count++; >> + =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0gcov_add_cgraph_edge (caller, callee, count); >> + =A0 =A0} >> +} >> + >> +/* Add call graph edges from indirect calls for caller CALLER. ICALL_CO= UNTERS >> + =A0 is the array of icall counters. N_COUNTS is the number of counters= . =A0*/ >> + >> +static void >> +gcov_build_callgraph_ic_fn (struct dyn_cgraph_node *caller, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_type *ical= l_counters, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned n_coun= ts) >> +{ >> + =A0unsigned i, j; >> + >> + =A0for (i =3D 0; i < n_counts; i +=3D GCOV_ICALL_TOPN_NCOUNTS) >> + =A0 =A0{ >> + =A0 =A0 =A0gcov_type *value_array =3D &icall_counters[i + 1]; >> + =A0 =A0 =A0for (j =3D 0; j < GCOV_ICALL_TOPN_NCOUNTS - 1; j +=3D 2) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0struct dyn_cgraph_node *callee; >> + =A0 =A0 =A0 =A0 =A0gcov_type count; >> + =A0 =A0 =A0 =A0 =A0gcov_type callee_guid =3D value_array[j]; >> + >> + =A0 =A0 =A0 =A0 =A0count =3D value_array[j + 1]; >> + =A0 =A0 =A0 =A0 /* Do not update zero count edge count >> + =A0 =A0 =A0 =A0 =A0* as it means there is no target in this entry. =A0= */ >> + =A0 =A0 =A0 =A0 =A0if (count =3D=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0 =A0callee =3D get_cgraph_node (callee_guid); >> + =A0 =A0 =A0 =A0 =A0if (!callee) >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0total_insane_count++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0gcov_add_cgraph_edge (caller, callee, count); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> + >> +/* Build the dynamic call graph. =A0*/ >> + >> +static void >> +gcov_build_callgraph (void) >> +{ >> + =A0struct gcov_info *gi_ptr; >> + =A0unsigned t_ix, m_ix; >> + >> + =A0init_dyn_call_graph (); >> + >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned c_ix, f_ix, n_counts, dp_cix =3D 0, ip_cix =3D 0; >> + =A0 =A0 =A0gcov_type *dcall_profile_values, *icall_profile_values; >> + =A0 =A0 =A0gcov_type *arcs_values =3D 0; unsigned arcs_cix; >> + >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[m_ix]; >> + >> + =A0 =A0 =A0dcall_profile_values =3D 0; >> + =A0 =A0 =A0icall_profile_values =3D 0; >> + =A0 =A0 =A0c_ix =3D 0; >> + =A0 =A0 =A0for (t_ix =3D 0; t_ix < GCOV_COUNTERS; t_ix++) >> + =A0 =A0 =A0 if ((1 << t_ix) & gi_ptr->ctr_mask) >> + =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 if (t_ix =3D=3D GCOV_COUNTER_DIRECT_CALL) >> + =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dcall_profile_values =3D gi_ptr->counts[c_= ix].values; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dp_cix =3D c_ix; >> + =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 if (t_ix =3D=3D GCOV_COUNTER_ICALL_TOPNV) >> + =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 icall_profile_values =3D gi_ptr->counts[c_= ix].values; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ip_cix =3D c_ix; >> + =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 if (t_ix =3D=3D GCOV_COUNTER_ARCS) >> + =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 arcs_values =3D gi_ptr->counts[c_ix].value= s; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 arcs_cix =3D c_ix; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 c_ix++; >> + =A0 =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0if (dcall_profile_values =3D=3D 0 && icall_profile_values = =3D=3D 0) >> + =A0 =A0 =A0 =A0continue; >> + >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0struct dyn_cgraph_node *caller; >> + =A0 =A0 =A0 =A0 =A0fi_ptr =3D the_dyn_call_graph.functions[m_ix][f_ix]; >> + =A0 =A0 =A0 =A0 =A0caller =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_= nodes[m_ix], >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (caller); >> + =A0 =A0 =A0 =A0 =A0if (dcall_profile_values) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned offset; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0n_counts =3D fi_ptr->n_ctrs[dp_cix]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0offset =3D fi_ptr->dc_offset; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_build_callgraph_dc_fn (caller, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0dcall_profile_values + offset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0n_counts); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0if (icall_profile_values) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0n_counts =3D fi_ptr->n_ctrs[ip_cix]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_build_callgraph_ic_fn (caller, icall_p= rofile_values, n_counts); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0icall_profile_values +=3D n_counts; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0if (arcs_values && 0) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_type total_arc_count =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned arc; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0n_counts =3D fi_ptr->n_ctrs[arcs_cix]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0for (arc =3D 0; arc < n_counts; arc++) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0total_arc_count +=3D arcs_values[arc]; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (total_arc_count !=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0the_dyn_call_graph.num_nodes_executed++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0arcs_values +=3D n_counts; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> +} >> + >> +static inline size_t >> +hash1 (unsigned p, unsigned long max, unsigned long logmax) >> +{ >> + =A0const unsigned long long A =3D 0x9e3779b97f4a7c16ull; >> + =A0const unsigned long long shift =3D 64 - logmax; >> + >> + =A0return ((A * (unsigned long) p) >> shift) & (max - 1); >> +} >> + >> +/* Allocate an empty imported-modules set. =A0*/ >> + >> +static struct dyn_pointer_set * >> +pointer_set_create (unsigned (*get_key) (const void *)) >> +{ >> + =A0struct dyn_pointer_set *result =3D XNEW (struct dyn_pointer_set); >> + >> + =A0result->n_elements =3D 0; >> + =A0result->log_slots =3D 8; >> + =A0result->n_slots =3D (size_t) 1 << result->log_slots; >> + >> + =A0result->slots =3D XNEWVEC (void *, result->n_slots); >> + =A0memset (result->slots, 0, sizeof (void *) * result->n_slots); >> + =A0result->get_key =3D get_key; >> + >> + =A0return result; >> +} >> + >> +/* Reclaim all memory associated with PSET. =A0*/ >> + >> +static void >> +pointer_set_destroy (struct dyn_pointer_set *pset) >> +{ >> + =A0size_t i; >> + =A0for (i =3D 0; i < pset->n_slots; i++) >> + =A0 =A0if (pset->slots[i]) >> + =A0 =A0 =A0XDELETE (pset->slots[i]); >> + =A0XDELETEVEC (pset->slots); >> + =A0XDELETE (pset); >> +} >> + >> +/* Subroutine of pointer_set_find_or_insert. =A0Return the insertion sl= ot for KEY >> + =A0 into an empty element of SLOTS, an array of length N_SLOTS. =A0*/ >> +static inline size_t >> +insert_aux (unsigned key, void **slots, >> + =A0 =A0 =A0 =A0 =A0 size_t n_slots, size_t log_slots, >> + =A0 =A0 =A0 =A0 =A0 unsigned (*get_key) (const void *)) >> +{ >> + =A0size_t n =3D hash1 (key, n_slots, log_slots); >> + =A0while (1) >> + =A0 =A0{ >> + =A0 =A0 =A0if (slots[n] =3D=3D 0 || get_key (slots[n]) =3D=3D key) >> + =A0 =A0 =A0 return n; >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 ++n; >> + =A0 =A0 =A0 =A0 if (n =3D=3D n_slots) >> + =A0 =A0 =A0 =A0 =A0 n =3D 0; >> + =A0 =A0 =A0 } >> + =A0 =A0} >> +} >> + >> +/* Find slot for KEY. KEY must be nonnull. =A0*/ >> + >> +static void ** >> +pointer_set_find_or_insert (struct dyn_pointer_set *pset, unsigned key) >> +{ >> + =A0size_t n; >> + >> + =A0/* For simplicity, expand the set even if KEY is already there. =A0= This can be >> + =A0 =A0 superfluous but can happen at most once. =A0*/ >> + =A0if (pset->n_elements > pset->n_slots / 4) >> + =A0 =A0{ >> + =A0 =A0 =A0size_t new_log_slots =3D pset->log_slots + 1; >> + =A0 =A0 =A0size_t new_n_slots =3D pset->n_slots * 2; >> + =A0 =A0 =A0void **new_slots =3D XNEWVEC (void *, new_n_slots); >> + =A0 =A0 =A0memset (new_slots, 0, sizeof (void *) * new_n_slots); >> + =A0 =A0 =A0size_t i; >> + >> + =A0 =A0 =A0for (i =3D 0; i < pset->n_slots; ++i) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 void *value =3D pset->slots[i]; >> + =A0 =A0 =A0 =A0 if (!value) >> + =A0 =A0 =A0 =A0 =A0 continue; >> + =A0 =A0 =A0 =A0 n =3D insert_aux (pset->get_key (value), new_slots, ne= w_n_slots, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 new_log_slots, pset->g= et_key); >> + =A0 =A0 =A0 =A0 new_slots[n] =3D value; >> + =A0 =A0 =A0 } >> + >> + =A0 =A0 =A0XDELETEVEC (pset->slots); >> + =A0 =A0 =A0pset->n_slots =3D new_n_slots; >> + =A0 =A0 =A0pset->log_slots =3D new_log_slots; >> + =A0 =A0 =A0pset->slots =3D new_slots; >> + =A0 =A0} >> + >> + =A0n =3D insert_aux (key, pset->slots, pset->n_slots, pset->log_slots, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pset->get_key); >> + =A0return &pset->slots[n]; >> +} >> + >> +/* Pass each pointer in PSET to the function in FN, together with the f= ixed >> + =A0 parameters DATA1, DATA2, DATA3. =A0If FN returns false, the iterat= ion stops. =A0*/ >> + >> +static void >> +pointer_set_traverse (const struct dyn_pointer_set *pset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int (*fn) (const void *, vo= id *, void *, void *), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data1, void *data2, void= *data3) >> +{ >> + =A0size_t i; >> + =A0for (i =3D 0; i < pset->n_slots; ++i) >> + =A0 =A0if (pset->slots[i] && !fn (pset->slots[i], data1, data2, data3)) >> + =A0 =A0 =A0break; >> +} >> + >> +static int >> +imp_mod_set_insert (struct dyn_pointer_set *p, const struct gcov_info *= imp_mod, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 double wt) >> +{ >> + =A0struct dyn_imp_mod **m =3D (struct dyn_imp_mod **) >> + =A0 =A0pointer_set_find_or_insert (p, imp_mod->mod_info->ident); >> + =A0if (*m) >> + =A0 =A0{ >> + =A0 =A0 =A0(*m)->weight +=3D wt; >> + =A0 =A0 =A0return 1; >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0*m =3D XNEW (struct dyn_imp_mod); >> + =A0 =A0 =A0(*m)->imp_mod =3D imp_mod; >> + =A0 =A0 =A0(*m)->weight =3D wt; >> + =A0 =A0 =A0p->n_elements++; >> + =A0 =A0 =A0return 0; >> + =A0 =A0} >> +} >> + >> +/* Callback function to propagate import module (VALUE) from callee to >> + =A0 caller's imported-module-set (DATA1). >> + =A0 The weight is scaled by the scaling-factor (DATA2) before propagat= ion, >> + =A0 and accumulated into DATA3. =A0*/ >> +static int >> +gcov_propagate_imp_modules (const void *value, void *data1, void *data2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data3) >> +{ >> + =A0const struct dyn_imp_mod *m =3D (const struct dyn_imp_mod *) value; >> + =A0struct dyn_pointer_set *receiving_set =3D (struct dyn_pointer_set *= ) data1; >> + =A0double *scale =3D (double *) data2; >> + =A0double *sum =3D (double *) data3; >> + =A0double wt =3D m->weight; >> + =A0if (scale) >> + =A0 =A0wt *=3D *scale; >> + =A0if (sum) >> + =A0 =A0(*sum) +=3D wt; >> + =A0imp_mod_set_insert (receiving_set, m->imp_mod, wt); >> + =A0return 1; >> +} >> + >> +static int >> +sort_by_count (const void *pa, const void *pb) >> +{ >> + =A0const struct dyn_cgraph_edge *edge_a =3D *(struct dyn_cgraph_edge *= const *)pa; >> + =A0const struct dyn_cgraph_edge *edge_b =3D *(struct dyn_cgraph_edge *= const *)pb; >> + >> + =A0/* This can overvlow. =A0*/ >> + =A0/* return edge_b->count - edge_a->count; =A0*/ >> + =A0if (edge_b->count > edge_a->count) >> + =A0 =A0return 1; >> + =A0else if (edge_b->count =3D=3D edge_a->count) >> + =A0 =A0return 0; >> + =A0else >> + =A0 =A0return -1; >> +} >> + >> +/* Compute the hot callgraph edge threhold. =A0*/ >> + >> +static gcov_type >> +gcov_compute_cutoff_count (void) >> +{ >> + =A0unsigned m_ix, capacity, i; >> + =A0unsigned num_edges =3D 0; >> + =A0gcov_type cutoff_count; >> + =A0double total, cum, cum_cutoff; >> + =A0struct dyn_cgraph_edge **edges; >> + =A0struct gcov_info *gi_ptr; >> + =A0char *cutoff_str; >> + =A0char *num_perc_str; >> + =A0unsigned cutoff_perc; >> + =A0unsigned num_perc; >> + =A0int do_dump; >> + >> + =A0capacity =3D 100; >> + =A0/* allocate an edge array */ >> + =A0edges =3D XNEWVEC (struct dyn_cgraph_edge*, capacity); >> + =A0/* First count the number of edges. =A0*/ >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned f_ix; >> + >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[m_ix]; >> + >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct dyn_cgraph_node *node; >> + =A0 =A0 =A0 =A0 =A0struct dyn_cgraph_edge *callees; >> + >> + =A0 =A0 =A0 =A0 fi_ptr =3D the_dyn_call_graph.functions[m_ix][f_ix]; >> + >> + =A0 =A0 =A0 =A0 node =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_node= s[m_ix], fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (node); >> + >> + =A0 =A0 =A0 =A0 =A0callees =3D node->callees; >> + =A0 =A0 =A0 =A0 =A0while (callees !=3D 0) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0num_edges++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0if (num_edges < capacity) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edges[num_edges - 1] =3D callees; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0capacity =3D capacity + (capacity >= > 1); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edges =3D (struct dyn_cgraph_edge *= *)realloc (edges, sizeof (void*) * capacity); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edges[num_edges - 1] =3D callees; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0callees =3D callees->next_callee; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + >> + =A0/* Now sort */ >> + qsort (edges, num_edges, sizeof (void *), sort_by_count); >> +#define CUM_CUTOFF_PERCENT 80 >> +#define MIN_NUM_EDGE_PERCENT 0 >> + =A0cutoff_str =3D getenv ("GCOV_DYN_CGRAPH_CUTOFF"); >> + =A0if (cutoff_str && strlen (cutoff_str)) >> + =A0 =A0{ >> + =A0 =A0 =A0if ((num_perc_str =3D strchr (cutoff_str, ':'))) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0*num_perc_str =3D '\0'; >> + =A0 =A0 =A0 =A0 =A0num_perc_str++; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0cutoff_perc =3D atoi (cutoff_str); >> + =A0 =A0 =A0if (num_perc_str) >> + =A0 =A0 =A0 =A0num_perc =3D atoi (num_perc_str); >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0num_perc =3D MIN_NUM_EDGE_PERCENT; >> + =A0 =A0} >> + =A0else >> + =A0 =A0{ >> + =A0 =A0 =A0cutoff_perc =3D CUM_CUTOFF_PERCENT; >> + =A0 =A0 =A0num_perc =3D MIN_NUM_EDGE_PERCENT; >> + =A0 =A0} >> + >> + =A0total =3D 0; >> + =A0cum =3D 0; >> + =A0for (i =3D 0; i < num_edges; i++) >> + =A0 =A0total +=3D edges[i]->count; >> + >> + =A0cum_cutoff =3D (total * cutoff_perc)/100; >> + =A0do_dump =3D (getenv ("GCOV_DYN_CGRAPH_DUMP") !=3D 0); >> + =A0for (i =3D 0; i < num_edges; i++) >> + =A0 =A0{ >> + =A0 =A0 =A0cum +=3D edges[i]->count; >> + =A0 =A0 =A0if (do_dump) >> + =A0 =A0 =A0 =A0fprintf (stderr, "// edge[%d] count =3D %.0f [%llx --> = %llx]\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i, (double) edges[i]->count, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) edges[i]->caller->guid, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) edges[i]->callee->guid); >> + =A0 =A0 =A0if (cum >=3D cum_cutoff && (i * 100 >=3D num_edges * num_pe= rc)) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0cutoff_count =3D edges[i]->count; >> + =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0if (do_dump) >> + =A0 =A0fprintf (stderr, "// total =3D %.0f cum =3D %.0f cum/total =3D = %.0f%%" >> + =A0 =A0 =A0 =A0 =A0 =A0 " cutoff_count =3D %lld [total edges: %d hot e= dges: %d perc: %d%%]\n" >> + =A0 =A0 =A0 =A0 =A0 =A0" total_zero_count_edges =3D %d total_insane_co= unt_edgess =3D %d\n" >> + =A0 =A0 =A0 =A0 =A0 =A0 " total_nodes_executed =3D %d\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 total, cum, (cum * 100)/total, (long long) cut= off_count, >> + =A0 =A0 =A0 =A0 =A0 =A0 num_edges, i, (i * 100)/num_edges, total_zero_= count, >> + =A0 =A0 =A0 =A0 =A0 =A0 total_insane_count, the_dyn_call_graph.num_nod= es_executed); >> + >> + =A0XDELETEVEC (edges); >> + =A0return cutoff_count; >> +} >> + >> +static inline unsigned >> +imp_mod_get_key (const void *p) >> +{ >> + =A0return ((const struct dyn_imp_mod *) p)->imp_mod->mod_info->ident; >> +} >> + >> +/* Return the imported module set for NODE. =A0*/ >> + >> +static struct dyn_pointer_set * >> +gcov_get_imp_module_set (struct dyn_cgraph_node *node) >> +{ >> + =A0if (!node->imported_modules) >> + =A0 =A0node->imported_modules =3D pointer_set_create (imp_mod_get_key); >> + >> + =A0return node->imported_modules; >> +} >> + >> +/* Return the imported module set for MODULE MI. =A0*/ >> + >> +static struct dyn_pointer_set * >> +gcov_get_module_imp_module_set (struct dyn_module_info *mi) >> +{ >> + =A0if (!mi->imported_modules) >> + =A0 =A0mi->imported_modules =3D pointer_set_create (imp_mod_get_key); >> + >> + =A0return mi->imported_modules; >> +} >> + >> +/* Callback function to mark if a module needs to be exported. =A0*/ >> + >> +static int >> +gcov_mark_export_modules (const void *value, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data1 ATTRIBUTE_= UNUSED, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data2 ATTRIBUTE_= UNUSED, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data3 ATTRIBUTE_= UNUSED) >> +{ >> + =A0const struct gcov_info *module_info >> + =A0 =A0=3D ((const struct dyn_imp_mod *) value)->imp_mod; >> + >> + =A0module_info->mod_info->is_exported =3D 1; >> + =A0return 1; >> +} >> + >> +struct gcov_import_mod_array >> +{ >> + =A0const struct dyn_imp_mod **imported_modules; >> + =A0struct gcov_info *importing_module; >> + =A0unsigned len; >> +}; >> + >> +/* Callback function to compute pointer set size. =A0*/ >> + >> +static int >> +gcov_compute_mset_size (const void *value ATTRIBUTE_UNUSED, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *data1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data2 ATTRIBUTE_UNUS= ED, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 void *data3 ATTRIBUTE_UNUS= ED) >> +{ >> + =A0unsigned *len =3D (unsigned *) data1; >> + =A0(*len)++; >> + =A0return 1; >> +} >> + >> +/* Callback function to collect imported modules. =A0*/ >> + >> +static int >> +gcov_collect_imported_modules (const void *value, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *data1, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *data2= ATTRIBUTE_UNUSED, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0void *data3= ATTRIBUTE_UNUSED) >> +{ >> + =A0struct gcov_import_mod_array *out_array; >> + =A0const struct dyn_imp_mod *m >> + =A0 =A0=3D (const struct dyn_imp_mod *) value; >> + >> + =A0out_array =3D (struct gcov_import_mod_array *) data1; >> + >> + =A0if (m->imp_mod !=3D out_array->importing_module) >> + =A0 =A0out_array->imported_modules[out_array->len++] =3D m; >> + >> + =A0return 1; >> +} >> + >> +/* Comparator for sorting imported modules using weights. =A0*/ >> + >> +static int >> +sort_by_module_wt (const void *pa, const void *pb) >> +{ >> + =A0const struct dyn_imp_mod *m_a =3D *((const struct dyn_imp_mod * con= st *) pa); >> + =A0const struct dyn_imp_mod *m_b =3D *((const struct dyn_imp_mod * con= st *) pb); >> + >> + =A0/* We want to sort in descending order of weights. =A0*/ >> + =A0if (m_a->weight < m_b->weight) >> + =A0 =A0return +1; >> + =A0if (m_a->weight > m_b->weight) >> + =A0 =A0return -1; >> + =A0return get_module_idx (m_a->imp_mod) - get_module_idx (m_b->imp_mod= ); >> +} >> + >> +/* Return a dynamic array of imported modules that is sorted for >> + =A0 the importing module MOD_INFO. The length of the array is returned >> + =A0 in *LEN. =A0*/ >> + >> +const struct dyn_imp_mod ** >> +gcov_get_sorted_import_module_array (struct gcov_info *mod_info, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 unsigned *len) >> +{ >> + =A0unsigned mod_id; >> + =A0struct dyn_module_info *sup_mod_info; >> + =A0unsigned array_len =3D 0; >> + =A0struct gcov_import_mod_array imp_array; >> + >> + =A0mod_id =3D get_module_idx (mod_info); >> + =A0sup_mod_info =3D &the_dyn_call_graph.sup_modules[mod_id]; >> + >> + =A0if (sup_mod_info->imported_modules =3D=3D 0) >> + =A0 =A0return 0; >> + >> + =A0pointer_set_traverse (sup_mod_info->imported_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_compute_mset_size,= &array_len, 0, 0); >> + =A0imp_array.imported_modules =3D XNEWVEC (const struct dyn_imp_mod *,= array_len); >> + =A0imp_array.len =3D 0; >> + =A0imp_array.importing_module =3D mod_info; >> + =A0pointer_set_traverse (sup_mod_info->imported_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_collect_imported_m= odules, &imp_array, 0, 0); >> + =A0*len =3D imp_array.len; >> + =A0qsort (imp_array.imported_modules, imp_array.len, >> + =A0 =A0 =A0 =A0 sizeof (void *), sort_by_module_wt); >> + =A0return imp_array.imported_modules; >> +} >> + >> +/* Compute modules that are needed for NODE (for cross module inlining). >> + =A0 CUTTOFF_COUNT is the call graph edge count cutoff value. >> + =A0 IMPORT_SCALE is the scaling-factor (percent) by which to scale the >> + =A0 weights of imported modules of a callee before propagating them to >> + =A0 the caller, if the callee and caller are in different modules. >> + >> + =A0 Each imported module is assigned a weight that corresponds to the >> + =A0 expected benefit due to cross-module inlining. When the imported m= odules >> + =A0 are written out, they are sorted with highest weight first. >> + >> + =A0 The following example illustrates how the weight is computed: >> + >> + =A0 Suppose we are processing call-graph node A. It calls function B 5= 0 times, >> + =A0 which calls function C 1000 times, and function E 800 times. Lets = say B has >> + =A0 another in-edge from function D, with edge-count of 50. Say all the >> + =A0 functions are in separate modules (modules a, b, c, d, e, respecti= vely): >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0D >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| 50 >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| >> + =A0 =A0 =A0 50 =A0 =A0 v =A0 =A0 1000 >> + =A0A --------> B ----------> C >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| 800 >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0| >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0v >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0E >> + >> + =A0Nodes are processed in depth-first order, so when processing A, we = first >> + =A0process B. For node B, we are going to add module c to the imported= -module >> + =A0set, with weight 1000 (edge-count), and module e with weight 800. >> + =A0Coming back to A, we are going to add the imported-module-set of B = to A, >> + =A0after doing some scaling. >> + =A0The first scaling factor comes from the fact that A calls B 50 time= s, but B >> + =A0has in-edge-count total of 100. So this scaling factor is 50/100 = =3D 0.5 >> + =A0The second scaling factor is that since B is in a different module = than A, >> + =A0we want to slightly downgrade imported modules of B, before adding = to the >> + =A0imported-modules set of A. This scaling factor has a default value = of 50% >> + =A0(can be set via env variable GCOV_DYN_IMPORT_SCALE). >> + =A0So we end up adding modules c and e to the imported-set of A, with = weights >> + =A00.5*0.5*1000=3D250 and 0.5*0.5*800=3D200, respectively. >> + >> + =A0Next, we have to add module b itself to A. The weight is computed a= s the >> + =A0edge-count plus the sum of scaled-weights of all modules in the >> + =A0imported-module set of B, i.e., 50 + 250 + 200 =3D 500. >> + >> + =A0In computing the weight of module b, we add the sum of scaled-weigh= ts of >> + =A0imported modules of b, because it doesn't make sense to import c, e= in >> + =A0module a, until module b is imported. =A0*/ >> + >> +static void >> +gcov_process_cgraph_node (struct dyn_cgraph_node *node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_type cutoff_co= unt, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned import_scale) >> +{ >> + =A0unsigned mod_id; >> + =A0struct dyn_cgraph_edge *callees; >> + =A0struct dyn_cgraph_edge *callers; >> + =A0node->visited =3D 1; >> + =A0node->sum_in_count =3D 0; >> + >> + =A0callers =3D node->callers; >> + =A0while (callers) >> + =A0 =A0{ >> + =A0 =A0 =A0node->sum_in_count +=3D callers->count; >> + =A0 =A0 =A0callers =3D callers->next_caller; >> + =A0 =A0} >> + >> + =A0callees =3D node->callees; >> + =A0mod_id =3D get_module_idx_from_func_glob_uid (node->guid); >> + >> + =A0while (callees) >> + =A0 =A0{ >> + =A0 =A0 =A0if (!callees->callee->visited) >> + =A0 =A0 =A0 =A0gcov_process_cgraph_node (callees->callee, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cut= off_count, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 import= _scale); >> + =A0 =A0 =A0callees =3D callees->next_callee; >> + =A0 =A0} >> + >> + =A0callees =3D node->callees; >> + =A0while (callees) >> + =A0 =A0{ >> + =A0 =A0 =A0if (callees->count >=3D cutoff_count) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0unsigned callee_mod_id; >> + =A0 =A0 =A0 =A0 =A0struct dyn_pointer_set *imp_modules >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D gcov_get_imp_module_set (node); >> + >> + =A0 =A0 =A0 =A0 =A0callee_mod_id >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D get_module_idx_from_func_glob_uid (call= ees->callee->guid); >> + >> + =A0 =A0 =A0 =A0 double callee_mod_wt =3D (double) callees->count; >> + =A0 =A0 =A0 =A0 =A0if (callees->callee->imported_modules) >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 double scale =3D ((double) callees->count) / >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ((double) callees->callee->sum_in_count); >> + =A0 =A0 =A0 =A0 =A0 =A0 /* Reduce weight if callee is in different mod= ule. =A0*/ >> + =A0 =A0 =A0 =A0 =A0 =A0 if (mod_id !=3D callee_mod_id) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 scale =3D (scale * import_scale) / 100.0; >> + =A0 =A0 =A0 =A0 =A0 =A0 pointer_set_traverse (callees->callee->importe= d_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gc= ov_propagate_imp_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 im= p_modules, &scale, &callee_mod_wt); >> + =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0if (mod_id !=3D callee_mod_id) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0struct gcov_info *callee_mod_info >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D get_module_info (callee_mod_id); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0imp_mod_set_insert (imp_modules, callee_mod= _info, callee_mod_wt); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0callees =3D callees->next_callee; >> + =A0 =A0} >> +} >> + >> +/* Compute module grouping using CUTOFF_COUNT as the hot edge >> + =A0 threshold. =A0*/ >> + >> +#define DEFAULT_IMPORT_SCALE 100 >> +static void >> +gcov_compute_module_groups (gcov_type cutoff_count) >> +{ >> + =A0unsigned m_ix; >> + =A0struct gcov_info *gi_ptr; >> + =A0const char *import_scale_str; >> + =A0unsigned import_scale =3D DEFAULT_IMPORT_SCALE; >> + >> + =A0import_scale_str =3D getenv ("GCOV_DYN_IMPORT_SCALE"); >> + =A0if (import_scale_str && strlen (import_scale_str)) >> + =A0 =A0import_scale =3D atoi (import_scale_str); >> + >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned f_ix; >> + >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[m_ix]; >> + >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct dyn_cgraph_node *node; >> + >> + =A0 =A0 =A0 =A0 fi_ptr =3D the_dyn_call_graph.functions[m_ix][f_ix]; >> + =A0 =A0 =A0 =A0 node =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_node= s[m_ix], fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (node); >> + =A0 =A0 =A0 =A0 =A0if (node->visited) >> + =A0 =A0 =A0 =A0 =A0 =A0continue; >> + >> + =A0 =A0 =A0 =A0 =A0gcov_process_cgraph_node (node, cutoff_count, impor= t_scale); >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned f_ix; >> + >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[m_ix]; >> + >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct dyn_cgraph_node *node; >> + =A0 =A0 =A0 =A0 =A0unsigned mod_id; >> + =A0 =A0 =A0 =A0 =A0struct dyn_pointer_set *imp_modules; >> + >> + =A0 =A0 =A0 =A0 fi_ptr =3D the_dyn_call_graph.functions[m_ix][f_ix]; >> + =A0 =A0 =A0 =A0 node =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_node= s[m_ix], fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (node); >> + >> + =A0 =A0 =A0 =A0 =A0if (!node->imported_modules) >> + =A0 =A0 =A0 =A0 =A0 =A0continue; >> + >> + =A0 =A0 =A0 =A0 =A0mod_id =3D get_module_idx_from_func_glob_uid (node-= >guid); >> + =A0 =A0 =A0 =A0 =A0gcc_assert (mod_id =3D=3D m_ix); >> + >> + =A0 =A0 =A0 =A0 =A0imp_modules >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D gcov_get_module_imp_module_set ( >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0&the_dyn_call_graph.sup_modules[mod= _id]); >> + >> + =A0 =A0 =A0 =A0 =A0pointer_set_traverse (node->imported_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_pr= opagate_imp_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0imp_mod= ules, 0, 0); >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + >> + =A0/* Now compute the export attribute =A0*/ >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0struct dyn_module_info *mi >> + =A0 =A0 =A0 =A0 =A0=3D &the_dyn_call_graph.sup_modules[m_ix]; >> + =A0 =A0 =A0if (mi->imported_modules) >> + =A0 =A0 =A0 =A0pointer_set_traverse (mi->imported_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_mark_e= xport_modules, 0, 0, 0); >> + =A0 =A0} >> +} >> + >> +/* For each module, compute at random, the group of imported modules, >> + =A0 that is of size at most MAX_GROUP_SIZE. =A0*/ >> + >> +static void >> +gcov_compute_random_module_groups (unsigned max_group_size) >> +{ >> + =A0unsigned m_ix; >> + >> + =A0if (max_group_size > the_dyn_call_graph.num_modules) >> + =A0 =A0max_group_size =3D the_dyn_call_graph.num_modules; >> + >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0struct dyn_pointer_set *imp_modules =3D >> + =A0 =A0 =A0 gcov_get_module_imp_module_set (&the_dyn_call_graph.sup_mo= dules[m_ix]); >> + =A0 =A0 =A0int cur_group_size =3D random () % max_group_size; >> + =A0 =A0 =A0int i =3D 0; >> + =A0 =A0 =A0while (i < cur_group_size) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct gcov_info *imp_mod_info; >> + =A0 =A0 =A0 =A0 unsigned mod_id =3D random () % the_dyn_call_graph.num= _modules; >> + =A0 =A0 =A0 =A0 if (mod_id =3D=3D m_ix) >> + =A0 =A0 =A0 =A0 =A0 continue; >> + =A0 =A0 =A0 =A0 imp_mod_info =3D get_module_info (mod_id); >> + =A0 =A0 =A0 =A0 if (!imp_mod_set_insert (imp_modules, imp_mod_info, 1.= 0)) >> + =A0 =A0 =A0 =A0 =A0 i++; >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + >> + =A0/* Now compute the export attribute =A0*/ >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0struct dyn_module_info *mi >> + =A0 =A0 =A0 =3D &the_dyn_call_graph.sup_modules[m_ix]; >> + =A0 =A0 =A0if (mi->imported_modules) >> + =A0 =A0 =A0 =A0pointer_set_traverse (mi->imported_modules, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_mark_e= xport_modules, 0, 0, 0); >> + =A0 =A0} >> +} >> + >> +/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag >> + =A0 indicating if the module is the primary module in the group. =A0*/ >> + >> +static void >> +gcov_write_module_info (const struct gcov_info *mod_info, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned is_primary) >> +{ >> + =A0gcov_unsigned_t len =3D 0, filename_len =3D 0, src_filename_len =3D= 0, i, j; >> + =A0gcov_unsigned_t num_strings; >> + =A0gcov_unsigned_t *aligned_fname; >> + =A0struct gcov_module_info =A0*module_info =3D mod_info->mod_info; >> + =A0filename_len =3D (strlen (module_info->da_filename) + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (gcov_unsigned_t)) / sizeof (gc= ov_unsigned_t); >> + =A0src_filename_len =3D (strlen (module_info->source_filename) + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 sizeof (gcov_unsigned_t)) / si= zeof (gcov_unsigned_t); >> + =A0len =3D filename_len + src_filename_len; >> + =A0len +=3D 2; /* each name string is led by a length. =A0*/ >> + >> + =A0num_strings =3D module_info->num_quote_paths + module_info->num_bra= cket_paths + >> + =A0 =A0module_info->num_cpp_defines + module_info->num_cpp_includes + >> + =A0 =A0module_info->num_cl_args; >> + =A0for (i =3D 0; i < num_strings; i++) >> + =A0 =A0{ >> + =A0 =A0 =A0gcov_unsigned_t string_len >> + =A0 =A0 =A0 =A0 =A0=3D (strlen (module_info->string_array[i]) + sizeof= (gcov_unsigned_t)) >> + =A0 =A0 =A0 =A0 =A0/ sizeof (gcov_unsigned_t); >> + =A0 =A0 =A0len +=3D string_len; >> + =A0 =A0 =A0len +=3D 1; /* Each string is lead by a length. =A0*/ >> + =A0 =A0} >> + >> + =A0len +=3D 9; /* 9 more fields */ >> + >> + =A0gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len); >> + =A0gcov_write_unsigned (module_info->ident); >> + =A0gcov_write_unsigned (is_primary); >> + =A0gcov_write_unsigned (module_info->is_exported); >> + =A0gcov_write_unsigned (module_info->lang); >> + =A0gcov_write_unsigned (module_info->num_quote_paths); >> + =A0gcov_write_unsigned (module_info->num_bracket_paths); >> + =A0gcov_write_unsigned (module_info->num_cpp_defines); >> + =A0gcov_write_unsigned (module_info->num_cpp_includes); >> + =A0gcov_write_unsigned (module_info->num_cl_args); >> + >> + =A0/* Now write the filenames */ >> + =A0aligned_fname =3D (gcov_unsigned_t *) alloca ((filename_len + src_f= ilename_len + 2) * >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 sizeof (gcov_unsigned_t)); >> + =A0memset (aligned_fname, 0, >> + =A0 =A0 =A0 =A0 =A0(filename_len + src_filename_len + 2) * sizeof (gco= v_unsigned_t)); >> + =A0aligned_fname[0] =3D filename_len; >> + =A0strcpy ((char*) (aligned_fname + 1), module_info->da_filename); >> + =A0aligned_fname[filename_len + 1] =3D src_filename_len; >> + =A0strcpy ((char*) (aligned_fname + filename_len + 2), module_info->so= urce_filename); >> + >> + =A0for (i =3D 0; i < (filename_len + src_filename_len + 2); i++) >> + =A0 =A0gcov_write_unsigned (aligned_fname[i]); >> + >> + =A0/* Now write the string array. =A0*/ >> + =A0for (j =3D 0; j < num_strings; j++) >> + =A0 =A0{ >> + =A0 =A0 =A0gcov_unsigned_t *aligned_string; >> + =A0 =A0 =A0gcov_unsigned_t string_len =3D >> + =A0 =A0 =A0 (strlen (module_info->string_array[j]) + sizeof (gcov_unsi= gned_t)) / >> + =A0 =A0 =A0 sizeof (gcov_unsigned_t); >> + =A0 =A0 =A0aligned_string =3D (gcov_unsigned_t *) >> + =A0 =A0 =A0 alloca ((string_len + 1) * sizeof (gcov_unsigned_t)); >> + =A0 =A0 =A0memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_= unsigned_t)); >> + =A0 =A0 =A0aligned_string[0] =3D string_len; >> + =A0 =A0 =A0strcpy ((char*) (aligned_string + 1), module_info->string_a= rray[j]); >> + =A0 =A0 =A0for (i =3D 0; i < (string_len + 1); i++) >> + =A0 =A0 =A0 =A0gcov_write_unsigned (aligned_string[i]); >> + =A0 =A0} >> +} >> + >> +/* Write out MOD_INFO and its imported modules into gcda file. =A0*/ >> + >> +void >> +gcov_write_module_infos (struct gcov_info *mod_info) >> +{ >> + =A0unsigned mod_id, imp_len =3D 0; >> + =A0const struct dyn_imp_mod **imp_mods; >> + >> + =A0mod_id =3D get_module_idx (mod_info); >> + =A0gcov_write_module_info (mod_info, 1); >> + >> + =A0imp_mods =3D gcov_get_sorted_import_module_array (mod_info, &imp_le= n); >> + =A0if (imp_mods) >> + =A0 =A0{ >> + =A0 =A0 =A0unsigned i; >> + >> + =A0 =A0 =A0for (i =3D 0; i < imp_len; i++) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0const struct gcov_info *imp_mod =3D imp_mods[i]->im= p_mod; >> + =A0 =A0 =A0 =A0 =A0gcov_write_module_info (imp_mod, 0); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0free (imp_mods); >> + =A0 =A0} >> +} >> + >> +/* Compute module groups needed for L-IPO compilation. =A0*/ >> + >> +void >> +__gcov_compute_module_groups (void) >> +{ >> + =A0gcov_type cut_off_count; >> + =A0char *seed =3D getenv ("LIPO_RANDOM_GROUPING"); >> + =A0char *max_group_size =3D seed ? strchr (seed, ':') : 0; >> + >> + =A0if (seed && max_group_size) >> + =A0 =A0{ >> + =A0 =A0 =A0*max_group_size =3D '\0'; >> + =A0 =A0 =A0max_group_size++; >> + =A0 =A0 =A0srandom (atoi (seed)); >> + =A0 =A0 =A0init_dyn_call_graph (); >> + =A0 =A0 =A0gcov_compute_random_module_groups (atoi (max_group_size)); >> + =A0 =A0 =A0return; >> + =A0 =A0} >> + >> + =A0/* First compute dynamic call graph. =A0*/ >> + =A0gcov_build_callgraph (); >> + >> + =A0cut_off_count =3D gcov_compute_cutoff_count (); >> + >> + =A0gcov_compute_module_groups (cut_off_count); >> + >> + =A0gcov_dump_callgraph (cut_off_count); >> + >> +} >> + >> +/* Dumper function for NODE. =A0*/ >> +static void >> +gcov_dump_cgraph_node_short (struct dyn_cgraph_node *node) >> +{ >> + =A0unsigned mod_id, func_id; >> + =A0struct gcov_info *mod_info; >> + =A0mod_id =3D get_module_idx_from_func_glob_uid (node->guid); >> + =A0func_id =3D get_intra_module_func_id (node->guid); >> + >> + =A0mod_info =3D the_dyn_call_graph.modules[mod_id]; >> + >> + =A0fprintf (stderr, "NODE(%llx) module(%s) func(%u)", >> + =A0 =A0 =A0 =A0 =A0 (long long)node->guid, >> + =A0 =A0 =A0 =A0 =A0 mod_info->mod_info->source_filename, func_id); >> +} >> + >> +/* Dumper function for NODE. =A0 M is the module id and F is the functi= on id. =A0*/ >> + >> +static void >> +gcov_dump_cgraph_node (struct dyn_cgraph_node *node, unsigned m, unsign= ed f) >> +{ >> + =A0unsigned mod_id, func_id; >> + =A0struct gcov_info *mod_info; >> + =A0struct dyn_cgraph_edge *callers; >> + =A0struct dyn_cgraph_edge *callees; >> + >> + =A0mod_id =3D get_module_idx_from_func_glob_uid (node->guid); >> + =A0func_id =3D get_intra_module_func_id (node->guid); >> + =A0gcc_assert (mod_id =3D=3D m && func_id =3D=3D f); >> + >> + =A0mod_info =3D the_dyn_call_graph.modules[mod_id]; >> + >> + =A0fprintf (stderr, "NODE(%llx) module(%s) func(%x)\n", >> + =A0 =A0 =A0 =A0 =A0 (long long) node->guid, >> + =A0 =A0 =A0 =A0 =A0 mod_info->mod_info->source_filename, f); >> + >> + =A0/* Now dump callers. =A0*/ >> + =A0callers =3D node->callers; >> + =A0fprintf (stderr, "\t[CALLERS]\n"); >> + =A0while (callers !=3D 0) >> + =A0 =A0{ >> + =A0 =A0 =A0fprintf (stderr,"\t\t[count=3D%ld] ", (long) =A0callers->co= unt); >> + =A0 =A0 =A0gcov_dump_cgraph_node_short (callers->caller); >> + =A0 =A0 =A0fprintf (stderr,"\n"); >> + =A0 =A0 =A0callers =3D callers->next_caller; >> + =A0 =A0} >> + >> + =A0callees =3D node->callees; >> + =A0fprintf (stderr, "\t[CALLEES]\n"); >> + =A0while (callees !=3D 0) >> + =A0 =A0{ >> + =A0 =A0 =A0fprintf (stderr,"\t\t[count=3D%ld] ", (long) =A0callees->co= unt); >> + =A0 =A0 =A0gcov_dump_cgraph_node_short (callees->callee); >> + =A0 =A0 =A0fprintf (stderr,"\n"); >> + =A0 =A0 =A0callees =3D callees->next_callee; >> + =A0 =A0} >> +} >> + >> +/* Dumper function for NODE. =A0 M is the module id and F is the functi= on id. =A0*/ >> + >> +static void >> +gcov_dump_cgraph_node_dot (struct dyn_cgraph_node *node, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned m, unsign= ed f, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 gcov_type cutoff_c= ount) >> +{ >> + =A0unsigned mod_id, func_id, imp_len =3D 0, i; >> + =A0struct gcov_info *mod_info; >> + =A0const struct dyn_imp_mod **imp_mods; >> + =A0struct dyn_cgraph_edge *callees; >> + >> + =A0mod_id =3D get_module_idx_from_func_glob_uid (node->guid); >> + =A0func_id =3D get_intra_module_func_id (node->guid); >> + =A0gcc_assert (mod_id =3D=3D m && func_id =3D=3D f); >> + >> + =A0mod_info =3D the_dyn_call_graph.modules[mod_id]; >> + >> + =A0fprintf (stderr, "NODE_%llx[label=3D\"MODULE\\n(%s)\\n FUNC(%x)\\n", >> + =A0 =A0 =A0 =A0 =A0 (long long) node->guid, mod_info->mod_info->source= _filename, f); >> + >> + =A0imp_mods =3D gcov_get_sorted_import_module_array (mod_info, &imp_le= n); >> + =A0fprintf (stderr, "IMPORTS:\\n"); >> + =A0if (imp_mods) >> + =A0 =A0{ >> + =A0 =A0 =A0for (i =3D 0; i < imp_len; i++) >> + =A0 =A0 =A0 =A0fprintf (stderr, "%s\\n", imp_mods[i]->imp_mod->mod_inf= o->source_filename); >> + =A0 =A0 =A0fprintf (stderr, "\"]\n"); >> + =A0 =A0 =A0free (imp_mods); >> + =A0 =A0} >> + =A0else >> + =A0 =A0fprintf (stderr, "\"]\n"); >> + >> + =A0callees =3D node->callees; >> + =A0while (callees !=3D 0) >> + =A0 =A0{ >> + =A0 =A0 =A0if (callees->count >=3D cutoff_count) >> + =A0 =A0 =A0 =A0fprintf (stderr, "NODE_%llx -> NODE_%llx[label=3D%lld c= olor=3Dred]\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) node->guid, (long long) ca= llees->callee->guid, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) callees->count); >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0fprintf (stderr, "NODE_%llx -> NODE_%llx[label=3D%lld c= olor=3Dblue]\n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) node->guid, (long long) ca= llees->callee->guid, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long long) callees->count); >> + =A0 =A0 =A0callees =3D callees->next_callee; >> + =A0 =A0} >> +} >> + >> +/* Dump dynamic call graph. =A0CUTOFF_COUNT is the computed hot edge th= reshold. =A0*/ >> + >> +static void >> +gcov_dump_callgraph (gcov_type cutoff_count) >> +{ >> + =A0struct gcov_info *gi_ptr; >> + =A0unsigned m_ix; >> + =A0const char *dyn_cgraph_dump =3D 0; >> + >> + =A0dyn_cgraph_dump =3D getenv ("GCOV_DYN_CGRAPH_DUMP"); >> + >> + =A0if (!dyn_cgraph_dump || !strlen (dyn_cgraph_dump)) >> + =A0 =A0 =A0return; >> + >> + =A0fprintf (stderr,"digraph dyn_call_graph {\n"); >> + =A0fprintf (stderr,"node[shape=3Dbox]\nsize=3D\"11,8.5\"\n"); >> + >> + =A0for (m_ix =3D 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) >> + =A0 =A0{ >> + =A0 =A0 =A0const struct gcov_fn_info *fi_ptr; >> + =A0 =A0 =A0unsigned f_ix; >> + >> + =A0 =A0 =A0gi_ptr =3D the_dyn_call_graph.modules[m_ix]; >> + >> + =A0 =A0 =A0for (f_ix =3D 0; f_ix < gi_ptr->n_functions; f_ix++) >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 struct dyn_cgraph_node *node; >> + =A0 =A0 =A0 =A0 fi_ptr =3D the_dyn_call_graph.functions[m_ix][f_ix]; >> + >> + =A0 =A0 =A0 =A0 node =3D *(pointer_set_find_or_insert >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(the_dyn_call_graph.call_graph_node= s[m_ix], fi_ptr->ident)); >> + =A0 =A0 =A0 =A0 gcc_assert (node); >> + >> + =A0 =A0 =A0 =A0 =A0/* skip dead functions =A0*/ >> + =A0 =A0 =A0 =A0 =A0if (!node->callees && !node->callers) >> + =A0 =A0 =A0 =A0 =A0 =A0continue; >> + >> + =A0 =A0 =A0 =A0 =A0if (dyn_cgraph_dump[0] =3D=3D '1') >> + =A0 =A0 =A0 =A0 =A0 =A0gcov_dump_cgraph_node (node, m_ix, fi_ptr->iden= t); >> + =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0gcov_dump_cgraph_node_dot (node, m_ix, fi_ptr->= ident, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 cutoff_count); >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + =A0fprintf (stderr,"}\n"); >> +} >> + >> + >> +#endif >> Index: dbgcnt.def >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- dbgcnt.def =A0(revision 172880) >> +++ dbgcnt.def =A0(working copy) >> @@ -141,10 +141,12 @@ echo ubound: $ub >> =A0*/ >> >> =A0/* Debug counter definitions. =A0*/ >> +DEBUG_COUNTER (alias) >> =A0DEBUG_COUNTER (auto_inc_dec) >> =A0DEBUG_COUNTER (ccp) >> =A0DEBUG_COUNTER (cfg_cleanup) >> =A0DEBUG_COUNTER (cse2_move2add) >> +DEBUG_COUNTER (clone) >> =A0DEBUG_COUNTER (cprop) >> =A0DEBUG_COUNTER (dce) >> =A0DEBUG_COUNTER (dce_fast) >> @@ -165,6 +167,7 @@ DEBUG_COUNTER (if_conversion) >> =A0DEBUG_COUNTER (if_conversion_tree) >> =A0DEBUG_COUNTER (if_after_combine) >> =A0DEBUG_COUNTER (if_after_reload) >> +DEBUG_COUNTER (inl) >> =A0DEBUG_COUNTER (local_alloc_for_sched) >> =A0DEBUG_COUNTER (postreload_cse) >> =A0DEBUG_COUNTER (pre) >> Index: c-family/c-opts.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- c-family/c-opts.c =A0 (revision 172880) >> +++ c-family/c-opts.c =A0 (working copy) >> @@ -38,6 +38,9 @@ along with GCC; see the file COPYING3. >> =A0#include "mkdeps.h" >> =A0#include "target.h" =A0 =A0 =A0 =A0 =A0 =A0/* For gcc_targetcm. =A0*/ >> =A0#include "tm_p.h" =A0 =A0 =A0 =A0 =A0 =A0 =A0/* For C_COMMON_OVERRIDE= _OPTIONS. =A0*/ >> +#include "function.h" >> +#include "params.h" >> +#include "l-ipo.h" >> >> =A0#ifndef DOLLARS_IN_IDENTIFIERS >> =A0# define DOLLARS_IN_IDENTIFIERS true >> @@ -364,6 +367,7 @@ c_common_handle_option (size_t scode, co >> =A0 =A0 =A0 warn_missing_braces =3D value; >> =A0 =A0 =A0 warn_parentheses =3D value; >> =A0 =A0 =A0 warn_return_type =3D value; >> + =A0 =A0 =A0warn_ripa_opt_mismatch =3D value; >> =A0 =A0 =A0 warn_sequence_point =3D value; =A0 =A0 /* Was C only. =A0*/ >> =A0 =A0 =A0 warn_switch =3D value; >> =A0 =A0 =A0 if (warn_strict_aliasing =3D=3D -1) >> @@ -864,6 +868,10 @@ c_common_post_options (const char **pfil >> =A0 else if (!flag_gnu89_inline && !flag_isoc99) >> =A0 =A0 error ("-fno-gnu89-inline is only supported in GNU99 or C99 mode= "); >> >> + =A0if (flag_dyn_ipa && cpp_opts->preprocessed) >> + =A0 =A0error ("-fpreprocessed/-save-temps are not supported with -frip= a"); >> + >> + >> =A0 /* Default to ObjC sjlj exception handling if NeXT runtime. =A0*/ >> =A0 if (flag_objc_sjlj_exceptions < 0) >> =A0 =A0 flag_objc_sjlj_exceptions =3D flag_next_runtime; >> @@ -1061,6 +1069,28 @@ c_common_init (void) >> =A0 return true; >> =A0} >> >> +/* Return TRUE if the lipo maximum memory consumption limit is reached,= and >> + =A0 we should not import any further auxiliary modules. Check after pa= rsing >> + =A0 each module, the Ith module being the just parsed module. =A0*/ >> +static bool >> +lipo_max_mem_reached (unsigned int i) >> +{ >> + =A0if (L_IPO_COMP_MODE && PARAM_VALUE (PARAM_MAX_LIPO_MEMORY) >> + =A0 =A0 =A0&& i < (num_in_fnames - 1) >> + =A0 =A0 =A0&& ((ggc_total_allocated () >> 10) >> + =A0 =A0 =A0 =A0 =A0> (size_t) PARAM_VALUE (PARAM_MAX_LIPO_MEMORY))) { >> + =A0 =A0i++; >> + =A0 =A0do { >> + =A0 =A0 =A0inform (input_location, "Not importing %s: maximum memory " >> + =A0 =A0 =A0 =A0 =A0 =A0 "consumption reached", in_fnames[i]); >> + =A0 =A0 =A0i++; >> + =A0 =A0} while (i < num_in_fnames); >> + =A0 =A0return true; >> + =A0} >> + =A0return false; >> +} >> + >> + >> =A0/* Initialize the integrated preprocessor after debug output has been >> =A0 =A0initialized; loop over each input file. =A0*/ >> =A0void >> @@ -1073,8 +1103,15 @@ c_common_parse_file (void) >> =A0 =A0 { >> =A0 =A0 =A0 c_finish_options (); >> =A0 =A0 =A0 pch_init (); >> + =A0 =A0 =A0set_lipo_c_parsing_context (parse_in, i, verbose); >> =A0 =A0 =A0 push_file_scope (); >> =A0 =A0 =A0 c_parse_file (); >> + =A0 =A0 =A0/* In lipo mode, processing too many auxiliary files will c= ause us >> + =A0 =A0 =A0 =A0to hit memory limits, and cause thrashing -- prevent th= is by not >> + =A0 =A0 =A0 =A0processing any further auxiliary modules if we reach a = certain >> + =A0 =A0 =A0 =A0memory limit. =A0*/ >> + =A0 =A0 =A0if (lipo_max_mem_reached (i)) >> + =A0 =A0 =A0 num_in_fnames =3D i + 1; >> =A0 =A0 =A0 pop_file_scope (); >> =A0 =A0 =A0 /* And end the main input file, if the debug writer wants it= =A0*/ >> =A0 =A0 =A0 if (debug_hooks->start_end_main_source_file) >> @@ -1083,6 +1120,7 @@ c_common_parse_file (void) >> =A0 =A0 =A0 =A0break; >> =A0 =A0 =A0 cpp_undef_all (parse_in); >> =A0 =A0 =A0 cpp_clear_file_cache (parse_in); >> + =A0 =A0 =A0deferred_count =3D 0; >> =A0 =A0 =A0 this_input_filename >> =A0 =A0 =A0 =A0=3D cpp_read_main_file (parse_in, in_fnames[i]); >> =A0 =A0 =A0 /* If an input file is missing, abandon further compilation. >> @@ -1320,9 +1358,15 @@ c_finish_options (void) >> =A0 =A0 =A0 =A0 =A0struct deferred_opt *opt =3D &deferred_opts[i]; >> >> =A0 =A0 =A0 =A0 =A0if (opt->code =3D=3D OPT_D) >> - =A0 =A0 =A0 =A0 =A0 cpp_define (parse_in, opt->arg); >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 cpp_define (parse_in, opt->arg); >> + =A0 =A0 =A0 =A0 =A0 =A0 coverage_note_define (opt->arg, true); >> + =A0 =A0 =A0 =A0 =A0 } >> =A0 =A0 =A0 =A0 =A0else if (opt->code =3D=3D OPT_U) >> - =A0 =A0 =A0 =A0 =A0 cpp_undef (parse_in, opt->arg); >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 cpp_undef (parse_in, opt->arg); >> + =A0 =A0 =A0 =A0 =A0 =A0 coverage_note_define (opt->arg, false); >> + =A0 =A0 =A0 =A0 =A0 } >> =A0 =A0 =A0 =A0 =A0else if (opt->code =3D=3D OPT_A) >> =A0 =A0 =A0 =A0 =A0 =A0{ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (opt->arg[0] =3D=3D '-') >> @@ -1345,6 +1389,7 @@ c_finish_options (void) >> =A0 =A0 =A0 =A0 =A0if (opt->code =3D=3D OPT_imacros >> =A0 =A0 =A0 =A0 =A0 =A0 =A0&& cpp_push_include (parse_in, opt->arg)) >> =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 coverage_note_include (opt->arg); >> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Disable push_command_line_include callback= for now. =A0*/ >> =A0 =A0 =A0 =A0 =A0 =A0 =A0include_cursor =3D deferred_count + 1; >> =A0 =A0 =A0 =A0 =A0 =A0 =A0cpp_scan_nooutput (parse_in); >> @@ -1376,7 +1421,10 @@ push_command_line_include (void) >> >> =A0 =A0 =A0 if (!cpp_opts->preprocessed && opt->code =3D=3D OPT_include >> =A0 =A0 =A0 =A0 =A0&& cpp_push_include (parse_in, opt->arg)) >> - =A0 =A0 =A0 return; >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 coverage_note_include (opt->arg); >> + =A0 =A0 =A0 =A0 return; >> + =A0 =A0 =A0 } >> =A0 =A0 } >> >> =A0 if (include_cursor =3D=3D deferred_count) >> Index: cgraph.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- cgraph.c =A0 =A0(revision 172880) >> +++ cgraph.c =A0 =A0(working copy) >> @@ -98,6 +98,7 @@ The callgraph: >> =A0#include "rtl.h" >> =A0#include "ipa-utils.h" >> =A0#include "lto-streamer.h" >> +#include "l-ipo.h" >> >> =A0const char * const ld_plugin_symbol_resolution_names[]=3D >> =A0{ >> @@ -485,6 +486,44 @@ cgraph_create_node (void) >> =A0 return node; >> =A0} >> >> +/* Add an entry in assembler hash for NODE. =A0*/ >> +void >> +cgraph_add_assembler_hash_node (struct cgraph_node *node) >> +{ >> + =A0if (assembler_name_hash) >> + =A0 =A0{ >> + =A0 =A0 =A0void **aslot; >> + =A0 =A0 =A0tree name =3D DECL_ASSEMBLER_NAME (node->decl); >> + >> + =A0 =A0 =A0aslot =3D htab_find_slot_with_hash (assembler_name_hash, na= me, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 decl_assembler_name_hash (name), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 INSERT); >> + =A0 =A0 =A0/* We can have multiple declarations with same assembler na= me. For C++ >> + =A0 =A0 =A0 =A0it is __builtin_strlen and strlen, for instance. =A0Do = we need to >> + =A0 =A0 =A0 =A0record them all? =A0Original implementation marked just= first one >> + =A0 =A0 =A0 =A0so lets hope for the best. =A0*/ >> + =A0 =A0 =A0if (*aslot =3D=3D NULL) >> + =A0 =A0 =A0 *aslot =3D node; >> + =A0 =A0} >> +} >> + >> +/* Remove from assembler hash for NODE. =A0*/ >> +void >> +cgraph_remove_assembler_hash_node (struct cgraph_node *node) >> +{ >> + =A0void **slot; >> + =A0if (assembler_name_hash) >> + =A0 =A0{ >> + =A0 =A0 =A0tree name =3D DECL_ASSEMBLER_NAME (node->decl); >> + =A0 =A0 =A0slot =3D htab_find_slot_with_hash (assembler_name_hash, nam= e, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0decl_assembler_name_hash (name), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0NO_INSERT); >> + =A0 =A0 =A0/* Inline clones are not hashed. =A0*/ >> + =A0 =A0 =A0if (slot && *slot =3D=3D node) >> + =A0 =A0 =A0 =A0htab_clear_slot (assembler_name_hash, slot); >> + =A0 =A0} >> +} >> + >> =A0/* Return cgraph node assigned to DECL. =A0Create new one when needed= . =A0*/ >> >> =A0struct cgraph_node * >> @@ -518,21 +557,7 @@ cgraph_node (tree decl) >> =A0 =A0 =A0 node->next_nested =3D node->origin->nested; >> =A0 =A0 =A0 node->origin->nested =3D node; >> =A0 =A0 } >> - =A0if (assembler_name_hash) >> - =A0 =A0{ >> - =A0 =A0 =A0void **aslot; >> - =A0 =A0 =A0tree name =3D DECL_ASSEMBLER_NAME (decl); >> - >> - =A0 =A0 =A0aslot =3D htab_find_slot_with_hash (assembler_name_hash, na= me, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 decl_assembler_name_hash (name), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 INSERT); >> - =A0 =A0 =A0/* We can have multiple declarations with same assembler na= me. For C++ >> - =A0 =A0 =A0 =A0it is __builtin_strlen and strlen, for instance. =A0Do = we need to >> - =A0 =A0 =A0 =A0record them all? =A0Original implementation marked just= first one >> - =A0 =A0 =A0 =A0so lets hope for the best. =A0*/ >> - =A0 =A0 =A0if (*aslot =3D=3D NULL) >> - =A0 =A0 =A0 *aslot =3D node; >> - =A0 =A0} >> + =A0cgraph_add_assembler_hash_node (node); >> =A0 return node; >> =A0} >> >> @@ -830,7 +855,9 @@ cgraph_edge (struct cgraph_node *node, g >> =A0 =A0 { >> =A0 =A0 =A0 node->call_site_hash =3D htab_create_ggc (120, edge_hash, ed= ge_eq, NULL); >> =A0 =A0 =A0 for (e2 =3D node->callees; e2; e2 =3D e2->next_callee) >> - =A0 =A0 =A0 cgraph_add_edge_to_call_site_hash (e2); >> + =A0 =A0 =A0 /* Skip fake edges. =A0*/ >> + =A0 =A0 =A0 if (e2->call_stmt) >> + =A0 =A0 =A0 =A0 cgraph_add_edge_to_call_site_hash (e2); >> =A0 =A0 =A0 for (e2 =3D node->indirect_calls; e2; e2 =3D e2->next_callee) >> =A0 =A0 =A0 =A0cgraph_add_edge_to_call_site_hash (e2); >> =A0 =A0 } >> @@ -1139,7 +1166,7 @@ cgraph_edge_remove_caller (struct cgraph >> =A0 =A0 =A0 else >> =A0 =A0 =A0 =A0e->caller->callees =3D e->next_callee; >> =A0 =A0 } >> - =A0if (e->caller->call_site_hash) >> + =A0if (e->caller->call_site_hash && e->call_stmt) >> =A0 =A0 htab_remove_elt_with_hash (e->caller->call_site_hash, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 e->call_stmt, >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 htab_hash_po= inter (e->call_stmt)); >> @@ -1178,6 +1205,26 @@ cgraph_remove_edge (struct cgraph_edge * >> =A0 cgraph_free_edge (e); >> =A0} >> >> +/* Remove fake cgraph edges for indirect calls. NODE is the callee >> + =A0 of the edges. =A0*/ >> + >> +void >> +cgraph_remove_fake_indirect_call_in_edges (struct cgraph_node *node) >> +{ >> + =A0struct cgraph_edge *f, *e; >> + >> + =A0if (!L_IPO_COMP_MODE) >> + =A0 =A0return; >> + >> + =A0for (e =3D node->callers; e; e =3D f) >> + =A0 =A0{ >> + =A0 =A0 =A0f =3D e->next_caller; >> + =A0 =A0 =A0if (!e->call_stmt) >> + =A0 =A0 =A0 =A0cgraph_remove_edge (e); >> + =A0 =A0} >> +} >> + >> + >> =A0/* Set callee of call graph edge E and add it to the corresponding se= t of >> =A0 =A0callers. */ >> >> @@ -1400,6 +1447,8 @@ cgraph_node_remove_callers (struct cgrap >> =A0void >> =A0cgraph_release_function_body (struct cgraph_node *node) >> =A0{ >> + =A0if (cgraph_is_aux_decl_external (node)) >> + =A0 =A0DECL_EXTERNAL (node->decl) =3D 1; >> =A0 if (DECL_STRUCT_FUNCTION (node->decl)) >> =A0 =A0 { >> =A0 =A0 =A0 tree old_decl =3D current_function_decl; >> @@ -1667,19 +1716,14 @@ cgraph_remove_node (struct cgraph_node * >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0|| n->in_other_partition))) >> =A0 =A0 =A0 =A0kill_body =3D true; >> =A0 =A0 } >> - =A0if (assembler_name_hash) >> - =A0 =A0{ >> - =A0 =A0 =A0tree name =3D DECL_ASSEMBLER_NAME (node->decl); >> - =A0 =A0 =A0slot =3D htab_find_slot_with_hash (assembler_name_hash, nam= e, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0decl_assembler_name_hash (name), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0NO_INSERT); >> - =A0 =A0 =A0/* Inline clones are not hashed. =A0*/ >> - =A0 =A0 =A0if (slot && *slot =3D=3D node) >> - =A0 =A0 =A0 =A0htab_clear_slot (assembler_name_hash, slot); >> - =A0 =A0} >> + >> + =A0cgraph_remove_assembler_hash_node (node); >> >> =A0 if (kill_body) >> =A0 =A0 cgraph_release_function_body (node); >> + >> + =A0cgraph_remove_link_node (node); >> + >> =A0 node->decl =3D NULL; >> =A0 if (node->call_site_hash) >> =A0 =A0 { >> @@ -1724,7 +1768,8 @@ cgraph_mark_reachable_node (struct cgrap >> =A0 =A0 =A0 =A0 =A0 =A0 during the optimization process. =A0This can hap= pen for extern >> =A0 =A0 =A0 =A0 =A0 =A0 inlines when bodies was removed after inlining. = =A0*/ >> =A0 =A0 =A0 =A0 =A0gcc_assert ((node->analyzed || node->in_other_partiti= on >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0|| DECL_EXTERNAL (node->dec= l))); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0|| DECL_EXTERNAL (node->dec= l) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 || cgraph_is_aux_decl_exte= rnal (node))); >> =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 else >> =A0 =A0 =A0 =A0 notice_global_symbol (node->decl); >> @@ -2190,6 +2235,7 @@ cgraph_clone_node (struct cgraph_node *n >> =A0 new_node->global =3D n->global; >> =A0 new_node->rtl =3D n->rtl; >> =A0 new_node->count =3D count; >> + =A0new_node->is_versioned_clone =3D n->is_versioned_clone; >> =A0 new_node->frequency =3D n->frequency; >> =A0 new_node->clone =3D n->clone; >> =A0 new_node->clone.tree_map =3D 0; >> @@ -2239,17 +2285,8 @@ cgraph_clone_node (struct cgraph_node *n >> =A0 =A0 =A0 slot =3D (struct cgraph_node **) htab_find_slot (cgraph_hash= , new_node, INSERT); >> =A0 =A0 =A0 gcc_assert (!*slot); >> =A0 =A0 =A0 *slot =3D new_node; >> - =A0 =A0 =A0if (assembler_name_hash) >> - =A0 =A0 =A0 { >> - =A0 =A0 =A0 =A0 void **aslot; >> - =A0 =A0 =A0 =A0 tree name =3D DECL_ASSEMBLER_NAME (decl); >> - >> - =A0 =A0 =A0 =A0 aslot =3D htab_find_slot_with_hash (assembler_name_has= h, name, >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 decl_assembler_name_hash (name), >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 INSERT); >> - =A0 =A0 =A0 =A0 gcc_assert (!*aslot); >> - =A0 =A0 =A0 =A0 *aslot =3D new_node; >> - =A0 =A0 =A0 } >> + =A0 =A0 =A0cgraph_add_assembler_hash_node (new_node); >> + =A0 =A0 =A0cgraph_link_node (new_node); >> =A0 =A0 } >> =A0 return new_node; >> =A0} >> @@ -2379,6 +2416,7 @@ cgraph_create_virtual_clone (struct cgra >> =A0 =A0 new_node->clone.combined_args_to_skip =3D args_to_skip; >> =A0 new_node->local.externally_visible =3D 0; >> =A0 new_node->local.local =3D 1; >> + =A0new_node->is_versioned_clone =3D 1; >> =A0 new_node->lowered =3D true; >> =A0 new_node->reachable =3D true; >> >> Index: cgraph.h >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- cgraph.h =A0 =A0(revision 172880) >> +++ cgraph.h =A0 =A0(working copy) >> @@ -286,6 +286,8 @@ struct GTY((chain_next ("%h.next"), chai >> =A0 unsigned alias : 1; >> =A0 /* Set for nodes that was constructed and finalized by frontend. =A0= */ >> =A0 unsigned finalized_by_frontend : 1; >> + =A0/* Is this function cloned during versioning ? =A0*/ >> + =A0unsigned is_versioned_clone : 1; >> =A0 /* Set for alias and thunk nodes, same_body points to the node they = are alias >> =A0 =A0 =A0of and they are linked through the next/previous pointers. = =A0*/ >> =A0 unsigned same_body_alias : 1; >> @@ -475,6 +477,8 @@ struct GTY((chain_next ("%h.next"), chai >> =A0 int order; >> =A0 enum ld_plugin_symbol_resolution resolution; >> >> + =A0/* The module in which it is first declared. =A0*/ >> + =A0unsigned module_id; >> =A0 /* Set when function must be output - it is externally visible >> =A0 =A0 =A0or its address is taken. =A0*/ >> =A0 unsigned needed : 1; >> @@ -547,6 +551,11 @@ void debug_cgraph_node (struct cgraph_no >> =A0void cgraph_insert_node_to_hashtable (struct cgraph_node *node); >> =A0void cgraph_remove_edge (struct cgraph_edge *); >> =A0void cgraph_remove_node (struct cgraph_node *); >> +void cgraph_add_assembler_hash_node (struct cgraph_node *); >> +void cgraph_remove_assembler_hash_node (struct cgraph_node *); >> +void cgraph_remove_fake_indirect_call_in_edges (struct cgraph_node *); >> +extern bool cgraph_pre_profiling_inlining_done; >> +extern bool cgraph_is_fake_indirect_call_edge (struct cgraph_edge *e); >> =A0void cgraph_remove_node_and_inline_clones (struct cgraph_node *); >> =A0void cgraph_release_function_body (struct cgraph_node *); >> =A0void cgraph_node_remove_callees (struct cgraph_node *node); >> @@ -641,6 +650,48 @@ struct cgraph_node *save_inline_function >> =A0void record_references_in_initializer (tree, bool); >> =A0bool cgraph_process_new_functions (void); >> >> +/* Module info structure. =A0*/ >> +struct GTY (()) cgraph_mod_info >> +{ >> + =A0unsigned module_id; >> +}; >> + >> +/* LIPO linker symbol table entry for function symbols. =A0*/ >> +struct GTY (()) cgraph_sym >> +{ >> + =A0tree assembler_name; >> + =A0struct cgraph_node *rep_node; >> + =A0tree rep_decl; >> + =A0htab_t GTY ((param_is (struct cgraph_mod_info))) def_module_hash; >> + =A0bool is_promoted_static; >> +}; >> + >> +void cgraph_init_gid_map (void); >> +void cgraph_add_fake_indirect_call_edges (void); >> +void cgraph_remove_zero_count_fake_edges (void); >> +void cgraph_do_link (void); >> +struct cgraph_sym *cgraph_link_node (struct cgraph_node *); >> +tree cgraph_find_decl (tree asm_name); >> +void cgraph_remove_link_node (struct cgraph_node *node); >> +struct cgraph_node *cgraph_lipo_get_resolved_node (tree decl); >> +struct cgraph_node *cgraph_lipo_get_resolved_node_1 (tree decl, bool); >> +unsigned =A0cgraph_get_module_id (tree fndecl); >> +bool cgraph_is_auxiliary (tree fndecl); >> +void cgraph_process_module_scope_statics (void); >> +bool cgraph_is_promoted_static_func (tree fndecl); >> +bool cgraph_is_inline_body_available_in_module (tree fndecl, unsigned m= odule_id); >> +bool cgraph_is_aux_decl_external (struct cgraph_node *); >> +void cgraph_unify_type_alias_sets (void); >> +void varpool_do_link (void); >> +void varpool_link_node (struct varpool_node *); >> +void varpool_remove_link_node (struct varpool_node *node); >> +struct varpool_node *real_varpool_node (tree decl); >> +bool varpool_is_auxiliary (struct varpool_node *node); >> +void varpool_get_referenced_asm_ids (VEC(tree, gc) **); >> +void varpool_clear_asm_id_reference_bit (void); >> +void varpool_reset_queue (void); >> +void varpool_remove_duplicate_weak_decls (void); >> + >> =A0bool cgraph_decide_is_function_needed (struct cgraph_node *, tree); >> >> =A0typedef void (*cgraph_edge_hook)(struct cgraph_edge *, void *); >> Index: value-prof.c >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >> --- value-prof.c =A0 =A0 =A0 =A0(revision 172880) >> +++ value-prof.c =A0 =A0 =A0 =A0(working copy) >> @@ -46,6 +46,9 @@ along with GCC; see the file COPYING3. >> =A0#include "timevar.h" >> =A0#include "tree-pass.h" >> =A0#include "pointer-set.h" >> +#include "langhooks.h" >> +#include "params.h" >> +#include "l-ipo.h" >> >> =A0/* In this file value profile based optimizations are placed. =A0Curr= ently the >> =A0 =A0following optimizations are implemented (for more detailed descri= ptions >> @@ -300,6 +303,10 @@ dump_histogram_value (FILE *dump_file, h >> =A0 =A0 =A0 =A0} >> =A0 =A0 =A0 fprintf (dump_file, ".\n"); >> =A0 =A0 =A0 break; >> + =A0 =A0case HIST_TYPE_INDIR_CALL_TOPN: >> + =A0 =A0 =A0fprintf (dump_file, "Indirect call -- top N\n"); >> + =A0 =A0 =A0/* TODO add more elaborate dumping code. =A0*/ >> + =A0 =A0 =A0break; >> =A0 =A0} >> =A0} >> >> @@ -487,6 +494,70 @@ check_counter (gimple stmt, const char * >> =A0 return false; >> =A0} >> >> +/* The overall number of invocations of the counter should match >> + =A0 execution count of basic block. =A0Report it as error rather than >> + =A0 internal error as it might mean that user has misused the profile >> + =A0 somehow. =A0STMT is the indiret call, COUNT1 and COUNT2 are counts >> + =A0 of two top targets, and ALL is the enclosing basic block execution >> + =A0 count. =A0*/ >> + >> +static bool >> +check_ic_counter (gimple stmt, gcov_type *count1, gcov_type *count2, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0gcov_type all) >> +{ >> + =A0location_t locus; >> + =A0if (*count1 > all && flag_profile_correction) >> + =A0 =A0{ >> + =A0 =A0 =A0locus =3D (stmt !=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0? gimple_location (stmt) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0: DECL_SOURCE_LOCATION (current_function_de= cl); >> + =A0 =A0 =A0inform (locus, "Correcting inconsistent value profile: " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0"ic (topn) profiler top target count (%ld) = exceeds " >> + =A0 =A0 =A0 =A0 =A0 =A0 "BB count (%ld)", (long)*count1, (long)all); >> + =A0 =A0 =A0*count1 =3D all; >> + =A0 =A0} >> + =A0if (*count2 > all && flag_profile_correction) >> + =A0 =A0{ >> + =A0 =A0 =A0locus =3D (stmt !=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0? gimple_location (stmt) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0: DECL_SOURCE_LOCATION (current_function_de= cl); >> + =A0 =A0 =A0inform (locus, "Correcting inconsistent value profile: " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0"ic (topn) profiler second target count (%l= d) exceeds " >> + =A0 =A0 =A0 =A0 =A0 =A0 "BB count (%ld)", (long)*count2, (long)all); >> + =A0 =A0 =A0*count2 =3D all; >> + =A0 =A0} >> + >> + =A0if (*count2 > *count1) >> + =A0 =A0{ >> + =A0 =A0 =A0locus =3D (stmt !=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0? gimple_location (stmt) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0: DECL_SOURCE_LOCATION (current_function_de= cl); >> + =A0 =A0 =A0inform (locus, "Corrupted topn ic value profile: " >> + =A0 =A0 =A0 =A0 =A0 =A0 "first target count (%ld) is less than the sec= ond " >> + =A0 =A0 =A0 =A0 =A0 =A0 "target count (%ld)", (long)*count1, (long)*co= unt2); >> + =A0 =A0 =A0return true; >> + =A0 =A0} >> + >> + =A0if (*count1 + *count2 > all) >> + =A0 =A0{ >> + =A0 =A0 =A0/* If (COUNT1 + COUNT2) is greater than ALL by less than ar= ound 10% then >> + =A0 =A0 =A0 =A0just fix COUNT2 up so that (COUNT1 + COUNT2) equals ALL= . =A0*/ >> + =A0 =A0 =A0if ((*count1 + *count2 - all) < (all >> 3)) >> + =A0 =A0 =A0 *count2 =3D all - *count1; >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 locus =3D (stmt !=3D NULL) >> + =A0 =A0 =A0 =A0 =A0 ? gimple_location (stmt) >> + =A0 =A0 =A0 =A0 =A0 : DECL_SOURCE_LOCATION (current_function_decl); >> + =A0 =A0 =A0 =A0 inform (locus, "Corrupted topn ic value profile: top t= wo targets's" >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 " total count (%ld) exceeds bb count (= %ld)", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (long)(*count1 + *count2), (long)all); >> + =A0 =A0 =A0 =A0 return true; >> + =A0 =A0 =A0 } >> + =A0 =A0} >> + =A0return false; >> +} >> + >> >> =A0/* GIMPLE based transformations. */ >> >> @@ -542,6 +613,14 @@ gimple_value_profile_transformations (vo >> =A0 if (changed) >> =A0 =A0 { >> =A0 =A0 =A0 counts_to_freqs (); >> + =A0 =A0 =A0/* Value profile transformations may change inline paramete= rs >> + =A0 =A0 =A0 =A0 a lot (e.g., indirect call promotion introduces new di= rect calls). >> + =A0 =A0 =A0 =A0 The update is also needed to avoid compiler ICE -- whe= n MULTI >> + =A0 =A0 =A0 =A0 target icall promotion happens, the caller's size may = become >> + =A0 =A0 =A0 =A0 negative when the promoted direct calls get promoted. = =A0*/ >> + =A0 =A0 =A0/* Guard this for LIPO for now. =A0*/ >> + =A0 =A0 =A0if (L_IPO_COMP_MODE) >> + =A0 =A0 =A0 =A0compute_inline_parameters (cgraph_node (current_functio= n_decl)); >> =A0 =A0 } >> >> =A0 return changed; >> @@ -1090,6 +1169,111 @@ find_func_by_pid (int =A0 pid) >> =A0 return pid_map [pid]; >> =A0} >> >> +/* Initialize map of gids (gid -> cgraph node) */ >> + >> +static htab_t gid_map =3D NULL; >> + >> +typedef struct func_gid_entry >> +{ >> + =A0struct cgraph_node *node; >> + =A0unsigned HOST_WIDEST_INT gid; >> +} func_gid_entry_t; >> + >> +/* Hash function for function global unique ids. =A0*/ >> + >> +static hashval_t >> +htab_gid_hash (const void * ent) >> +{ >> + =A0const func_gid_entry_t *const entry =3D (const func_gid_entry_t *) = ent; >> + =A0return entry->gid; >> +} >> + >> +/* Hash table equality function for function global unique ids. =A0*/ >> + >> +static int >> +htab_gid_eq (const void *ent1, const void * ent2) >> +{ >> + =A0const func_gid_entry_t *const entry1 =3D (const func_gid_entry_t *)= ent1; >> + =A0const func_gid_entry_t *const entry2 =3D (const func_gid_entry_t *)= ent2; >> + =A0return entry1->gid =3D=3D entry2->gid; >> +} >> + >> +static void >> +htab_gid_del (void *ent) >> +{ >> + =A0func_gid_entry_t *const entry =3D (func_gid_entry_t *) ent; >> + =A0free (entry); >> +} >> + >> +/* Initialize the global unique id map for functions. =A0*/ >> + >> +static void >> +init_gid_map (void) >> +{ >> + =A0struct cgraph_node *n; >> + >> + =A0gcc_assert (!gid_map); >> + >> + =A0gid_map >> + =A0 =A0 =A0=3D htab_create (10, htab_gid_hash, htab_gid_eq, htab_gid_d= el); >> + >> + =A0for (n =3D cgraph_nodes; n; n =3D n->next) >> + =A0 =A0{ >> + =A0 =A0 =A0func_gid_entry_t ent, *entp; >> + =A0 =A0 =A0func_gid_entry_t **slot; >> + =A0 =A0 =A0struct function *f; >> + =A0 =A0 =A0ent.node =3D n; >> + =A0 =A0 =A0f =3D DECL_STRUCT_FUNCTION (n->decl); >> + =A0 =A0 =A0/* Do not care to indirect call promote a function with id.= =A0*/ >> + =A0 =A0 =A0if (!f || DECL_ABSTRACT (n->decl)) >> + =A0 =A0 =A0 =A0continue; >> + =A0 =A0 =A0/* The global function id computed at profile-use time >> + =A0 =A0 =A0 =A0 is slightly different from the one computed in >> + =A0 =A0 =A0 =A0 instrumentation runtime -- for the latter, the intra- >> + =A0 =A0 =A0 =A0 module function ident is 1 based while in profile-use >> + =A0 =A0 =A0 =A0 phase, it is zero based. See get_next_funcdef_no in >> + =A0 =A0 =A0 =A0 function.c. =A0*/ >> + =A0 =A0 =A0ent.gid =3D FUNC_DECL_GLOBAL_ID (DECL_STRUCT_FUNCTION (n->d= ecl)); >> + =A0 =A0 =A0slot =3D (func_gid_entry_t **) htab_find_slot (gid_map, &en= t, INSERT); >> + >> + =A0 =A0 =A0gcc_assert (!*slot || ((*slot)->gid =3D=3D ent.gid && (*slo= t)->node =3D=3D n)); >> + =A0 =A0 =A0if (!*slot) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0*slot =3D entp =3D XCNEW (func_gid_entry_t); >> + =A0 =A0 =A0 =A0 =A0entp->node =3D n; >> + =A0 =A0 =A0 =A0 =A0entp->gid =3D ent.gid; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> + >> +/* Initialize the global unique id map for functions. =A0*/ >> + >> +void >> +cgraph_init_gid_map (void) >> +{ >> + =A0if (!L_IPO_COMP_MODE) >> + =A0 =A0return; >> + >> + =A0init_gid_map (); >> +} >> + >> +/* Return cgraph node for function with global id. =A0*/ >> + >> +struct cgraph_node * >> +find_func_by_global_id (unsigned HOST_WIDE_INT gid) >> +{ >> + =A0func_gid_entry_t ent, *entp; >> + >> + =A0gcc_assert (gid_map); >> + >> + =A0ent.node =3D NULL; >> + =A0ent.gid =3D gid; >> + =A0entp =3D (func_gid_entry_t *)htab_find (gid_map, &ent); >> + =A0if (entp) >> + =A0 =A0return entp->node; >> + =A0return NULL; >> +} >> + >> =A0/* Perform sanity check on the indirect call target. Due to race cond= itions, >> =A0 =A0false function target may be attributed to an indirect call site.= If the >> =A0 =A0call expression type mismatches with the target function's type, = expand_call >> @@ -1244,27 +1428,13 @@ gimple_ic (gimple icall_stmt, struct cgr >> =A0*/ >> >> =A0static bool >> -gimple_ic_transform (gimple stmt) >> +gimple_ic_transform_single_targ (gimple stmt, histogram_value histogram) >> =A0{ >> - =A0histogram_value histogram; >> =A0 gcov_type val, count, all, bb_all; >> =A0 gcov_type prob; >> - =A0tree callee; >> =A0 gimple modify; >> =A0 struct cgraph_node *direct_call; >> >> - =A0if (gimple_code (stmt) !=3D GIMPLE_CALL) >> - =A0 =A0return false; >> - >> - =A0callee =3D gimple_call_fn (stmt); >> - >> - =A0if (TREE_CODE (callee) =3D=3D FUNCTION_DECL) >> - =A0 =A0return false; >> - >> - =A0histogram =3D gimple_histogram_value_of_type (cfun, stmt, HIST_TYPE= _INDIR_CALL); >> - =A0if (!histogram) >> - =A0 =A0return false; >> - >> =A0 val =3D histogram->hvalue.counters [0]; >> =A0 count =3D histogram->hvalue.counters [1]; >> =A0 all =3D histogram->hvalue.counters [2]; >> @@ -1312,6 +1482,195 @@ gimple_ic_transform (gimple stmt) >> =A0 return true; >> =A0} >> >> +/* Convert indirect function call STMT into guarded direct function >> + =A0 calls. Multiple indirect call targets are supported. HISTOGRAM >> + =A0 is the target distribution for the callsite. =A0*/ >> + >> +static bool >> +gimple_ic_transform_mult_targ (gimple stmt, histogram_value histogram) >> +{ >> + =A0gcov_type val1, val2, count1, count2, all, bb_all; >> + =A0gcov_type prob1, prob2; >> + =A0gimple modify1, modify2; >> + =A0struct cgraph_node *direct_call1 =3D 0, *direct_call2 =3D 0; >> + =A0int perc_threshold, count_threshold, always_inline; >> + =A0location_t locus; >> + >> + =A0val1 =3D histogram->hvalue.counters [1]; >> + =A0count1 =3D histogram->hvalue.counters [2]; >> + =A0val2 =3D histogram->hvalue.counters [3]; >> + =A0count2 =3D histogram->hvalue.counters [4]; >> + =A0bb_all =3D gimple_bb (stmt)->count; >> + =A0all =3D bb_all; >> + >> + =A0gimple_remove_histogram_value (cfun, stmt, histogram); >> + >> + =A0if (count1 =3D=3D 0) >> + =A0 =A0return false; >> + >> + =A0perc_threshold =3D PARAM_VALUE (PARAM_ICALL_PROMOTE_PERCENT_THRESHO= LD); >> + =A0count_threshold =3D PARAM_VALUE (PARAM_ICALL_PROMOTE_COUNT_THRESHOL= D); >> + =A0always_inline =3D PARAM_VALUE (PARAM_ALWAYS_INLINE_ICALL_TARGET); >> + >> + =A0if (100 * count1 < all * perc_threshold || count1 < count_threshold) >> + =A0 =A0return false; >> + >> + =A0if (check_ic_counter (stmt, &count1, &count2, all)) >> + =A0 =A0return false; >> + >> + =A0if (all > 0) >> + =A0 =A0{ >> + =A0 =A0 =A0prob1 =3D (count1 * REG_BR_PROB_BASE + all / 2) / all; >> + =A0 =A0 =A0if (all - count1 > 0) >> + =A0 =A0 =A0 =A0prob2 =3D (count2 * REG_BR_PROB_BASE >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 + (all - count1) / 2) / (all - count1); >> + =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0prob2 =3D 0; >> + =A0 =A0} >> + =A0else >> + =A0 =A0prob1 =3D prob2 =3D 0; >> + >> + =A0direct_call1 =3D find_func_by_global_id (val1); >> + >> + =A0if (val2 && (100 * count2 >=3D all * perc_threshold) >> + =A0 =A0 =A0&& count2 > count_threshold) >> + =A0 =A0direct_call2 =3D find_func_by_global_id (val2); >> + >> + =A0locus =3D (stmt !=3D NULL) ? gimple_location (stmt) >> + =A0 =A0 =A0: DECL_SOURCE_LOCATION (current_function_decl); >> + =A0if (direct_call1 =3D=3D NULL >> + =A0 =A0 =A0|| !check_ic_target (stmt, direct_call1)) >> + =A0 =A0{ >> + =A0 =A0 =A0if (flag_ripa_verbose) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0if (!direct_call1) >> + =A0 =A0 =A0 =A0 =A0 =A0inform (locus, "Can not find indirect call targ= et decl " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"(%d:%d)[cnt:%u] in current mod= ule", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0EXTRACT_MODULE_ID_FROM_GLOBAL_I= D (val1), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0EXTRACT_FUNC_ID_FROM_GLOBAL_ID = (val1), (unsigned) count1); >> + =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0inform (locus, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Can not find promote indirect = call target decl -- type mismatch " >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"(%d:%d)[cnt:%u] in current mod= ule", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0EXTRACT_MODULE_ID_FROM_GLOBAL_I= D (val1), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0EXTRACT_FUNC_ID_FROM_GLOBAL_ID = (val1), (unsigned) count1); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0return false; >> + =A0 =A0} >> + >> + =A0/* Don't indirect-call promote if the target is in auxiliary module= and >> + =A0 =A0 DECL_ARTIFICIAL and not TREE_PUBLIC, because we don't static-p= romote >> + =A0 =A0 DECL_ARTIFICIALs yet. =A0*/ >> + =A0if (cgraph_is_auxiliary (direct_call1->decl) >> + =A0 =A0 =A0&& DECL_ARTIFICIAL (direct_call1->decl) >> + =A0 =A0 =A0&& ! TREE_PUBLIC (direct_call1->decl)) >> + =A0 =A0return false; >> + >> + =A0modify1 =3D gimple_ic (stmt, direct_call1, prob1, count