Line data Source code
1 : /* Read and annotate call graph profile from the auto profile data file.
2 : Copyright (C) 2014-2026 Free Software Foundation, Inc.
3 : Contributed by Dehao Chen (dehao@google.com)
4 :
5 : This file is part of GCC.
6 :
7 : GCC is free software; you can redistribute it and/or modify it under
8 : the terms of the GNU General Public License as published by the Free
9 : Software Foundation; either version 3, or (at your option) any later
10 : version.
11 :
12 : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 : WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 : for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with GCC; see the file COPYING3. If not see
19 : <http://www.gnu.org/licenses/>. */
20 :
21 : #include "config.h"
22 : #define INCLUDE_MAP
23 : #define INCLUDE_SET
24 : #include "system.h"
25 : #include "coretypes.h"
26 : #include "backend.h"
27 : #include "tree.h"
28 : #include "gimple.h"
29 : #include "predict.h"
30 : #include "alloc-pool.h"
31 : #include "tree-pass.h"
32 : #include "ssa.h"
33 : #include "cgraph.h"
34 : #include "gcov-io.h"
35 : #include "diagnostic-core.h"
36 : #include "profile.h"
37 : #include "langhooks.h"
38 : #include "context.h"
39 : #include "pass_manager.h"
40 : #include "cfgloop.h"
41 : #include "tree-cfg.h"
42 : #include "tree-cfgcleanup.h"
43 : #include "tree-into-ssa.h"
44 : #include "gimple-iterator.h"
45 : #include "value-prof.h"
46 : #include "symbol-summary.h"
47 : #include "sreal.h"
48 : #include "ipa-cp.h"
49 : #include "ipa-prop.h"
50 : #include "ipa-fnsummary.h"
51 : #include "ipa-inline.h"
52 : #include "tree-inline.h"
53 : #include "auto-profile.h"
54 : #include "tree-pretty-print.h"
55 : #include "gimple-pretty-print.h"
56 : #include "output.h"
57 :
58 : /* The following routines implement AutoFDO optimization.
59 :
60 : This optimization uses sampling profiles to annotate basic block counts
61 : and uses heuristics to estimate branch probabilities.
62 :
63 : There are three phases in AutoFDO:
64 :
65 : Phase 1: At startup.
66 : Read profile from the profile data file.
67 : The following info is read from the profile datafile:
68 : * string_table: a map between function name and its index.
69 : * autofdo_source_profile: a map from function_instance name to
70 : function_instance. This is represented as a forest of
71 : function_instances.
72 : * WorkingSet: a histogram of how many instructions are covered for a
73 : given percentage of total cycles. This is describing the binary
74 : level information (not source level). This info is used to help
75 : decide if we want aggressive optimizations that could increase
76 : code footprint (e.g. loop unroll etc.)
77 : A function instance is an instance of function that could either be a
78 : standalone symbol, or a clone of a function that is inlined into another
79 : function.
80 :
81 : Phase 2: In afdo_offline pass.
82 : Remove function instances from other translation units
83 : and offline all cross-translation unit inlining done during train
84 : run compilation. This is necessary to not lose profiles with
85 : LTO train run.
86 :
87 : Phase 3: During early optimization.
88 : AFDO inline + value profile transformation.
89 : This happens during early optimization.
90 : During early inlining AFDO inliner is executed which
91 : uses autofdo_source_profile to find if a callsite is:
92 : * inlined in the profiled binary.
93 : * callee body is hot in the profiling run.
94 : If both condition satisfies, early inline will inline the callsite
95 : regardless of the code growth.
96 :
97 : Performing this early has benefit of doing early optimizations
98 : before read IPA passes and getting more "context sensitivity" of
99 : the profile read. Profile of inlined functions may differ
100 : significantly from one inline instance to another and from the
101 : offline version.
102 :
103 : This is controlled by -fauto-profile-inlining and is independent
104 : of -fearly-inlining.
105 :
106 : Phase 4: In AFDO pass.
107 : Offline all functions that has been inlined in the
108 : train run but were not inlined in early inlining nor AFDO
109 : inline.
110 :
111 : Phase 5: In AFDO pass.
112 : Annotate control flow graph.
113 : * Annotate basic block count
114 : * Estimate branch probability
115 : * Use earlier static profile to fill in the gaps
116 : if AFDO profile is ambiguous
117 :
118 : After the above 5 phases, all profile is readily annotated on the GCC IR.
119 : AutoFDO tries to reuse all FDO infrastructure as much as possible to make
120 : use of the profile. E.g. it uses existing mechanism to calculate the basic
121 : block/edge frequency, as well as the cgraph node/edge count.
122 : */
123 :
124 : #define DEFAULT_AUTO_PROFILE_FILE "fbdata.afdo"
125 : #define AUTO_PROFILE_VERSION 3
126 :
127 : /* profile counts determined by AFDO smaller than afdo_hot_bb_threshold are
128 : considered cols. */
129 : gcov_type afdo_hot_bb_threshold = -1;
130 :
131 : /* Return true if COUNT is possibly hot. */
132 : bool
133 0 : maybe_hot_afdo_count_p (profile_count count)
134 : {
135 0 : gcc_checking_assert (count.ipa ().initialized_p ());
136 0 : return count.ipa ().to_gcov_type () >= afdo_hot_bb_threshold;
137 : }
138 :
139 : /* Return true if location of STMT may be expressed by debug info. */
140 :
141 : static bool
142 0 : stmt_loc_used_by_debug_info (gimple *stmt)
143 : {
144 : /* Only inline_entry and gimple_bind's locations
145 : are not output into debug output. */
146 0 : if (is_gimple_debug (stmt))
147 0 : return gimple_debug_begin_stmt_p (stmt);
148 0 : if (gimple_code (stmt) == GIMPLE_LABEL
149 : || gimple_code (stmt) == GIMPLE_NOP
150 : || gimple_code (stmt) == GIMPLE_PREDICT)
151 : return false;
152 0 : if (gimple_clobber_p (stmt))
153 0 : return false;
154 : return true;
155 : }
156 :
157 : namespace autofdo
158 : {
159 :
160 : /* Intermediate edge info used when propagating AutoFDO profile information.
161 : We can't edge->count() directly since it's computed from edge's probability
162 : while probability is yet not decided during propagation. */
163 : #define AFDO_EINFO(e) ((class edge_info *) e->aux)
164 : class edge_info
165 : {
166 : public:
167 0 : edge_info () : count_ (profile_count::zero ().afdo ()), annotated_ (false) {}
168 0 : bool is_annotated () const { return annotated_; }
169 0 : void set_annotated () { annotated_ = true; }
170 0 : profile_count get_count () const { return count_; }
171 0 : void set_count (profile_count count) { count_ = count; }
172 : private:
173 : profile_count count_;
174 : bool annotated_;
175 : };
176 :
177 : /* Represent a source location: (function_decl, lineno). */
178 : struct decl_lineno
179 : {
180 : tree decl;
181 : /* Relative locations stored in auto-profile. */
182 : unsigned int afdo_loc;
183 : /* Actual location afdo_loc was computed from used to output diagnostics. */
184 : location_t location;
185 : };
186 :
187 : /* Represent an inline stack. vector[0] is the leaf node. */
188 : typedef auto_vec<decl_lineno, 20> inline_stack;
189 :
190 : /* String array that stores function names. */
191 : typedef auto_vec<const char *> string_vector;
192 :
193 : /* Map from function name's index in string_table to target's
194 : execution count. */
195 : typedef std::map<unsigned, gcov_type> icall_target_map;
196 :
197 : /* Set of gimple stmts. Used to track if the stmt has already been promoted
198 : to direct call. */
199 : typedef std::set<gimple *> stmt_set;
200 :
201 : /* Set and map used to translate name indexes. */
202 : typedef hash_set<int_hash <int, -1, -2>> name_index_set;
203 : typedef hash_map<int_hash <int, -1, -2>, int> name_index_map;
204 :
205 : /* Represent count info of an inline stack. */
206 0 : class count_info
207 : {
208 : public:
209 : /* Sampled count of the inline stack. */
210 : gcov_type count;
211 :
212 : /* Map from indirect call target to its sample count. */
213 : icall_target_map targets;
214 :
215 : /* Whether this inline stack is already used in annotation.
216 :
217 : Each inline stack should only be used to annotate IR once.
218 : This will be enforced when instruction-level discriminator
219 : is supported. */
220 : };
221 :
222 : /* operator< for "const char *". */
223 : struct string_compare
224 : {
225 0 : bool operator()(const char *a, const char *b) const
226 : {
227 0 : return strcmp (a, b) < 0;
228 : }
229 : };
230 :
231 : /* Store the summary information for the profile. */
232 : struct summary_info
233 : {
234 : /* There are currently 16 hard-coded percentiles in the GCOV format. */
235 : static constexpr unsigned NUM_PERCENTILES = 16;
236 :
237 : /* The detailed summary is a histogram-based calculation of the minimum
238 : execution count required to belong to a certain set of percentile of
239 : counts. */
240 : struct detailed_summary
241 : {
242 : /* The percentile that this represents (multiplied by 1,000,000). */
243 : uint32_t cutoff;
244 : /* The minimum execution count required to belong to this percentile. */
245 : uint64_t min_count;
246 : /* The number of samples which belong to this percentile. */
247 : uint64_t num_counts;
248 : };
249 :
250 : /* The sum of execution counts of all samples. */
251 : uint64_t total_count;
252 : /* The maximum individual count. */
253 : uint64_t max_count;
254 : /* The maximum head count across all functions. */
255 : uint64_t max_function_count;
256 : /* The number of lines that have samples. */
257 : uint64_t num_counts;
258 : /* The number of functions that have samples. */
259 : uint64_t num_functions;
260 : /* The percentile threshold information. */
261 : detailed_summary detailed_summaries[NUM_PERCENTILES];
262 :
263 : /* Read profile. Return TRUE on success. */
264 : bool read ();
265 :
266 : /* Get the minimum count required for percentile CUTOFF. */
267 : uint64_t get_threshold_count (uint32_t cutoff);
268 : };
269 :
270 : /* Store a string array, indexed by string position in the array. */
271 : class string_table
272 : {
273 : public:
274 : static const int unknown_filename = -1;
275 :
276 0 : string_table ()
277 0 : {}
278 :
279 : ~string_table ();
280 :
281 : /* For a given string, returns its index. */
282 : int get_index (const char *name) const;
283 :
284 : /* For a given decl, returns the index of the decl name. */
285 : int get_index_by_decl (tree decl) const;
286 :
287 : /* For a given index, returns the symbol name. */
288 : const char *get_symbol_name (int index) const;
289 :
290 : /* For a given index, returns the filename. */
291 : const char *get_filename (int index) const;
292 :
293 : /* For a given symbol name index, returns the filename index. */
294 : int get_filename_by_symbol (int index) const;
295 :
296 : /* For a given function name, returns the filename index. */
297 : int get_filename_by_symbol (const char *name) const;
298 :
299 : /* For a given filename, returns the index. */
300 : int get_filename_index (const char *name) const;
301 :
302 : /* Get the original name and file name index for a node. This will return the
303 : name from the current TU if there are multiple symbols that map to
304 : NAME. */
305 : std::pair<const char *, int> get_original_name (const char *name) const;
306 :
307 : /* Read profile, return TRUE on success. */
308 : bool read ();
309 :
310 : /* Return number of entries. */
311 0 : size_t num_entries () { return symbol_names_.length (); }
312 :
313 : /* Add new symbol name STRING (with an associated file name FILENAME_IDX) and
314 : return its index. */
315 : int add_symbol_name (const char *string, int filename_idx);
316 :
317 : /* Add new filename and return its index (returning the same if it already
318 : exists). */
319 : int add_filename (const char *name);
320 :
321 : /* Return cgraph node corresponding to given name index. */
322 : cgraph_node *get_cgraph_node (int);
323 :
324 : const string_vector& filenames () { return filenames_; }
325 : private:
326 : typedef std::map<const char *, unsigned, string_compare> string_index_map;
327 : typedef std::map<const char *, auto_vec<unsigned>, string_compare>
328 : clashing_name_map;
329 : typedef std::map<const char *, char *, string_compare> string_string_map;
330 :
331 : string_vector symbol_names_;
332 : string_vector filenames_;
333 :
334 : string_index_map symbol_name_map_;
335 : string_index_map filename_map_;
336 : string_index_map symbol_to_filename_map_;
337 :
338 : string_string_map original_names_map_;
339 : clashing_name_map clashing_names_map_;
340 : };
341 :
342 : /* Descriptor for a function_instance which can be used to disambiguate it from
343 : other instances. This consists of the symbol name and the file name indices
344 : from string_table. */
345 :
346 : class function_instance_descriptor
347 : {
348 : /* The string_table index for the file name. */
349 : unsigned file_name_;
350 : /* The string_table index for the function name. */
351 : unsigned symbol_name_;
352 :
353 : public:
354 0 : unsigned file_name () const { return file_name_; }
355 0 : unsigned symbol_name () const { return symbol_name_; }
356 :
357 0 : function_instance_descriptor (unsigned file_name, unsigned symbol_name)
358 0 : : file_name_ (file_name), symbol_name_ (symbol_name)
359 : {}
360 :
361 0 : function_instance_descriptor (int file_name, int symbol_name)
362 0 : : file_name_ (file_name), symbol_name_ (symbol_name)
363 : {}
364 :
365 0 : void set_symbol_name (unsigned new_name) { symbol_name_ = new_name; }
366 :
367 0 : bool operator< (const function_instance_descriptor &other) const
368 : {
369 0 : return file_name_ < other.file_name_
370 0 : || (file_name_ == other.file_name_
371 0 : && symbol_name_ < other.symbol_name_);
372 : }
373 : };
374 :
375 : /* Profile of a function instance:
376 : 1. total_count of the function.
377 : 2. head_count (entry basic block count) of the function (only valid when
378 : function is a top-level function_instance, i.e. it is the original copy
379 : instead of the inlined copy).
380 : 3. map from source location (decl_lineno) to profile (count_info).
381 : 4. map from callsite to callee function_instance. */
382 :
383 : class function_instance
384 : {
385 : public:
386 : typedef auto_vec<function_instance *> function_instance_stack;
387 :
388 : /* Read the profile and return a function_instance with head count as
389 : HEAD_COUNT. Recursively read callsites to create nested function_instances
390 : too. STACK is used to track the recursive creation process. */
391 : static function_instance *
392 : read_function_instance (function_instance_stack *stack, bool toplevel = true);
393 :
394 : /* Recursively deallocate all callsites (nested function_instances). */
395 : ~function_instance ();
396 :
397 : /* Accessors. */
398 0 : int symbol_name () const { return descriptor_.symbol_name (); }
399 0 : int file_name () const { return descriptor_.file_name (); }
400 0 : void set_symbol_name (int index) { descriptor_.set_symbol_name (index); }
401 0 : function_instance_descriptor get_descriptor () const { return descriptor_; }
402 :
403 : gcov_type
404 0 : total_count () const
405 : {
406 0 : return total_count_;
407 : }
408 :
409 : /* Return head count or -1 if unknown. */
410 : gcov_type
411 0 : head_count () const
412 : {
413 0 : return head_count_;
414 : }
415 :
416 : gcov_type
417 0 : timestamp () const
418 : {
419 0 : return timestamp_;
420 : }
421 :
422 0 : void set_timestamp (gcov_type timestamp) { timestamp_ = timestamp; }
423 :
424 : /* Propagate timestamp from top-level function_instance to
425 : inlined instances. */
426 : void prop_timestamp ();
427 :
428 : /* Traverse callsites of the current function_instance to find one at the
429 : location of LINENO and callee name represented in DECL.
430 : LOCATION should match LINENO and is used to output diagnostics. */
431 : function_instance *get_function_instance_by_decl (unsigned lineno,
432 : tree decl,
433 : location_t location) const;
434 :
435 : /* Merge profile of clones. Note that cloning hasn't been performed when
436 : we annotate the CFG (at this stage). */
437 : void merge (function_instance *other,
438 : vec <function_instance *> &new_functions);
439 :
440 : /* Look for inline instances that was not realized and
441 : remove them while possibly merging them to offline variants. */
442 : void offline_if_not_realized (vec <function_instance *> &new_functions);
443 :
444 : /* Match function instance with gimple body. */
445 : bool match (cgraph_node *node, vec <function_instance *> &new_functions,
446 : name_index_map &to_symbol_name);
447 :
448 : /* Offline all inlined functions with name in SEEN.
449 : If new toplevel functions are created, add them to NEW_FUNCTIONS. */
450 : void offline_if_in_set (name_index_set &seen,
451 : vec <function_instance *> &new_functions);
452 :
453 : /* Walk inlined functions and if their name is not in SEEN
454 : remove it. */
455 :
456 : void remove_external_functions (name_index_set &seen,
457 : name_index_map &to_symbol_name,
458 : vec <function_instance *> &new_functions);
459 :
460 : /* Store the profile info for LOC in INFO. Return TRUE if profile info
461 : is found. */
462 : bool get_count_info (location_t loc, count_info *info) const;
463 :
464 : /* Read the inlined indirect call target profile for STMT in FN and store it
465 : in MAP, return the total count for all inlined indirect calls. */
466 : gcov_type find_icall_target_map (tree fn, gcall *stmt,
467 : icall_target_map *map) const;
468 :
469 : /* Remove inlined indirect call target profile for STMT in FN. */
470 : void remove_icall_target (tree fn, gcall *stmt);
471 :
472 : /* Mark LOC as annotated. */
473 : void mark_annotated (location_t loc);
474 :
475 : void dump (FILE *f, int indent = 0, bool nested = false) const;
476 :
477 : void dump_inline_stack (FILE *f) const;
478 :
479 : DEBUG_FUNCTION void debug () const;
480 :
481 : /* Mark function as removed from indir target list. */
482 : void
483 0 : remove_icall_target ()
484 : {
485 0 : removed_icall_target_ = true;
486 : }
487 :
488 : /* Return true if function is removed from indir target list. */
489 : bool
490 0 : removed_icall_target ()
491 : {
492 0 : return removed_icall_target_;
493 : }
494 :
495 : /* Set inlined_to pointer. */
496 : void
497 0 : set_inlined_to (function_instance *inlined_to)
498 : {
499 0 : gcc_checking_assert (inlined_to != this);
500 0 : inlined_to_ = inlined_to;
501 0 : }
502 :
503 : /* Return pointer to the function instance this function is inlined
504 : to or NULL if it is outer instance. */
505 : function_instance *
506 0 : inlined_to () const
507 : {
508 0 : return inlined_to_;
509 : }
510 :
511 : /* Mark function as realized. */
512 : void
513 0 : set_realized ()
514 : {
515 0 : realized_ = true;
516 0 : }
517 :
518 : /* Return true if function is realized. */
519 : bool
520 0 : realized_p ()
521 : {
522 0 : return realized_;
523 : }
524 :
525 : /* Mark function as in_worklist. */
526 : void
527 0 : set_in_worklist ()
528 : {
529 0 : gcc_checking_assert (!inlined_to_ && !in_worklist_p ());
530 0 : in_worklist_ = true;
531 0 : }
532 :
533 : void
534 0 : clear_in_worklist ()
535 : {
536 0 : gcc_checking_assert (!inlined_to_ && in_worklist_p ());
537 0 : in_worklist_ = false;
538 0 : }
539 :
540 :
541 : /* Return true if function is in_worklist. */
542 : bool
543 0 : in_worklist_p ()
544 : {
545 0 : return in_worklist_;
546 : }
547 :
548 : /* Return corresponding cgraph node. */
549 : cgraph_node *get_cgraph_node ();
550 :
551 : void
552 0 : set_location (location_t l)
553 : {
554 0 : gcc_checking_assert (location_ == UNKNOWN_LOCATION);
555 0 : location_= l;
556 0 : }
557 :
558 : location_t
559 0 : get_location ()
560 : {
561 0 : return location_;
562 : }
563 :
564 : void
565 0 : set_call_location (location_t l)
566 : {
567 0 : gcc_checking_assert (call_location_ == UNKNOWN_LOCATION
568 : && l != UNKNOWN_LOCATION);
569 0 : call_location_= l;
570 0 : }
571 :
572 : location_t
573 0 : get_call_location ()
574 : {
575 0 : return call_location_;
576 : }
577 :
578 : /* Lookup count and warn about duplicates. */
579 : count_info *lookup_count (location_t loc, inline_stack &stack,
580 : cgraph_node *node);
581 : private:
582 : /* Callsite, represented as (decl_lineno, callee_function_name_index). */
583 : typedef std::pair<unsigned, unsigned> callsite;
584 :
585 : /* Map from callsite to callee function_instance. */
586 : typedef std::map<callsite, function_instance *> callsite_map;
587 :
588 0 : function_instance (unsigned symbol_name, unsigned file_name,
589 : gcov_type head_count)
590 0 : : descriptor_ (file_name, symbol_name), total_count_ (0),
591 0 : head_count_ (head_count), timestamp_ (0),
592 0 : removed_icall_target_ (false), realized_ (false), in_worklist_ (false),
593 0 : inlined_to_ (NULL), location_ (UNKNOWN_LOCATION),
594 0 : call_location_ (UNKNOWN_LOCATION)
595 : {
596 : }
597 :
598 : /* Map from source location (decl_lineno) to profile (count_info). */
599 : typedef std::map<unsigned, count_info> position_count_map;
600 :
601 : /* The indices into the string table identifying the function_instance. */
602 : function_instance_descriptor descriptor_;
603 :
604 : /* Total sample count. */
605 : gcov_type total_count_;
606 :
607 : /* Entry BB's sample count. */
608 : gcov_type head_count_;
609 :
610 : /* perf timestamp associated with first execution of function, which is
611 : used to compute node->tp_first_run. */
612 : gcov_type timestamp_;
613 :
614 : /* Map from callsite location to callee function_instance. */
615 : callsite_map callsites;
616 :
617 : /* Map from source location to count_info. */
618 : position_count_map pos_counts;
619 :
620 : /* True if function was removed from indir target list. */
621 : bool removed_icall_target_;
622 :
623 : /* True if function exists in IL. I.e. for toplevel instance we
624 : have corresponding symbol and for inline instance we inlined
625 : to it. */
626 : bool realized_;
627 :
628 : /* True if function is in worklist for merging/offlining. */
629 : bool in_worklist_;
630 :
631 : /* Pointer to outer function instance or NULL if this
632 : is a toplevel one. */
633 : function_instance *inlined_to_;
634 :
635 : /* Location of function and its call (in case it is inlined). */
636 : location_t location_, call_location_;
637 :
638 : /* Turn inline instance to offline. */
639 : static bool offline (function_instance *fn,
640 : vec <function_instance *> &new_functions);
641 :
642 : /* Helper routine for prop_timestamp. */
643 : void prop_timestamp_1 (gcov_type timestamp);
644 : };
645 :
646 : /* Profile for all functions. */
647 : class autofdo_source_profile
648 : {
649 : public:
650 : static autofdo_source_profile *
651 0 : create ()
652 : {
653 0 : autofdo_source_profile *map = new autofdo_source_profile ();
654 :
655 0 : if (map->read ())
656 : return map;
657 0 : delete map;
658 0 : return NULL;
659 : }
660 :
661 : ~autofdo_source_profile ();
662 :
663 : /* For a given DECL, returns the top-level function_instance. */
664 : function_instance *get_function_instance_by_decl (tree decl, const char * = NULL) const;
665 :
666 : /* For a given DESCRIPTOR, return the matching instance if found. */
667 : function_instance *
668 : get_function_instance_by_descriptor (function_instance_descriptor) const;
669 :
670 : void add_function_instance (function_instance *);
671 :
672 : /* Find count_info for a given gimple STMT. If found, store the count_info
673 : in INFO and return true; otherwise return false.
674 : NODE can be used to specify particular inline clone. */
675 : bool get_count_info (gimple *stmt, count_info *info,
676 : cgraph_node *node = NULL) const;
677 :
678 : /* Find count_info for a given gimple location GIMPLE_LOC. If found,
679 : store the count_info in INFO and return true; otherwise return false.
680 : NODE can be used to specify particular inline clone. */
681 : bool get_count_info (location_t gimple_loc, count_info *info,
682 : cgraph_node *node = NULL) const;
683 :
684 : /* Find total count of the callee of EDGE. */
685 : gcov_type get_callsite_total_count (struct cgraph_edge *edge) const;
686 :
687 : /* Update value profile INFO for STMT within NODE from the inlined indirect
688 : callsite. Return true if INFO is updated. */
689 : bool update_inlined_ind_target (gcall *stmt, count_info *info,
690 : cgraph_node *node);
691 :
692 : void remove_icall_target (cgraph_edge *e);
693 :
694 : /* Offline all functions not defined in the current translation unit. */
695 : void offline_external_functions ();
696 :
697 : void offline_unrealized_inlines ();
698 :
699 : private:
700 : /* Map from pair of function_instance filename and symbol name (in
701 : string_table) to function_instance. */
702 : typedef std::map<function_instance_descriptor, function_instance *>
703 : name_function_instance_map;
704 :
705 0 : autofdo_source_profile () {}
706 :
707 : /* Read AutoFDO profile and returns TRUE on success. */
708 : bool read ();
709 :
710 : /* Return the function_instance in the profile that correspond to the
711 : inline STACK. */
712 : function_instance *
713 : get_function_instance_by_inline_stack (const inline_stack &stack) const;
714 :
715 : /* Find the matching function instance which has DESCRIPTOR as its
716 : descriptor. If not found, also try checking if an instance exists with the
717 : same name which has no associated filename. */
718 : name_function_instance_map::const_iterator find_iter_for_function_instance (
719 : function_instance_descriptor descriptor) const;
720 :
721 : /* Similar to the above, but return a pointer to the instance instead of an
722 : iterator. */
723 : function_instance *
724 : find_function_instance (function_instance_descriptor descriptor) const;
725 :
726 : /* Remove a function instance from the map. Returns true if the entry was
727 : actually deleted. */
728 : bool remove_function_instance (function_instance *inst);
729 :
730 : name_function_instance_map map_;
731 :
732 : auto_vec <function_instance *> duplicate_functions_;
733 : };
734 :
735 : /* Store the summary information from the GCOV file. */
736 : static summary_info *afdo_summary_info;
737 :
738 : /* Store the strings read from the profile data file. */
739 : static string_table *afdo_string_table;
740 :
741 : /* Store the AutoFDO source profile. */
742 : static autofdo_source_profile *afdo_source_profile;
743 :
744 : /* gcov_summary structure to store the profile_info. */
745 : static gcov_summary *afdo_profile_info;
746 :
747 : /* Map from timestamp -> <name, tp_first_run>.
748 :
749 : The purpose of this map is to map 64-bit timestamp values to (1..N) sorted
750 : by ascending order of timestamps and assign that to node->tp_first_run,
751 : since we don't need the full 64-bit range. */
752 : static std::map<gcov_type, int> timestamp_info_map;
753 :
754 : /* Scaling factor for afdo data. Compared to normal profile
755 : AFDO profile counts are much lower, depending on sampling
756 : frequency. We scale data up to reduce effects of roundoff
757 : errors. */
758 :
759 : static gcov_type afdo_count_scale = 1;
760 :
761 : /* Helper functions. */
762 :
763 : /* Return the original name of NAME: strip the suffix that starts
764 : with '.' for names that are generated after auto-profile pass.
765 : This is to match profiled names with the names in the IR at this stage.
766 : Note that we only have to strip suffix and not in the middle.
767 : Caller is responsible for freeing RET. */
768 :
769 : static char *
770 0 : get_original_name (const char *name, bool alloc = true)
771 : {
772 0 : char *ret = alloc ? xstrdup (name) : const_cast<char *> (name);
773 0 : char *last_dot = strrchr (ret, '.');
774 0 : if (last_dot == NULL)
775 : return ret;
776 0 : bool only_digits = true;
777 : char *ptr = last_dot;
778 0 : while (*(++ptr) != 0)
779 0 : if (*ptr < '0' || *ptr > '9')
780 : {
781 : only_digits = false;
782 : break;
783 : }
784 0 : if (only_digits)
785 0 : *last_dot = 0;
786 0 : char *next_dot = strrchr (ret, '.');
787 : /* if nested function such as foo.0, return foo.0 */
788 0 : if (next_dot == NULL)
789 : {
790 0 : *last_dot = '.';
791 0 : return ret;
792 : }
793 : /* Suffixes of clones that compiler generates after auto-profile. */
794 0 : const char *suffixes[] = {"isra", "constprop", "lto_priv", "part", "cold"};
795 0 : for (unsigned i = 0; i < sizeof (suffixes) / sizeof (const char *); ++i)
796 : {
797 0 : int len = strlen (suffixes[i]);
798 0 : if (len == last_dot - next_dot - 1
799 0 : && strncmp (next_dot + 1, suffixes[i], strlen (suffixes[i])) == 0)
800 : {
801 0 : *next_dot = 0;
802 0 : return get_original_name (ret, false);
803 : }
804 : }
805 : /* Otherwise, it is for clones such as .omp_fn.N that was done before
806 : auto-profile and should be kept as it is. */
807 0 : *last_dot = '.';
808 0 : return ret;
809 : }
810 :
811 : /* Return the combined location, which is a 32bit integer in which
812 : higher 16 bits stores the line offset of LOC to the start lineno
813 : of DECL, The lower 16 bits stores the discriminator. */
814 :
815 : static unsigned
816 0 : get_combined_location (location_t loc, tree decl)
817 : {
818 0 : bool warned = false;
819 : /* TODO: allow more bits for line and less bits for discriminator. */
820 0 : if ((LOCATION_LINE (loc) - DECL_SOURCE_LINE (decl)) >= (1<<15)
821 0 : || (LOCATION_LINE (loc) - DECL_SOURCE_LINE (decl)) <= -(1<<15))
822 0 : warned = warning_at (loc, OPT_Wauto_profile,
823 : "auto-profile cannot encode offset %i "
824 : "that exceeds 16 bytes",
825 0 : LOCATION_LINE (loc) - DECL_SOURCE_LINE (decl));
826 0 : if (warned)
827 0 : inform (DECL_SOURCE_LOCATION (decl), "location offset is related to");
828 0 : if ((unsigned)get_discriminator_from_loc (loc) >= (1u << 16))
829 0 : warning_at (loc, OPT_Wauto_profile,
830 : "auto-profile cannot encode discriminators "
831 : "that exceeds 16 bytes");
832 0 : return ((unsigned)(LOCATION_LINE (loc) - DECL_SOURCE_LINE (decl)) << 16)
833 0 : | get_discriminator_from_loc (loc);
834 : }
835 :
836 : /* Return the function decl of a given lexical BLOCK. */
837 :
838 : static tree
839 0 : get_function_decl_from_block (tree block)
840 : {
841 0 : if (!inlined_function_outer_scope_p (block))
842 : return NULL_TREE;
843 :
844 0 : return BLOCK_ABSTRACT_ORIGIN (block);
845 : }
846 :
847 : /* Dump LOC to F. */
848 :
849 : static void
850 0 : dump_afdo_loc (FILE *f, unsigned loc)
851 : {
852 0 : if (loc & 65535)
853 0 : fprintf (f, "%i.%i", loc >> 16, loc & 65535);
854 : else
855 0 : fprintf (f, "%i", loc >> 16);
856 0 : }
857 :
858 : /* Return assembler name as in symbol table and DW_AT_linkage_name. */
859 :
860 : static const char *
861 0 : raw_symbol_name (const char *asmname)
862 : {
863 : /* If we start supporting user_label_prefixes, add_linkage_attr will also
864 : need to be fixed. */
865 0 : if (strlen (user_label_prefix))
866 0 : sorry ("auto-profile is not supported for targets with user label prefix");
867 0 : return asmname + (asmname[0] == '*');
868 : }
869 :
870 : /* Convenience wrapper that looks up assembler name. */
871 :
872 : static const char *
873 0 : raw_symbol_name (tree decl)
874 : {
875 0 : return raw_symbol_name (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
876 : }
877 :
878 : /* Dump STACK to F. */
879 :
880 : static void
881 0 : dump_inline_stack (FILE *f, inline_stack *stack)
882 : {
883 0 : bool first = true;
884 0 : for (decl_lineno &p : *stack)
885 : {
886 0 : fprintf (f, "%s%s:",
887 : first ? "" : "; ",
888 : raw_symbol_name (p.decl));
889 0 : dump_afdo_loc (f, p.afdo_loc);
890 0 : first = false;
891 : }
892 0 : fprintf (f, "\n");
893 0 : }
894 :
895 : /* Store inline stack for STMT in STACK. */
896 :
897 : static void
898 0 : get_inline_stack (location_t locus, inline_stack *stack,
899 : tree fn = current_function_decl)
900 : {
901 0 : if (LOCATION_LOCUS (locus) == UNKNOWN_LOCATION)
902 : return;
903 :
904 0 : tree block = LOCATION_BLOCK (locus);
905 0 : if (block && TREE_CODE (block) == BLOCK)
906 : {
907 0 : for (block = BLOCK_SUPERCONTEXT (block);
908 0 : block && (TREE_CODE (block) == BLOCK);
909 0 : block = BLOCK_SUPERCONTEXT (block))
910 : {
911 0 : location_t tmp_locus = BLOCK_SOURCE_LOCATION (block);
912 0 : if (LOCATION_LOCUS (tmp_locus) == UNKNOWN_LOCATION)
913 0 : continue;
914 :
915 0 : tree decl = get_function_decl_from_block (block);
916 0 : stack->safe_push (
917 0 : {decl, get_combined_location (locus, decl), locus});
918 0 : locus = tmp_locus;
919 : }
920 : }
921 0 : stack->safe_push ({fn, get_combined_location (locus, fn), locus});
922 : }
923 :
924 : /* Same as get_inline_stack for a given node which may be
925 : an inline clone. If NODE is NULL, assume current_function_decl. */
926 : static void
927 0 : get_inline_stack_in_node (location_t locus, inline_stack *stack,
928 : cgraph_node *node)
929 : {
930 0 : if (!node)
931 0 : return get_inline_stack (locus, stack);
932 0 : do
933 : {
934 0 : get_inline_stack (locus, stack, node->decl);
935 : /* If caller is inlined, continue building stack. */
936 0 : if (!node->inlined_to)
937 : node = NULL;
938 : else
939 : {
940 0 : locus = gimple_location (node->callers->call_stmt);
941 0 : node = node->callers->caller;
942 : }
943 : }
944 0 : while (node);
945 : }
946 :
947 : /* Return combined location of LOCUS within BLOCK that is in
948 : function FN.
949 :
950 : This is a 32bit integer in which higher 16 bits stores the line offset of
951 : LOC to the start lineno of DECL, The lower 16 bits stores the
952 : discriminator. */
953 :
954 : static unsigned
955 0 : get_relative_location_for_locus (tree fn, tree block, location_t locus)
956 : {
957 0 : if (LOCATION_LOCUS (locus) == UNKNOWN_LOCATION)
958 : return -1;
959 :
960 0 : for (; block && (TREE_CODE (block) == BLOCK);
961 0 : block = BLOCK_SUPERCONTEXT (block))
962 0 : if (inlined_function_outer_scope_p (block))
963 0 : return get_combined_location (locus,
964 0 : get_function_decl_from_block (block));
965 0 : return get_combined_location (locus, fn);
966 : }
967 :
968 : /* Return combined location of STMT in function FN. */
969 :
970 : static unsigned
971 0 : get_relative_location_for_stmt (tree fn, gimple *stmt)
972 : {
973 0 : return get_relative_location_for_locus
974 0 : (fn, LOCATION_BLOCK (gimple_location (stmt)),
975 0 : gimple_location (stmt));
976 : }
977 :
978 : /* Return either the basename or the realpath for a given path based on
979 : PARAM_PROFILE_FUNC_INTERNAL_ID. */
980 :
981 : static const char *
982 0 : get_normalized_path (const char *path, bool from_gcov = false)
983 : {
984 0 : if (param_profile_func_internal_id == 1)
985 : /* The GCOV will already contain the entire path. It doesn't need to be
986 : normalized with lrealpath (). */
987 0 : return from_gcov ? path : lrealpath (path);
988 0 : return lbasename (path);
989 : }
990 :
991 : /* Member functions for summary_info. */
992 :
993 : bool
994 0 : summary_info::read ()
995 : {
996 0 : if (gcov_read_unsigned () != GCOV_TAG_AFDO_SUMMARY)
997 : return false;
998 :
999 0 : total_count = gcov_read_counter ();
1000 0 : max_count = gcov_read_counter ();
1001 0 : max_function_count = gcov_read_counter ();
1002 0 : num_counts = gcov_read_counter ();
1003 0 : num_functions = gcov_read_counter ();
1004 0 : uint64_t num_detailed_summaries = gcov_read_counter ();
1005 0 : gcc_checking_assert (num_detailed_summaries == NUM_PERCENTILES);
1006 0 : for (uint64_t i = 0; i < num_detailed_summaries; i++)
1007 : {
1008 0 : detailed_summaries[i].cutoff = gcov_read_unsigned ();
1009 0 : detailed_summaries[i].min_count = gcov_read_counter ();
1010 0 : detailed_summaries[i].num_counts = gcov_read_counter ();
1011 : }
1012 :
1013 0 : return !gcov_is_error ();
1014 : }
1015 :
1016 : /* Get the minimum count required for percentile CUTOFF. */
1017 :
1018 : uint64_t
1019 0 : summary_info::get_threshold_count (uint32_t cutoff)
1020 : {
1021 : /* The cutoffs stored in the GCOV are fractions multiplied by 1,000,000. */
1022 0 : gcc_checking_assert (cutoff <= 1'000'000);
1023 0 : unsigned idx = 0;
1024 : /* Find the first cutoff at least as high as CUTOFF. */
1025 0 : for (; idx < NUM_PERCENTILES; idx++)
1026 0 : if (detailed_summaries[idx].cutoff >= cutoff)
1027 : break;
1028 0 : idx = std::min (NUM_PERCENTILES - 1, idx);
1029 0 : return detailed_summaries[idx].min_count;
1030 : }
1031 :
1032 : /* Member functions for string_table. */
1033 :
1034 : /* Deconstructor. */
1035 :
1036 0 : string_table::~string_table ()
1037 : {
1038 0 : for (unsigned i = 0; i < symbol_names_.length (); i++)
1039 0 : free (const_cast<char *> (symbol_names_[i]));
1040 0 : for (unsigned i = 0; i < filenames_.length (); i++)
1041 0 : free (const_cast<char *> (filenames_[i]));
1042 0 : for (auto it = original_names_map_.begin (); it != original_names_map_.end ();
1043 0 : it++)
1044 0 : free (it->second);
1045 0 : }
1046 :
1047 :
1048 : /* Return the index of a given function NAME. Return -1 if NAME is not
1049 : found in string table. */
1050 :
1051 : int
1052 0 : string_table::get_index (const char *name) const
1053 : {
1054 0 : if (name == NULL)
1055 : return -1;
1056 0 : string_index_map::const_iterator iter = symbol_name_map_.find (name);
1057 0 : if (iter == symbol_name_map_.end ())
1058 : return -1;
1059 :
1060 0 : return iter->second;
1061 : }
1062 :
1063 : /* Return the index of a given function DECL. Return -1 if DECL is not
1064 : found in string table. */
1065 :
1066 : int
1067 0 : string_table::get_index_by_decl (tree decl) const
1068 : {
1069 0 : const char *name = raw_symbol_name (decl);
1070 0 : int ret = get_index (name);
1071 0 : if (ret != -1)
1072 : return ret;
1073 0 : if (DECL_FROM_INLINE (decl))
1074 0 : return get_index_by_decl (DECL_ABSTRACT_ORIGIN (decl));
1075 :
1076 : return -1;
1077 : }
1078 :
1079 : /* Return the function name of a given INDEX. */
1080 :
1081 : const char *
1082 0 : string_table::get_symbol_name (int index) const
1083 : {
1084 0 : if (index <= 0 || index >= (int) symbol_names_.length ())
1085 0 : fatal_error (UNKNOWN_LOCATION,
1086 : "auto-profile contains invalid symbol name index %d", index);
1087 :
1088 0 : return symbol_names_[index];
1089 : }
1090 :
1091 : /* For a given index, returns the string. */
1092 :
1093 : const char *
1094 0 : string_table::get_filename (int index) const
1095 : {
1096 : /* There may not be any file name for some functions, ignore them. */
1097 0 : if (index == string_table::unknown_filename)
1098 : return "<unknown>";
1099 :
1100 0 : if (index < 0 || index >= (int) filenames_.length ())
1101 0 : fatal_error (UNKNOWN_LOCATION,
1102 : "auto-profile contains invalid filename index %d", index);
1103 :
1104 0 : return filenames_[index];
1105 : }
1106 :
1107 : /* For a given symbol name index, returns the filename index. */
1108 :
1109 : int
1110 0 : string_table::get_filename_by_symbol (int index) const
1111 : {
1112 0 : return get_filename_by_symbol (get_symbol_name (index));
1113 : }
1114 :
1115 : /* For a given function name, returns the filename index. */
1116 :
1117 : int
1118 0 : string_table::get_filename_by_symbol (const char *name) const
1119 : {
1120 0 : auto it = symbol_to_filename_map_.find (name);
1121 0 : if (it != symbol_to_filename_map_.end () && it->second < filenames_.length ())
1122 0 : return it->second;
1123 : return string_table::unknown_filename;
1124 : }
1125 :
1126 : /* For a given filename, returns the index. */
1127 :
1128 : int
1129 0 : string_table::get_filename_index (const char *name) const
1130 : {
1131 0 : auto iter = filename_map_.find (name);
1132 0 : return iter == filename_map_.end () ? string_table::unknown_filename
1133 0 : : iter->second;
1134 : }
1135 :
1136 : /* Get the original name and file name index for a node. This will return the
1137 : name from the current TU if there are multiple symbols that map to
1138 : NAME. */
1139 :
1140 : std::pair<const char *, int>
1141 0 : string_table::get_original_name (const char *name) const
1142 : {
1143 : /* Check if the un-prefixed name differs from the actual name. */
1144 0 : auto stripped = original_names_map_.find (name);
1145 :
1146 : /* The original name for the symbol is its name, i.e. there are no
1147 : suffixes. */
1148 0 : if (stripped == original_names_map_.end ())
1149 0 : return {name, get_filename_by_symbol (name)};
1150 :
1151 : /* Figure out if a clash exists. */
1152 0 : auto clash = clashing_names_map_.find (stripped->second);
1153 0 : gcc_checking_assert (clash != clashing_names_map_.end ());
1154 :
1155 : /* Try to find a function from the current TU. */
1156 0 : gcc_checking_assert (clash->second.length () >= 1);
1157 0 : symtab_node *n
1158 0 : = cgraph_node::get_for_asmname (get_identifier (stripped->second));
1159 0 : if (n && is_a<cgraph_node *> (n))
1160 0 : for (cgraph_node *cn = dyn_cast<cgraph_node *> (n); cn;)
1161 : {
1162 : /* Check if there is a symbol in the current TU that has the same name
1163 : as in the GCOV. */
1164 0 : for (auto name : clash->second)
1165 : {
1166 0 : int filename_idx = get_filename_by_symbol (name);
1167 0 : if (cn->definition && cn->has_gimple_body_p ()
1168 0 : && !strcmp (get_normalized_path (DECL_SOURCE_FILE (cn->decl)),
1169 : get_filename (filename_idx)))
1170 0 : return {stripped->second, filename_idx};
1171 : }
1172 0 : cn = dyn_cast<cgraph_node *> (cn->next_sharing_asm_name);
1173 : }
1174 :
1175 : /* No match found. Just stick to the current symbol and return the stripped
1176 : name. */
1177 0 : return {stripped->second, get_filename_by_symbol (name)};
1178 : }
1179 :
1180 : /* Add new symbol name STRING (with an associated file name FILENAME_IDX) and
1181 : return its index. */
1182 :
1183 : int
1184 0 : string_table::add_symbol_name (const char *string, int filename_idx)
1185 : {
1186 0 : gcc_checking_assert (
1187 : filename_idx == string_table::unknown_filename
1188 : || (filename_idx >= 0 && filename_idx < (int) filenames_.length ()));
1189 0 : symbol_names_.safe_push (string);
1190 0 : symbol_name_map_[symbol_names_.last ()] = symbol_names_.length () - 1;
1191 0 : symbol_to_filename_map_[symbol_names_.last ()] = filename_idx;
1192 0 : return symbol_names_.length () - 1;
1193 : }
1194 :
1195 : /* Add new filename and return its index (returning the same if it already
1196 : exists). */
1197 :
1198 : int
1199 0 : string_table::add_filename (const char *name)
1200 : {
1201 0 : auto it = filename_map_.find (name);
1202 0 : if (it != filename_map_.end ())
1203 0 : return it->second;
1204 0 : filenames_.safe_push (xstrdup (name));
1205 0 : return filenames_.length () - 1;
1206 : }
1207 :
1208 : /* Read the string table. Return TRUE if reading is successful. */
1209 :
1210 : bool
1211 0 : string_table::read ()
1212 : {
1213 0 : if (gcov_read_unsigned () != GCOV_TAG_AFDO_FILE_NAMES)
1214 : return false;
1215 : /* Skip the length of the section. */
1216 0 : gcov_read_unsigned ();
1217 : /* Read in the file name table. */
1218 0 : unsigned file_num = gcov_read_unsigned ();
1219 0 : filenames_.reserve (file_num);
1220 0 : for (unsigned i = 0; i < file_num; i++)
1221 : {
1222 0 : const char *filename = gcov_read_string ();
1223 0 : filenames_.quick_push (xstrdup (get_normalized_path (filename, true)));
1224 0 : filename_map_[filenames_.last ()] = i;
1225 0 : free (const_cast<char *> (filename));
1226 0 : if (gcov_is_error ())
1227 : return false;
1228 : }
1229 : /* Read in the function name -> file name table. */
1230 0 : unsigned string_num = gcov_read_unsigned ();
1231 0 : symbol_names_.reserve (string_num);
1232 0 : for (unsigned i = 0; i < string_num; i++)
1233 : {
1234 0 : symbol_names_.quick_push (const_cast<char *> (gcov_read_string ()));
1235 0 : symbol_name_map_[symbol_names_.last ()] = i;
1236 0 : unsigned filename_idx = gcov_read_unsigned ();
1237 0 : symbol_to_filename_map_[symbol_names_.last ()] = filename_idx;
1238 0 : char *original = const_cast<char *> (
1239 0 : autofdo::get_original_name (symbol_names_.last ()));
1240 0 : if (strcmp (original, symbol_names_.last ()))
1241 : {
1242 : /* Take ownership of ORIGINAL. */
1243 0 : original_names_map_[symbol_names_.last ()] = original;
1244 0 : clashing_names_map_[original].safe_push (i);
1245 : /* It is possible that a public symbol with the stripped name exists.
1246 : If it does exist, add it as well. */
1247 0 : auto publik = symbol_name_map_.find (original);
1248 0 : if (publik != symbol_name_map_.end ()
1249 0 : && clashing_names_map_.find (publik->first)
1250 0 : == clashing_names_map_.end ())
1251 0 : clashing_names_map_[publik->first].safe_push (publik->second);
1252 : }
1253 : else
1254 : /* There are no suffixes to remove. */
1255 0 : free (original);
1256 :
1257 0 : if (gcov_is_error ())
1258 0 : return false;
1259 : }
1260 0 : return true;
1261 : }
1262 :
1263 : /* Return cgraph node corresponding to given NAME_INDEX,
1264 : NULL if unavailable. */
1265 : cgraph_node *
1266 0 : string_table::get_cgraph_node (int name_index)
1267 : {
1268 0 : const char *sname = get_symbol_name (name_index);
1269 :
1270 0 : symtab_node *n = cgraph_node::get_for_asmname (get_identifier (sname));
1271 0 : for (;n; n = n->next_sharing_asm_name)
1272 0 : if (cgraph_node *cn = dyn_cast <cgraph_node *> (n))
1273 0 : if (cn->definition && cn->has_gimple_body_p ())
1274 : return cn;
1275 : return NULL;
1276 : }
1277 :
1278 : /* Return corresponding cgraph node. */
1279 :
1280 : cgraph_node *
1281 0 : function_instance::get_cgraph_node ()
1282 : {
1283 0 : return afdo_string_table->get_cgraph_node (symbol_name ());
1284 : }
1285 :
1286 : /* Member functions for function_instance. */
1287 :
1288 0 : function_instance::~function_instance ()
1289 : {
1290 0 : gcc_assert (!in_worklist_p ());
1291 0 : for (callsite_map::iterator iter = callsites.begin ();
1292 0 : iter != callsites.end (); ++iter)
1293 0 : delete iter->second;
1294 0 : }
1295 :
1296 : /* Propagate timestamp TS of function_instance to inlined instances if it's
1297 : not already set. */
1298 :
1299 : void
1300 0 : function_instance::prop_timestamp_1 (gcov_type ts)
1301 : {
1302 0 : if (!timestamp () && total_count () > 0)
1303 0 : set_timestamp (ts);
1304 0 : for (auto it = callsites.begin (); it != callsites.end (); ++it)
1305 0 : it->second->prop_timestamp_1 (ts);
1306 0 : }
1307 :
1308 : void
1309 0 : function_instance::prop_timestamp (void)
1310 : {
1311 0 : prop_timestamp_1 (timestamp ());
1312 0 : }
1313 :
1314 : /* Traverse callsites of the current function_instance to find one at the
1315 : location of LINENO and callee name represented in DECL. */
1316 :
1317 : function_instance *
1318 0 : function_instance::get_function_instance_by_decl (unsigned lineno,
1319 : tree decl,
1320 : location_t location) const
1321 : {
1322 0 : int func_name_idx = afdo_string_table->get_index_by_decl (decl);
1323 0 : if (func_name_idx != -1)
1324 : {
1325 0 : callsite_map::const_iterator ret
1326 0 : = callsites.find (std::make_pair (lineno, func_name_idx));
1327 0 : if (ret != callsites.end ())
1328 0 : return ret->second;
1329 : }
1330 0 : if (DECL_FROM_INLINE (decl))
1331 : {
1332 0 : function_instance
1333 0 : *ret = get_function_instance_by_decl (lineno,
1334 0 : DECL_ABSTRACT_ORIGIN (decl),
1335 : location);
1336 0 : return ret;
1337 : }
1338 0 : if (dump_enabled_p ())
1339 : {
1340 0 : for (auto const &iter : callsites)
1341 0 : if (iter.first.first == lineno)
1342 0 : dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS,
1343 0 : dump_user_location_t::from_location_t (location),
1344 : "auto-profile has mismatched function name %s"
1345 : " instead of %s at loc %i:%i",
1346 : afdo_string_table->get_symbol_name (
1347 0 : iter.first.second),
1348 : raw_symbol_name (decl), lineno >> 16,
1349 : lineno & 65535);
1350 : }
1351 :
1352 : return NULL;
1353 : }
1354 :
1355 : /* Merge profile of OTHER to THIS. Note that cloning hasn't been performed
1356 : when we annotate the CFG (at this stage). */
1357 :
1358 : void
1359 0 : function_instance::merge (function_instance *other,
1360 : vec <function_instance *> &new_functions)
1361 : {
1362 : /* Do not merge to itself and only merge functions of same name. */
1363 0 : gcc_checking_assert (other != this
1364 : && other->symbol_name () == symbol_name ());
1365 :
1366 0 : if (file_name () != other->file_name ())
1367 : return;
1368 :
1369 0 : total_count_ += other->total_count_;
1370 0 : if (other->total_count () && total_count () && other->head_count () == -1)
1371 0 : head_count_ = -1;
1372 0 : else if (head_count_ != -1)
1373 0 : head_count_ += other->head_count_;
1374 :
1375 : /* While merging timestamps, set the one that occurs earlier. */
1376 0 : if (other->timestamp () < timestamp ())
1377 0 : set_timestamp (other->timestamp ());
1378 :
1379 : bool changed = true;
1380 :
1381 0 : while (changed)
1382 : {
1383 0 : changed = false;
1384 : /* If both function instances agree on particular inlined function,
1385 : merge profiles. Otherwise offline the instance. */
1386 0 : for (callsite_map::const_iterator iter = other->callsites.begin ();
1387 0 : iter != other->callsites.end ();)
1388 0 : if (callsites.count (iter->first) == 0)
1389 : {
1390 0 : function_instance *f = iter->second;
1391 0 : if (dump_file)
1392 : {
1393 0 : fprintf (dump_file, " Mismatch in inlined functions;"
1394 : " offlining in merge source:");
1395 0 : f->dump_inline_stack (dump_file);
1396 0 : fprintf (dump_file, "\n");
1397 : }
1398 : /* We already merged outer part of the function accounting
1399 : the inlined call; compensate. */
1400 0 : for (function_instance *s = this; s; s = s->inlined_to ())
1401 : {
1402 0 : s->total_count_ -= f->total_count ();
1403 0 : gcc_checking_assert (s->total_count_ >= 0);
1404 : }
1405 0 : other->callsites.erase (iter);
1406 0 : function_instance::offline (f, new_functions);
1407 : /* Start from beginning as merging might have offlined
1408 : some functions in the case of recursive inlining. */
1409 0 : iter = other->callsites.begin ();
1410 : }
1411 : else
1412 0 : ++iter;
1413 0 : for (callsite_map::const_iterator iter = callsites.begin ();
1414 0 : iter != callsites.end ();)
1415 0 : if (other->callsites.count (iter->first) == 0)
1416 : {
1417 0 : function_instance *f = iter->second;
1418 0 : if (dump_file)
1419 : {
1420 0 : fprintf (dump_file, " Mismatch in inlined functions;"
1421 : " offlining in merge destination:");
1422 0 : f->dump_inline_stack (dump_file);
1423 0 : fprintf (dump_file, "\n");
1424 : }
1425 0 : callsites.erase (iter);
1426 0 : function_instance::offline (f, new_functions);
1427 0 : iter = callsites.begin ();
1428 0 : changed = true;
1429 : }
1430 : else
1431 0 : ++iter;
1432 : }
1433 0 : for (callsite_map::const_iterator iter = other->callsites.begin ();
1434 0 : iter != other->callsites.end (); ++iter)
1435 : {
1436 0 : if (dump_file)
1437 : {
1438 0 : fprintf (dump_file, " Merging profile for inlined function\n"
1439 : " from: ");
1440 0 : iter->second->dump_inline_stack (dump_file);
1441 0 : fprintf (dump_file, " total:%" PRIu64 "\n to : ",
1442 0 : (int64_t)iter->second->total_count ());
1443 0 : callsites[iter->first]->dump_inline_stack (dump_file);
1444 0 : fprintf (dump_file, " total:%" PRIu64 "\n",
1445 0 : (int64_t)callsites[iter->first]->total_count ());
1446 : }
1447 :
1448 0 : callsites[iter->first]->merge (iter->second, new_functions);
1449 : }
1450 :
1451 0 : for (position_count_map::const_iterator iter = other->pos_counts.begin ();
1452 0 : iter != other->pos_counts.end (); ++iter)
1453 0 : if (pos_counts.count (iter->first) == 0)
1454 0 : pos_counts[iter->first] = iter->second;
1455 : else
1456 : {
1457 0 : pos_counts[iter->first].count += iter->second.count;
1458 0 : for (icall_target_map::const_iterator titer
1459 0 : = iter->second.targets.begin ();
1460 0 : titer != iter->second.targets.end (); ++titer)
1461 0 : if (pos_counts[iter->first].targets.count (titer->first) == 0)
1462 0 : pos_counts[iter->first].targets[titer->first]
1463 0 : = titer->second;
1464 : else
1465 0 : pos_counts[iter->first].targets[titer->first]
1466 0 : += titer->second;
1467 : }
1468 : }
1469 :
1470 : /* Make inline function FN offline.
1471 : If toplevel function of same name already exists, then merge profiles.
1472 : Otherwise turn FN toplevel. Return true if new toplevel function
1473 : was introduced.
1474 : If new toplevel functions are created and NEW_FUNCTIONS != NULL,
1475 : add them to NEW_FUNCTIONS.
1476 :
1477 : TODO: When offlining indirect call we lose information about the
1478 : call target. It should be possible to add it into
1479 : targets histogram. */
1480 :
1481 : bool
1482 0 : function_instance::offline (function_instance *fn,
1483 : vec <function_instance *> &new_functions)
1484 : {
1485 0 : gcc_checking_assert (fn->inlined_to ());
1486 0 : for (function_instance *s = fn->inlined_to (); s; s = s->inlined_to ())
1487 : {
1488 0 : s->total_count_ -= fn->total_count ();
1489 0 : gcc_checking_assert (s->total_count_ >= 0);
1490 : }
1491 0 : function_instance *to
1492 0 : = afdo_source_profile->get_function_instance_by_descriptor (
1493 : fn->get_descriptor ());
1494 0 : fn->set_inlined_to (NULL);
1495 : /* If there is offline function of same name, we need to merge profile.
1496 : Delay this by adding function to a worklist so we do not run into
1497 : problem with recursive inlining. */
1498 0 : if (to)
1499 : {
1500 0 : if (fn->in_worklist_p ())
1501 : return false;
1502 0 : fn->set_in_worklist ();
1503 0 : new_functions.safe_push (fn);
1504 0 : if (dump_file)
1505 : {
1506 0 : fprintf (dump_file, " Recoding duplicate: ");
1507 0 : to->dump_inline_stack (dump_file);
1508 0 : fprintf (dump_file, "\n");
1509 : }
1510 0 : return true;
1511 : }
1512 0 : if (dump_file)
1513 : {
1514 0 : fprintf (dump_file, " Added as offline instance: ");
1515 0 : fn->dump_inline_stack (dump_file);
1516 0 : fprintf (dump_file, "\n");
1517 : }
1518 0 : if (fn->total_count ())
1519 0 : fn->head_count_ = -1;
1520 0 : afdo_source_profile->add_function_instance (fn);
1521 0 : fn->set_in_worklist ();
1522 0 : new_functions.safe_push (fn);
1523 0 : return true;
1524 : }
1525 :
1526 : /* Offline all inlined functions with name in SEEN.
1527 : If new toplevel functions are created, add them to NEW_FUNCTIONS. */
1528 :
1529 : void
1530 0 : function_instance::offline_if_in_set (name_index_set &seen,
1531 : vec <function_instance *> &new_functions)
1532 : {
1533 0 : for (callsite_map::const_iterator iter = callsites.begin ();
1534 0 : iter != callsites.end ();)
1535 0 : if (seen.contains (iter->first.second))
1536 : {
1537 0 : function_instance *f = iter->second;
1538 0 : if (dump_file)
1539 : {
1540 0 : fprintf (dump_file, "Offlining function inlined to other module: ");
1541 0 : f->dump_inline_stack (dump_file);
1542 0 : fprintf (dump_file, "\n");
1543 : }
1544 0 : iter = callsites.erase (iter);
1545 0 : function_instance::offline (f, new_functions);
1546 : /* Start from beginning as merging might have offlined
1547 : some functions in the case of recursive inlining. */
1548 0 : iter = callsites.begin ();
1549 : }
1550 : else
1551 : {
1552 0 : iter->second->offline_if_in_set (seen, new_functions);
1553 0 : ++iter;
1554 : }
1555 0 : }
1556 :
1557 : /* Try to check if inlined_fn can correspond to a call of function N.
1558 : Return non-zero if it corresponds and 2 if renaming was done. */
1559 :
1560 : static int
1561 0 : match_with_target (cgraph_node *n,
1562 : gimple *stmt,
1563 : function_instance *inlined_fn,
1564 : cgraph_node *orig_callee)
1565 : {
1566 0 : cgraph_node *callee = orig_callee->ultimate_alias_target ();
1567 0 : const char *symbol_name = raw_symbol_name (callee->decl);
1568 0 : const char *name
1569 0 : = afdo_string_table->get_symbol_name (inlined_fn->symbol_name ());
1570 0 : if (strcmp (name, symbol_name))
1571 : {
1572 0 : int i;
1573 0 : bool in_suffix = false;
1574 0 : for (i = 0; i; i++)
1575 : {
1576 : if (name[i] != symbol_name[i])
1577 : break;
1578 : if (name[i] == '.')
1579 : in_suffix = true;
1580 : }
1581 : /* Accept dwarf names and stripped suffixes. */
1582 0 : if (!strcmp (lang_hooks.dwarf_name (callee->decl, 0),
1583 : afdo_string_table->get_symbol_name (
1584 : inlined_fn->symbol_name ()))
1585 0 : || (!name[i] && symbol_name[i] == '.') || in_suffix)
1586 : {
1587 0 : int index = afdo_string_table->get_index (symbol_name);
1588 0 : if (index == -1)
1589 0 : index = afdo_string_table->add_symbol_name (
1590 0 : xstrdup (symbol_name),
1591 : afdo_string_table->add_filename (
1592 0 : get_normalized_path (DECL_SOURCE_FILE (callee->decl))));
1593 0 : if (dump_file)
1594 0 : fprintf (dump_file,
1595 : " Renaming inlined call target %s to %s\n",
1596 : name, symbol_name);
1597 0 : inlined_fn->set_symbol_name (index);
1598 0 : return 2;
1599 : }
1600 : /* Only warn about declarations. It is possible that the function
1601 : is declared as alias in other module and we inlined cross-module. */
1602 0 : if (callee->definition
1603 0 : && warning (OPT_Wauto_profile,
1604 : "auto-profile of %q+F contains inlined "
1605 : "function with symbol name %s instead of symbol name %s",
1606 : n->decl, name, symbol_name))
1607 0 : inform (gimple_location (stmt), "corresponding call");
1608 0 : return 0;
1609 : }
1610 : return 1;
1611 : }
1612 :
1613 : static void
1614 0 : dump_stmt (gimple *stmt, count_info *info, function_instance *inlined_fn,
1615 : inline_stack &stack)
1616 : {
1617 0 : if (dump_file)
1618 : {
1619 0 : fprintf (dump_file, " ");
1620 0 : if (!stack.length ())
1621 0 : fprintf (dump_file, " ");
1622 : else
1623 : {
1624 0 : gcc_checking_assert (stack.length () == 1);
1625 0 : fprintf (dump_file, "%5i", stack[0].afdo_loc >> 16);
1626 0 : if (stack[0].afdo_loc & 65535)
1627 0 : fprintf (dump_file, ".%-5i", stack[0].afdo_loc & 65535);
1628 : else
1629 0 : fprintf (dump_file, " ");
1630 0 : if (info)
1631 0 : fprintf (dump_file, "%9" PRIu64 " ", (int64_t)info->count);
1632 0 : else if (inlined_fn)
1633 0 : fprintf (dump_file, " inlined ");
1634 : else
1635 0 : fprintf (dump_file, " no info ");
1636 : }
1637 0 : print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
1638 : }
1639 0 : }
1640 :
1641 : /* Lookup count and warn about duplicates. */
1642 : count_info *
1643 0 : function_instance::lookup_count (location_t loc, inline_stack &stack,
1644 : cgraph_node *node)
1645 : {
1646 0 : gcc_checking_assert (stack.length () < 2);
1647 0 : if (stack.length ())
1648 : {
1649 0 : int c = pos_counts.count (stack[0].afdo_loc);
1650 0 : if (c > 1
1651 : && warning (OPT_Wauto_profile,
1652 : "duplicated count information"
1653 : " in auto-profile of %q+F"
1654 : " with relative location %i discriminator %i",
1655 : node->decl, stack[0].afdo_loc >> 16,
1656 : stack[0].afdo_loc & 65535))
1657 : inform (loc, "corresponding source location");
1658 0 : if (c)
1659 0 : return &pos_counts[stack[0].afdo_loc];
1660 : }
1661 : return NULL;
1662 : }
1663 :
1664 : /* Mark expr locations as used. */
1665 : void
1666 0 : mark_expr_locations (function_instance *f, tree t, cgraph_node *node,
1667 : hash_set<const count_info *> &counts)
1668 : {
1669 0 : inline_stack stack;
1670 0 : return;
1671 : if (!t)
1672 : return;
1673 : do
1674 : {
1675 : get_inline_stack_in_node (EXPR_LOCATION (t), &stack, node);
1676 : /* FIXME: EXPR_LOCATION does not always originate from current
1677 : function. */
1678 : if (stack.length () > 1)
1679 : break;
1680 : count_info *info = f->lookup_count (EXPR_LOCATION (t), stack, node);
1681 : if (info)
1682 : counts.add (info);
1683 : if (handled_component_p (t))
1684 : t = TREE_OPERAND (t, 0);
1685 : else
1686 : break;
1687 : }
1688 : while (true);
1689 0 : }
1690 :
1691 : /* Match function instance with gimple body.
1692 : Report mismatches, attempt to fix them if possible and remove data we will
1693 : not use.
1694 :
1695 : Set location and call_location so we can output diagnostics and know what
1696 : functions was already matched. */
1697 :
1698 : bool
1699 0 : function_instance::match (cgraph_node *node,
1700 : vec <function_instance *> &new_functions,
1701 : name_index_map &to_symbol_name)
1702 : {
1703 0 : if (get_location () != UNKNOWN_LOCATION)
1704 : return false;
1705 0 : set_location (DECL_SOURCE_LOCATION (node->decl));
1706 0 : if (dump_file)
1707 : {
1708 0 : fprintf (dump_file,
1709 : "\nMatching gimple function %s with auto profile: ",
1710 : node->dump_name ());
1711 0 : dump_inline_stack (dump_file);
1712 0 : fprintf (dump_file, "\n");
1713 : }
1714 0 : basic_block bb;
1715 : /* Sets used to track if entires in auto-profile are useful. */
1716 0 : hash_set<const count_info *> counts;
1717 0 : hash_set<const count_info *> targets;
1718 0 : hash_set<const function_instance *> functions;
1719 0 : hash_set<const function_instance *> functions_to_offline;
1720 :
1721 : /* We try to fill in lost disciminator if there is unique call
1722 : with given line number. This map is used to record them. */
1723 0 : hash_map<int_hash <int, -1, -2>,auto_vec <gcall *>> lineno_to_call;
1724 0 : bool lineno_to_call_computed = false;
1725 :
1726 0 : for (tree arg = DECL_ARGUMENTS (node->decl); arg; arg = DECL_CHAIN (arg))
1727 : {
1728 0 : inline_stack stack;
1729 :
1730 0 : get_inline_stack_in_node (DECL_SOURCE_LOCATION (arg), &stack, node);
1731 0 : count_info *info = lookup_count (DECL_SOURCE_LOCATION (arg), stack, node);
1732 0 : if (stack.length () && dump_file)
1733 : {
1734 0 : gcc_checking_assert (stack.length () == 1);
1735 0 : fprintf (dump_file, "%5i", stack[0].afdo_loc >> 16);
1736 0 : if (stack[0].afdo_loc & 65535)
1737 0 : fprintf (dump_file, " .%-5i arg", stack[0].afdo_loc & 65535);
1738 : else
1739 0 : fprintf (dump_file, " arg ");
1740 0 : print_generic_expr (dump_file, arg);
1741 0 : fprintf (dump_file, "\n");
1742 : }
1743 0 : if (info)
1744 0 : counts.add (info);
1745 0 : }
1746 0 : FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
1747 : {
1748 0 : if (dump_file)
1749 0 : fprintf (dump_file, " basic block %i\n", bb->index);
1750 0 : for (gphi_iterator gpi = gsi_start_phis (bb);
1751 0 : !gsi_end_p (gpi);
1752 0 : gsi_next (&gpi))
1753 : {
1754 0 : gphi *phi = gpi.phi ();
1755 0 : inline_stack stack;
1756 :
1757 : /* We do not assign discriminators to PHI nodes.
1758 : In case we every start using them, we wil need to
1759 : update tree-cfg.cc::assign_discriminators. */
1760 0 : gcc_assert (gimple_location (phi) == UNKNOWN_LOCATION);
1761 0 : get_inline_stack_in_node (gimple_location (phi), &stack, node);
1762 0 : count_info *info = lookup_count (gimple_location (phi), stack, node);
1763 0 : gcc_assert (!info);
1764 0 : dump_stmt (phi, info, NULL, stack);
1765 0 : counts.add (info);
1766 0 : for (edge e : bb->succs)
1767 : {
1768 0 : location_t phi_loc
1769 0 : = gimple_phi_arg_location_from_edge (phi, e);
1770 0 : inline_stack stack;
1771 0 : get_inline_stack_in_node (phi_loc, &stack, node);
1772 0 : count_info *info = lookup_count (phi_loc, stack, node);
1773 0 : if (info)
1774 0 : counts.add (info);
1775 0 : gcc_checking_assert (stack.length () < 2);
1776 0 : mark_expr_locations (this,
1777 : gimple_phi_arg_def_from_edge (phi, e),
1778 : node, counts);
1779 0 : }
1780 0 : }
1781 : /* TODO: goto locuses are not used for BB annotation. */
1782 0 : for (edge e : bb->succs)
1783 : {
1784 0 : inline_stack stack;
1785 0 : get_inline_stack_in_node (e->goto_locus, &stack, node);
1786 0 : count_info *info = lookup_count (e->goto_locus, stack, node);
1787 0 : if (info)
1788 0 : counts.add (info);
1789 0 : }
1790 0 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
1791 0 : !gsi_end_p (gsi); gsi_next (&gsi))
1792 : {
1793 0 : inline_stack stack;
1794 0 : gimple *stmt = gsi_stmt (gsi);
1795 0 : get_inline_stack_in_node (gimple_location (stmt), &stack, node);
1796 :
1797 0 : count_info *info = lookup_count (gimple_location (stmt), stack, node);
1798 0 : if (info)
1799 0 : counts.add (info);
1800 0 : for (unsigned int op = 0; op < gimple_num_ops (stmt); op++)
1801 0 : mark_expr_locations (this, gimple_op (stmt, op), node, counts);
1802 0 : if (gimple_code (stmt) == GIMPLE_CALL)
1803 : {
1804 0 : function_instance *inlined_fn = NULL;
1805 0 : function_instance *inlined_fn_nodisc = NULL;
1806 : /* Lookup callsite. */
1807 0 : if (stack.length ())
1808 : {
1809 0 : int c = 0;
1810 0 : int cnodis = 0;
1811 0 : for (auto const &iter : callsites)
1812 0 : if (iter.first.first == stack[0].afdo_loc)
1813 : {
1814 0 : if (!c)
1815 0 : inlined_fn = iter.second;
1816 0 : c++;
1817 : }
1818 : /* Discriminators are sometimes lost; try to find the
1819 : call without discriminator info. */
1820 0 : else if (iter.first.first == (stack[0].afdo_loc & ~65535))
1821 : {
1822 0 : if (!cnodis)
1823 0 : inlined_fn_nodisc = iter.second;
1824 0 : cnodis++;
1825 : }
1826 0 : if ((c > 1 || (!c && cnodis > 1))
1827 0 : && warning (OPT_Wauto_profile,
1828 : "duplicated callsite in auto-profile of %q+F"
1829 : " with relative location %i,"
1830 : " discriminator %i",
1831 0 : node->decl, stack[0].afdo_loc >> 16,
1832 0 : stack[0].afdo_loc & 65535))
1833 0 : inform (gimple_location (stmt), "corresponding call");
1834 0 : if (inlined_fn && info && info->targets.size ()
1835 0 : && warning (OPT_Wauto_profile,
1836 : "both call targets and inline callsite"
1837 : " information is present in auto-profile"
1838 : " of function %q+F with relative location"
1839 : " %i, discriminator %i",
1840 0 : node->decl, stack[0].afdo_loc >> 16,
1841 0 : stack[0].afdo_loc & 65535))
1842 0 : inform (gimple_location (stmt), "corresponding call");
1843 0 : tree callee = gimple_call_fndecl (stmt);
1844 0 : cgraph_node *callee_node;
1845 0 : unsigned int loc = stack[0].afdo_loc;
1846 0 : bool lost_discriminator = false;
1847 0 : if (!inlined_fn && inlined_fn_nodisc)
1848 : {
1849 0 : if (!lineno_to_call_computed)
1850 : {
1851 0 : basic_block bb2;
1852 0 : FOR_EACH_BB_FN (bb2,
1853 : DECL_STRUCT_FUNCTION (node->decl))
1854 0 : for (gimple_stmt_iterator gsi2
1855 0 : = gsi_start_bb (bb2);
1856 0 : !gsi_end_p (gsi2); gsi_next (&gsi2))
1857 0 : if (gcall *call
1858 0 : = dyn_cast <gcall *> (gsi_stmt (gsi2)))
1859 : {
1860 0 : inline_stack stack2;
1861 0 : get_inline_stack_in_node
1862 0 : (gimple_location (call),
1863 : &stack2, node);
1864 0 : if (stack2.length ())
1865 0 : lineno_to_call.get_or_insert
1866 0 : (stack2[0].afdo_loc >> 16).safe_push (call);
1867 0 : }
1868 : lineno_to_call_computed = true;
1869 : }
1870 : /* If we can determine lost discriminator uniquely,
1871 : use it. */
1872 0 : if (lineno_to_call.get
1873 0 : (stack[0].afdo_loc >> 16)->length () == 1)
1874 : {
1875 0 : if (warning (OPT_Wauto_profile,
1876 : "auto-profile of %q+F seem to contain"
1877 : " lost discriminator %i for"
1878 : " call of %s at relative location %i",
1879 : node->decl, loc & 65535,
1880 : afdo_string_table->get_symbol_name (
1881 : inlined_fn_nodisc->symbol_name ()),
1882 : loc >> 16))
1883 0 : inform (gimple_location (stmt),
1884 : "corresponding call");
1885 0 : inlined_fn = inlined_fn_nodisc;
1886 0 : if (dump_file)
1887 0 : fprintf (dump_file, " Lost discriminator %i\n",
1888 : loc & 65535);
1889 0 : loc = loc & ~65535;
1890 : }
1891 : lost_discriminator = true;
1892 : }
1893 0 : if (callee && (callee_node = cgraph_node::get (callee)))
1894 : {
1895 0 : if (inlined_fn)
1896 : {
1897 0 : int old_name = inlined_fn->symbol_name ();
1898 0 : int r = match_with_target (node, stmt, inlined_fn,
1899 : callee_node);
1900 0 : if (r == 2)
1901 : {
1902 0 : auto iter = callsites.find ({loc, old_name});
1903 0 : gcc_checking_assert (
1904 : old_name != inlined_fn->symbol_name ()
1905 : && iter != callsites.end ()
1906 : && iter->second == inlined_fn);
1907 0 : callsite key2 = {stack[0].afdo_loc,
1908 0 : inlined_fn->symbol_name ()};
1909 0 : callsites.erase (iter);
1910 0 : callsites[key2] = inlined_fn;
1911 : }
1912 0 : if (r)
1913 0 : functions.add (inlined_fn);
1914 : else
1915 0 : functions_to_offline.add (inlined_fn);
1916 : }
1917 :
1918 0 : if (info && info->targets.size () > 1)
1919 0 : warning_at (gimple_location (stmt), OPT_Wauto_profile,
1920 : "auto-profile of %q+F contains multiple"
1921 : " targets for a direct call with relative"
1922 : " location %i, discriminator %i",
1923 0 : node->decl, stack[0].afdo_loc >> 16,
1924 0 : stack[0].afdo_loc & 65535);
1925 : /* We do not need target profile for direct calls. */
1926 0 : if (info)
1927 0 : info->targets.clear ();
1928 : }
1929 : else
1930 : {
1931 0 : if (inlined_fn
1932 0 : && inlined_fn->get_call_location ()
1933 : != UNKNOWN_LOCATION)
1934 : {
1935 0 : if (warning (OPT_Wauto_profile,
1936 : "function contains two calls of the same"
1937 : " relative location +%i,"
1938 : " discriminator %i,"
1939 : " that leads to lost auto-profile",
1940 : loc >> 16,
1941 : loc & 65535))
1942 : {
1943 0 : inform (gimple_location (stmt),
1944 : "location of the first call");
1945 0 : inform (inlined_fn->get_call_location (),
1946 : "location of the second call");
1947 : }
1948 0 : if (dump_file)
1949 0 : fprintf (dump_file,
1950 : " Duplicated call location\n");
1951 0 : inlined_fn = NULL;
1952 : }
1953 0 : if (inlined_fn)
1954 : {
1955 0 : inlined_fn->set_call_location
1956 0 : (gimple_location (stmt));
1957 : /* Do renaming if needed so we can look up
1958 : cgraph node and recurse into inlined function. */
1959 0 : int *newn
1960 0 : = to_symbol_name.get (inlined_fn->symbol_name ());
1961 0 : gcc_checking_assert (
1962 : !newn || *newn != inlined_fn->symbol_name ());
1963 0 : if (newn || lost_discriminator)
1964 : {
1965 0 : auto iter = callsites.find (
1966 0 : {loc, inlined_fn->symbol_name ()});
1967 0 : gcc_checking_assert (iter != callsites.end ()
1968 : && iter->second
1969 : == inlined_fn);
1970 0 : callsite key2
1971 0 : = {stack[0].afdo_loc,
1972 0 : newn ? *newn : inlined_fn->symbol_name ()};
1973 0 : callsites.erase (iter);
1974 0 : callsites[key2] = inlined_fn;
1975 0 : inlined_fn->set_symbol_name (
1976 0 : newn ? *newn : inlined_fn->symbol_name ());
1977 : }
1978 0 : functions.add (inlined_fn);
1979 : }
1980 0 : if (info)
1981 0 : targets.add (info);
1982 : }
1983 : }
1984 0 : dump_stmt (stmt, info, inlined_fn, stack);
1985 : }
1986 : else
1987 0 : dump_stmt (stmt, info, NULL, stack);
1988 0 : }
1989 : }
1990 0 : bool warned = false;
1991 0 : for (auto &iter : pos_counts)
1992 0 : if (iter.second.targets.size ()
1993 0 : && counts.contains (&iter.second)
1994 0 : && !targets.contains (&iter.second))
1995 : {
1996 0 : if (!warned)
1997 0 : warned = warning_at
1998 0 : (DECL_SOURCE_LOCATION (node->decl),
1999 0 : OPT_Wauto_profile,
2000 : "auto-profile of %q+F contains indirect call targets"
2001 : " not associated with an indirect call statement",
2002 : node->decl);
2003 0 : if (warned)
2004 0 : inform (DECL_SOURCE_LOCATION (node->decl),
2005 : "count %" PRIu64
2006 : " with relative location +%i, discriminator %i",
2007 0 : iter.second.count, iter.first >> 16, iter.first & 65535);
2008 0 : if (dump_file)
2009 : {
2010 0 : fprintf (dump_file, "Removing targets of ");
2011 0 : dump_afdo_loc (dump_file, iter.first);
2012 0 : fprintf (dump_file, "\n");
2013 : }
2014 0 : iter.second.targets.clear ();
2015 : }
2016 0 : warned = false;
2017 : /* Profile sometimes contains extra location for start or end of function
2018 : (prologue, epilogue).
2019 : TODO: If present, perhaps it can be used to determine entry block
2020 : and exit block counts. */
2021 0 : unsigned int end_location = get_combined_location
2022 0 : (DECL_STRUCT_FUNCTION (node->decl)->function_end_locus, node->decl);
2023 0 : unsigned int start_location = get_combined_location
2024 0 : (DECL_STRUCT_FUNCTION (node->decl)->function_start_locus, node->decl);
2025 : /* When outputting code to builtins location we use line number 0.
2026 : create_gcov is stupid and happily computes offsets across files.
2027 : Silently ignore it. */
2028 0 : unsigned int zero_location
2029 0 : = ((unsigned)(1-DECL_SOURCE_LINE (node->decl))) << 16;
2030 0 : for (position_count_map::const_iterator iter = pos_counts.begin ();
2031 0 : iter != pos_counts.end ();)
2032 0 : if (!counts.contains (&iter->second))
2033 : {
2034 0 : if (iter->first != end_location
2035 : && iter->first != start_location
2036 : && (iter->first & 65535) != zero_location
2037 : && iter->first
2038 : /* FIXME: dwarf5 does not represent inline stack of debug
2039 : statements and consequently create_gcov is sometimes
2040 : mixing up statements from other functions. Do not warn
2041 : user about this until this problem is solved.
2042 : We still write info into dump file. */
2043 : && 0)
2044 : {
2045 : if (!warned)
2046 : warned = warning_at (DECL_SOURCE_LOCATION (node->decl),
2047 : OPT_Wauto_profile,
2048 : "auto-profile of %q+F contains extra statements",
2049 : node->decl);
2050 : if (warned)
2051 : inform (DECL_SOURCE_LOCATION (node->decl),
2052 : "count %" PRIu64 " with relative location +%i,"
2053 : " discriminator %i",
2054 : iter->second.count, iter->first >> 16,
2055 : iter->first & 65535);
2056 : if ((iter->first >> 16) > (end_location >> 16) && warned)
2057 : inform (DECL_SOURCE_LOCATION (node->decl),
2058 : "location is after end of function");
2059 : }
2060 0 : if (dump_file)
2061 : {
2062 0 : fprintf (dump_file, "Removing unmatched count ");
2063 0 : dump_afdo_loc (dump_file, iter->first);
2064 0 : fprintf (dump_file, ":%" PRIu64, iter->second.count);
2065 0 : for (auto &titer : iter->second.targets)
2066 0 : fprintf (dump_file, " %s:%" PRIu64,
2067 0 : afdo_string_table->get_symbol_name (titer.first),
2068 0 : (int64_t) titer.second);
2069 0 : fprintf (dump_file, "\n");
2070 : }
2071 0 : iter = pos_counts.erase (iter);
2072 : }
2073 : else
2074 0 : iter++;
2075 0 : warned = false;
2076 0 : for (callsite_map::const_iterator iter = callsites.begin ();
2077 0 : iter != callsites.end ();)
2078 0 : if (!functions.contains (iter->second))
2079 : {
2080 0 : function_instance *f = iter->second;
2081 : /* If we did not see the corresponding statement, warn. */
2082 0 : if (!functions_to_offline.contains (iter->second))
2083 : {
2084 0 : if (!warned)
2085 0 : warned = warning_at (DECL_SOURCE_LOCATION (node->decl),
2086 0 : OPT_Wauto_profile,
2087 : "auto-profile of %q+F contains"
2088 : " extra callsites",
2089 : node->decl);
2090 0 : if (warned)
2091 0 : inform (DECL_SOURCE_LOCATION (node->decl),
2092 : "call of %s with total count %" PRId64
2093 : ", relative location +%i, discriminator %i",
2094 0 : afdo_string_table->get_symbol_name (iter->first.second),
2095 0 : iter->second->total_count (), iter->first.first >> 16,
2096 0 : iter->first.first & 65535);
2097 0 : if ((iter->first.first >> 16) > (end_location >> 16) && warned)
2098 0 : inform (DECL_SOURCE_LOCATION (node->decl),
2099 : "location is after end of function");
2100 0 : if (dump_file)
2101 : {
2102 0 : fprintf (dump_file,
2103 : "Offlining inline with no corresponding gimple stmt ");
2104 0 : f->dump_inline_stack (dump_file);
2105 0 : fprintf (dump_file, "\n");
2106 : }
2107 : }
2108 0 : else if (dump_file)
2109 : {
2110 0 : fprintf (dump_file,
2111 : "Offlining mismatched inline ");
2112 0 : f->dump_inline_stack (dump_file);
2113 0 : fprintf (dump_file, "\n");
2114 : }
2115 0 : callsites.erase (iter);
2116 0 : offline (f, new_functions);
2117 0 : iter = callsites.begin ();
2118 : }
2119 : else
2120 0 : iter++;
2121 0 : for (auto &iter : callsites)
2122 0 : if (cgraph_node *n = iter.second->get_cgraph_node ())
2123 0 : iter.second->match (n, new_functions, to_symbol_name);
2124 0 : return true;
2125 0 : }
2126 :
2127 : /* Walk inlined functions and if their name is not in SEEN
2128 : remove it. Also rename function names as given by
2129 : to_symbol_name map. */
2130 :
2131 : void
2132 0 : function_instance::remove_external_functions
2133 : (name_index_set &seen,
2134 : name_index_map &to_symbol_name,
2135 : vec <function_instance *> &new_functions)
2136 : {
2137 0 : auto_vec <callsite, 20> to_rename;
2138 :
2139 0 : for (callsite_map::const_iterator iter = callsites.begin ();
2140 0 : iter != callsites.end ();)
2141 0 : if (!seen.contains (iter->first.second))
2142 : {
2143 0 : function_instance *f = iter->second;
2144 0 : if (dump_file)
2145 : {
2146 0 : fprintf (dump_file, " Removing external inline: ");
2147 0 : f->dump_inline_stack (dump_file);
2148 0 : fprintf (dump_file, "\n");
2149 : }
2150 0 : iter = callsites.erase (iter);
2151 0 : f->set_inlined_to (NULL);
2152 0 : f->offline_if_in_set (seen, new_functions);
2153 0 : delete f;
2154 : }
2155 : else
2156 : {
2157 0 : gcc_checking_assert ((int) iter->first.second
2158 : == iter->second->symbol_name ());
2159 0 : int *newn = iter->second->get_call_location () == UNKNOWN_LOCATION
2160 0 : ? to_symbol_name.get (iter->first.second)
2161 : : NULL;
2162 0 : if (newn)
2163 : {
2164 0 : gcc_checking_assert (iter->second->inlined_to ());
2165 0 : to_rename.safe_push (iter->first);
2166 : }
2167 0 : iter->second->remove_external_functions
2168 0 : (seen, to_symbol_name, new_functions);
2169 0 : ++iter;
2170 : }
2171 0 : for (auto &key : to_rename)
2172 : {
2173 0 : auto iter = callsites.find (key);
2174 0 : callsite key2 = key;
2175 0 : key2.second = *to_symbol_name.get (key.second);
2176 0 : iter->second->set_symbol_name (key2.second);
2177 0 : callsites.erase (iter);
2178 0 : callsites[key2] = iter->second;
2179 : }
2180 0 : auto_vec <int, 20> target_to_rename;
2181 0 : for (auto &iter : pos_counts)
2182 : {
2183 0 : for (auto const &titer : iter.second.targets)
2184 : {
2185 0 : int *ren = to_symbol_name.get (titer.first);
2186 0 : if (ren)
2187 0 : target_to_rename.safe_push (titer.first);
2188 : }
2189 0 : while (target_to_rename.length ())
2190 : {
2191 0 : int key = target_to_rename.pop ();
2192 0 : int key2 = *to_symbol_name.get (key);
2193 0 : auto i = iter.second.targets.find (key);
2194 0 : if (iter.second.targets.count (key2) == 0)
2195 0 : iter.second.targets[key2] = i->second;
2196 : else
2197 0 : iter.second.targets[key2] += i->second;
2198 0 : iter.second.targets.erase (i);
2199 : }
2200 : }
2201 0 : }
2202 :
2203 : /* Look for inline instances that was not realized and
2204 : remove them while possibly merging them to offline variants. */
2205 :
2206 : void
2207 0 : function_instance::offline_if_not_realized
2208 : (vec <function_instance *> &new_functions)
2209 : {
2210 0 : for (callsite_map::const_iterator iter = callsites.begin ();
2211 0 : iter != callsites.end ();)
2212 0 : if (!iter->second->realized_p ())
2213 : {
2214 0 : function_instance *f = iter->second;
2215 0 : if (dump_file)
2216 : {
2217 0 : fprintf (dump_file, "Offlining unrealized inline ");
2218 0 : f->dump_inline_stack (dump_file);
2219 0 : fprintf (dump_file, "\n");
2220 : }
2221 0 : iter = callsites.erase (iter);
2222 0 : offline (f, new_functions);
2223 : }
2224 : else
2225 : {
2226 0 : iter->second->offline_if_not_realized (new_functions);
2227 0 : ++iter;
2228 : }
2229 0 : }
2230 :
2231 : /* Dump instance to F indented by INDENT. */
2232 :
2233 : void
2234 0 : function_instance::dump (FILE *f, int indent, bool nested) const
2235 : {
2236 0 : if (!nested)
2237 0 : fprintf (f, "%*s%s total:%" PRIu64 " head:%" PRId64 "\n", indent, "",
2238 : afdo_string_table->get_symbol_name (symbol_name ()),
2239 0 : (int64_t) total_count (), (int64_t) head_count ());
2240 : else
2241 0 : fprintf (f, " total:%" PRIu64 "\n", (int64_t)total_count ());
2242 0 : for (auto const &iter : pos_counts)
2243 : {
2244 0 : fprintf (f, "%*s", indent + 2, "");
2245 0 : dump_afdo_loc (f, iter.first);
2246 0 : fprintf (f, ": %" PRIu64, (int64_t)iter.second.count);
2247 :
2248 0 : for (auto const &titer : iter.second.targets)
2249 0 : fprintf (f, " %s:%" PRIu64,
2250 0 : afdo_string_table->get_symbol_name (titer.first),
2251 0 : (int64_t) titer.second);
2252 0 : fprintf (f,"\n");
2253 : }
2254 0 : for (auto const &iter : callsites)
2255 : {
2256 0 : fprintf (f, "%*s", indent + 2, "");
2257 0 : dump_afdo_loc (f, iter.first.first);
2258 0 : fprintf (f, ": %s",
2259 0 : afdo_string_table->get_symbol_name (iter.first.second));
2260 0 : iter.second->dump (f, indent + 2, true);
2261 0 : gcc_checking_assert ((int) iter.first.second
2262 : == iter.second->symbol_name ());
2263 : }
2264 0 : }
2265 :
2266 : /* Dump inline path. */
2267 :
2268 : void
2269 0 : function_instance::dump_inline_stack (FILE *f) const
2270 : {
2271 0 : auto_vec <callsite, 20> stack;
2272 0 : const function_instance *p = this, *s = inlined_to ();
2273 0 : while (s)
2274 : {
2275 0 : bool found = false;
2276 0 : for (callsite_map::const_iterator iter = s->callsites.begin ();
2277 0 : iter != s->callsites.end (); ++iter)
2278 0 : if (iter->second == p)
2279 : {
2280 0 : gcc_checking_assert (
2281 : !found && (int) iter->first.second == p->symbol_name ());
2282 0 : stack.safe_push ({iter->first.first, s->symbol_name ()});
2283 0 : found = true;
2284 : }
2285 0 : gcc_checking_assert (found);
2286 0 : p = s;
2287 0 : s = s->inlined_to ();
2288 : }
2289 0 : for (callsite &s: stack)
2290 : {
2291 0 : fprintf (f, "%s:", afdo_string_table->get_symbol_name (s.second));
2292 0 : dump_afdo_loc (f, s.first);
2293 0 : fprintf (f, " ");
2294 : }
2295 0 : fprintf (f, "%s", afdo_string_table->get_symbol_name (symbol_name ()));
2296 0 : }
2297 :
2298 : /* Dump instance to stderr. */
2299 :
2300 : void
2301 0 : function_instance::debug () const
2302 : {
2303 0 : dump (stderr);
2304 0 : }
2305 :
2306 : /* Return profile info for LOC in INFO. */
2307 :
2308 : bool
2309 0 : function_instance::get_count_info (location_t loc, count_info *info) const
2310 : {
2311 0 : position_count_map::const_iterator iter = pos_counts.find (loc);
2312 0 : if (iter == pos_counts.end ())
2313 : return false;
2314 0 : *info = iter->second;
2315 0 : return true;
2316 : }
2317 :
2318 : /* Read the inlined indirect call target profile for STMT and store it in
2319 : MAP, return the total count for all inlined indirect calls. */
2320 :
2321 : gcov_type
2322 0 : function_instance::find_icall_target_map (tree fn, gcall *stmt,
2323 : icall_target_map *map) const
2324 : {
2325 0 : gcov_type ret = 0;
2326 0 : unsigned stmt_offset = get_relative_location_for_stmt (fn, stmt);
2327 :
2328 0 : for (callsite_map::const_iterator iter = callsites.begin ();
2329 0 : iter != callsites.end (); ++iter)
2330 : {
2331 0 : unsigned callee = iter->second->symbol_name ();
2332 : /* Check if callsite location match the stmt. */
2333 0 : if (iter->first.first != stmt_offset
2334 0 : || iter->second->removed_icall_target ())
2335 0 : continue;
2336 0 : struct cgraph_node *node = cgraph_node::get_for_asmname (
2337 : get_identifier (afdo_string_table->get_symbol_name (callee)));
2338 0 : if (node == NULL)
2339 0 : continue;
2340 0 : (*map)[callee] = iter->second->total_count () * afdo_count_scale;
2341 0 : ret += iter->second->total_count () * afdo_count_scale;
2342 : }
2343 0 : return ret;
2344 : }
2345 :
2346 : /* Remove the inlined indirect call target profile for STMT. */
2347 :
2348 : void
2349 0 : function_instance::remove_icall_target (tree fn, gcall *stmt)
2350 : {
2351 0 : unsigned stmt_offset = get_relative_location_for_stmt (fn, stmt);
2352 0 : int n = 0;
2353 :
2354 0 : for (auto iter : callsites)
2355 0 : if (iter.first.first == stmt_offset)
2356 : {
2357 0 : iter.second->remove_icall_target ();
2358 0 : n++;
2359 : }
2360 : /* TODO: If we add support for multiple targets, we may want to
2361 : remove only those we succesfully inlined. */
2362 0 : gcc_assert (n);
2363 0 : }
2364 :
2365 : /* Offline all functions not defined in the current unit.
2366 : We will not be able to early inline them.
2367 : Doing so early will get VPT decisions more realistic. */
2368 :
2369 : void
2370 0 : autofdo_source_profile::offline_external_functions ()
2371 : {
2372 : /* First check all available definitions and mark their names as
2373 : visible. */
2374 0 : cgraph_node *node;
2375 0 : name_index_set seen;
2376 0 : name_index_map to_symbol_name;
2377 0 : size_t last_name;
2378 :
2379 : /* Add renames erasing suffixes produced by late clones, such as
2380 : .isra, .ipcp. */
2381 0 : for (size_t i = 1; i < afdo_string_table->num_entries (); i++)
2382 : {
2383 0 : const char *n1 = afdo_string_table->get_symbol_name (i);
2384 0 : std::pair<const char *, int> name_filename
2385 0 : = afdo_string_table->get_original_name (n1);
2386 0 : const char *n2 = name_filename.first;
2387 0 : if (!strcmp (n1, n2))
2388 : {
2389 : /* Watch for duplicate entries.
2390 : This seems to happen in practice and may be useful to distinguish
2391 : multiple static symbols of the same name, but we do not realy
2392 : have a way to differentiate them in get_symbol_name lookup. */
2393 0 : int index = afdo_string_table->get_index (n1);
2394 0 : if (index != (int)i)
2395 : {
2396 0 : if (dump_file)
2397 0 : fprintf (dump_file,
2398 : "string table in auto-profile contains"
2399 : " duplicated name %s\n", n1);
2400 0 : to_symbol_name.put (i, index);
2401 : }
2402 0 : continue;
2403 0 : }
2404 0 : if (dump_file)
2405 0 : fprintf (dump_file, "Adding rename removing clone suffixes %s -> %s\n",
2406 : n1, n2);
2407 0 : int index = afdo_string_table->get_index (n2);
2408 0 : if (index == -1)
2409 0 : index = afdo_string_table->add_symbol_name (xstrdup (n2),
2410 : name_filename.second);
2411 0 : to_symbol_name.put (i, index);
2412 : }
2413 0 : last_name = afdo_string_table->num_entries ();
2414 0 : FOR_EACH_DEFINED_FUNCTION (node)
2415 : {
2416 0 : const char *name = raw_symbol_name (node->decl);
2417 0 : const char *dwarf_name = lang_hooks.dwarf_name (node->decl, 0);
2418 0 : int index = afdo_string_table->get_index (name);
2419 :
2420 : /* Inline function may be identified by its dwarf names;
2421 : rename them to symbol names. With LTO dwarf names are
2422 : lost in free_lange_data. */
2423 0 : if (strcmp (name, dwarf_name))
2424 : {
2425 0 : int index2 = afdo_string_table->get_index (dwarf_name);
2426 0 : if (index2 != -1)
2427 : {
2428 0 : if (index == -1)
2429 0 : index = afdo_string_table->add_symbol_name (
2430 0 : xstrdup (name),
2431 : afdo_string_table->add_filename (
2432 0 : get_normalized_path (DECL_SOURCE_FILE (node->decl))));
2433 0 : if (dump_file)
2434 : {
2435 0 : fprintf (dump_file, "Adding dwarf->symbol rename %s -> %s\n",
2436 : afdo_string_table->get_symbol_name (index2), name);
2437 0 : if (to_symbol_name.get (index2))
2438 0 : fprintf (dump_file, "Dwarf name is not unique");
2439 : }
2440 0 : to_symbol_name.put (index2, index);
2441 0 : seen.add (index2);
2442 : }
2443 : }
2444 0 : if (index != -1)
2445 : {
2446 0 : if (dump_file)
2447 0 : fprintf (dump_file, "%s is defined in node %s\n",
2448 : afdo_string_table->get_symbol_name (index),
2449 : node->dump_name ());
2450 0 : seen.add (index);
2451 : }
2452 : else
2453 : {
2454 0 : if (dump_file)
2455 : {
2456 0 : if (dwarf_name && strcmp (dwarf_name, name))
2457 0 : fprintf (dump_file,
2458 : "Node %s not in auto profile (%s neither %s)\n",
2459 : node->dump_name (),
2460 : name,
2461 : dwarf_name);
2462 : else
2463 0 : fprintf (dump_file,
2464 : "Node %s (symbol %s) not in auto profile\n",
2465 : node->dump_name (),
2466 : name);
2467 : }
2468 : }
2469 : }
2470 :
2471 0 : for (auto iter : to_symbol_name)
2472 : {
2473 : /* In case dwarf name was duplicated and later renamed,
2474 : handle both. No more than one hop should be needed. */
2475 0 : int *newn = to_symbol_name.get (iter.second);
2476 0 : if (newn)
2477 0 : iter.second = *newn;
2478 0 : gcc_checking_assert (!to_symbol_name.get (iter.second));
2479 0 : if (seen.contains (iter.second))
2480 0 : seen.add (iter.first);
2481 : }
2482 :
2483 : /* Now process all toplevel (offline) function instances.
2484 :
2485 : If instance has no definition in this translation unit,
2486 : first offline all inlined functions which are defined here
2487 : (so we do not lose profile due to cross-module inlining
2488 : done by link-time optimizers).
2489 :
2490 : If instance has a definition, look into all inlined functions
2491 : and remove external ones (result of cross-module inlining).
2492 :
2493 : TODO: after early-inlining we ought to offline all functions
2494 : that were not inlined. */
2495 0 : vec <function_instance *>&fns = duplicate_functions_;
2496 0 : auto_vec <function_instance *, 20>fns2;
2497 : /* Populate worklist with all functions to process. Processing
2498 : may introduce new functions by offlining. */
2499 0 : for (auto &function : map_)
2500 : {
2501 0 : function.second->set_in_worklist ();
2502 0 : fns.safe_push (function.second);
2503 : }
2504 :
2505 : /* There are two worklists. First all functions needs to be matched
2506 : with gimple body and only then we want to do merging, since matching
2507 : should be done on unmodified profile and merging works better if
2508 : mismatches are already resolved both in source and destination. */
2509 0 : while (fns.length () || fns2.length ())
2510 : {
2511 : /* In case renaming introduced new name, keep seen up to date. */
2512 0 : for (; last_name < afdo_string_table->num_entries (); last_name++)
2513 : {
2514 0 : const char *name = afdo_string_table->get_symbol_name (last_name);
2515 0 : symtab_node *n
2516 0 : = afdo_string_table->get_cgraph_node (last_name);
2517 0 : if (dump_file)
2518 0 : fprintf (dump_file, "New name %s %s\n", name,
2519 : n ? "wth corresponding definition"
2520 : : "with no corresponding definition");
2521 0 : if (n)
2522 0 : seen.add (last_name);
2523 : }
2524 0 : if (fns.length ())
2525 : {
2526 0 : function_instance *f = fns.pop ();
2527 0 : if (f->get_location () == UNKNOWN_LOCATION)
2528 : {
2529 0 : int index = f->symbol_name ();
2530 0 : int *newn = to_symbol_name.get (index);
2531 0 : if (newn)
2532 : {
2533 0 : if (find_function_instance (f->get_descriptor ()) == f)
2534 0 : remove_function_instance (f);
2535 0 : f->set_symbol_name (*newn);
2536 0 : if (!find_function_instance (f->get_descriptor ()))
2537 0 : add_function_instance (f);
2538 : }
2539 0 : if (cgraph_node *n = f->get_cgraph_node ())
2540 : {
2541 0 : gcc_checking_assert (seen.contains (f->symbol_name ()));
2542 0 : f->match (n, fns, to_symbol_name);
2543 : }
2544 : }
2545 0 : fns2.safe_push (f);
2546 : }
2547 : else
2548 : {
2549 0 : function_instance *f = fns2.pop ();
2550 0 : int index = f->symbol_name ();
2551 0 : gcc_checking_assert (f->in_worklist_p ());
2552 :
2553 : /* If map has different function_instance of same name, then
2554 : this is a duplicated entry which needs to be merged. */
2555 0 : function_instance *index_inst
2556 0 : = find_function_instance (f->get_descriptor ());
2557 0 : if (index_inst && index_inst != f)
2558 : {
2559 0 : if (dump_file)
2560 : {
2561 0 : fprintf (dump_file, "Merging duplicate instance: ");
2562 0 : f->dump_inline_stack (dump_file);
2563 0 : fprintf (dump_file, "\n");
2564 : }
2565 0 : index_inst->merge (f, fns);
2566 0 : gcc_checking_assert (!f->inlined_to ());
2567 0 : f->clear_in_worklist ();
2568 0 : delete f;
2569 : }
2570 : /* If name was not seen in the symbol table, remove it. */
2571 0 : else if (!seen.contains (index))
2572 : {
2573 0 : f->offline_if_in_set (seen, fns);
2574 0 : f->clear_in_worklist ();
2575 0 : if (dump_file)
2576 0 : fprintf (dump_file, "Removing external %s\n",
2577 : afdo_string_table->get_symbol_name (
2578 : f->symbol_name ()));
2579 0 : if (index_inst == f)
2580 0 : remove_function_instance (f);
2581 0 : delete f;
2582 : }
2583 : /* If this is offline function instance seen in this
2584 : translation unit offline external inlines and possibly
2585 : rename from dwarf name. */
2586 : else
2587 : {
2588 0 : f->remove_external_functions (seen, to_symbol_name, fns);
2589 0 : f->clear_in_worklist ();
2590 : }
2591 : }
2592 : }
2593 0 : if (dump_file)
2594 0 : for (auto const &function : map_)
2595 : {
2596 0 : seen.contains (function.second->symbol_name ());
2597 0 : function.second->dump (dump_file);
2598 : }
2599 0 : }
2600 :
2601 : /* Walk scope block BLOCK and mark all inlined functions as realized. */
2602 :
2603 : static void
2604 0 : walk_block (tree fn, function_instance *s, tree block)
2605 : {
2606 0 : if (inlined_function_outer_scope_p (block))
2607 : {
2608 0 : unsigned loc = get_relative_location_for_locus
2609 0 : (fn, BLOCK_SUPERCONTEXT (block),
2610 0 : BLOCK_SOURCE_LOCATION (block));
2611 0 : function_instance *ns
2612 : = s->get_function_instance_by_decl
2613 0 : (loc, BLOCK_ABSTRACT_ORIGIN (block),
2614 0 : BLOCK_SOURCE_LOCATION (block));
2615 0 : if (!ns)
2616 : {
2617 0 : if (dump_file)
2618 : {
2619 0 : fprintf (dump_file, " Failed to find inlined instance:");
2620 0 : s->dump_inline_stack (dump_file);
2621 0 : fprintf (dump_file, ":");
2622 0 : dump_afdo_loc (dump_file, loc);
2623 0 : fprintf (dump_file, " %s\n",
2624 0 : raw_symbol_name (BLOCK_ABSTRACT_ORIGIN (block)));
2625 : }
2626 0 : return;
2627 : }
2628 0 : s = ns;
2629 0 : if (dump_file)
2630 : {
2631 0 : fprintf (dump_file, " Marking realized inline: ");
2632 0 : s->dump_inline_stack (dump_file);
2633 0 : fprintf (dump_file, "\n");
2634 : }
2635 0 : s->set_realized ();
2636 : }
2637 0 : for (tree t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
2638 0 : walk_block (fn, s, t);
2639 : }
2640 :
2641 : /* Offline all inline functions that are not marked as realized.
2642 : This will merge their profile into offline versions where available.
2643 : Also remove all functions we will no longer use. */
2644 :
2645 : void
2646 0 : autofdo_source_profile::offline_unrealized_inlines ()
2647 : {
2648 0 : auto_vec <function_instance *>fns;
2649 : /* Populate worklist with all functions to process. Processing
2650 : may introduce new functions by offlining. */
2651 0 : for (auto const &function : map_)
2652 : {
2653 0 : fns.safe_push (function.second);
2654 0 : function.second->set_in_worklist ();
2655 : }
2656 0 : while (fns.length ())
2657 : {
2658 0 : function_instance *f = fns.pop ();
2659 0 : int index = f->symbol_name ();
2660 0 : function_instance *index_inst
2661 0 : = find_function_instance (f->get_descriptor ());
2662 0 : bool in_map = index_inst != nullptr;
2663 0 : if (in_map)
2664 0 : if (cgraph_node *n = f->get_cgraph_node ())
2665 : {
2666 0 : if (dump_file)
2667 0 : fprintf (dump_file, "Marking realized %s\n",
2668 : afdo_string_table->get_symbol_name (index));
2669 0 : f->set_realized ();
2670 0 : if (DECL_INITIAL (n->decl)
2671 0 : && DECL_INITIAL (n->decl) != error_mark_node)
2672 0 : walk_block (n->decl, f, DECL_INITIAL (n->decl));
2673 : }
2674 0 : f->offline_if_not_realized (fns);
2675 0 : gcc_checking_assert ((in_map || !f->realized_p ())
2676 : && f->in_worklist_p ());
2677 :
2678 : /* If this is duplicated instance, merge it into one in map. */
2679 0 : if (in_map && index_inst != f)
2680 : {
2681 0 : if (dump_file)
2682 : {
2683 0 : fprintf (dump_file, "Merging duplicate instance: ");
2684 0 : f->dump_inline_stack (dump_file);
2685 0 : fprintf (dump_file, "\n");
2686 : }
2687 0 : index_inst->merge (f, fns);
2688 0 : f->clear_in_worklist ();
2689 0 : gcc_checking_assert (!f->inlined_to ());
2690 0 : delete f;
2691 : }
2692 : /* If function is not in symbol table, remove it. */
2693 0 : else if (!f->realized_p ())
2694 : {
2695 0 : if (dump_file)
2696 0 : fprintf (dump_file, "Removing optimized out function %s\n",
2697 : afdo_string_table->get_symbol_name (f->symbol_name ()));
2698 0 : if (in_map)
2699 0 : remove_function_instance (index_inst);
2700 0 : f->clear_in_worklist ();
2701 0 : delete f;
2702 : }
2703 : else
2704 0 : f->clear_in_worklist ();
2705 : }
2706 0 : if (dump_file)
2707 0 : for (auto const &function : map_)
2708 0 : function.second->dump (dump_file);
2709 0 : }
2710 :
2711 : /* Read the profile and create a function_instance with head count as
2712 : HEAD_COUNT. Recursively read callsites to create nested function_instances
2713 : too. STACK is used to track the recursive creation process. */
2714 :
2715 : /* function instance profile format:
2716 :
2717 : ENTRY_COUNT: 8 bytes
2718 : TIMESTAMP: 8 bytes (only for toplevel symbols)
2719 : NAME_INDEX: 4 bytes
2720 : NUM_POS_COUNTS: 4 bytes
2721 : NUM_CALLSITES: 4 byte
2722 : POS_COUNT_1:
2723 : POS_1_OFFSET: 4 bytes
2724 : NUM_TARGETS: 4 bytes
2725 : COUNT: 8 bytes
2726 : TARGET_1:
2727 : VALUE_PROFILE_TYPE: 4 bytes
2728 : TARGET_IDX: 8 bytes
2729 : COUNT: 8 bytes
2730 : TARGET_2
2731 : ...
2732 : TARGET_n
2733 : POS_COUNT_2
2734 : ...
2735 : POS_COUNT_N
2736 : CALLSITE_1:
2737 : CALLSITE_1_OFFSET: 4 bytes
2738 : FUNCTION_INSTANCE_PROFILE (nested)
2739 : CALLSITE_2
2740 : ...
2741 : CALLSITE_n. */
2742 :
2743 : function_instance *
2744 0 : function_instance::read_function_instance (function_instance_stack *stack,
2745 : bool toplevel)
2746 : {
2747 0 : gcov_type_unsigned timestamp = 0;
2748 0 : gcov_type head_count = -1;
2749 0 : if (toplevel)
2750 : {
2751 0 : head_count = gcov_read_counter ();
2752 0 : timestamp = (gcov_type_unsigned) gcov_read_counter ();
2753 : }
2754 0 : unsigned name = gcov_read_unsigned ();
2755 0 : unsigned num_pos_counts = gcov_read_unsigned ();
2756 0 : unsigned num_callsites = gcov_read_unsigned ();
2757 0 : function_instance *s
2758 : = new function_instance (name,
2759 0 : afdo_string_table->get_filename_by_symbol (name),
2760 0 : head_count);
2761 0 : if (timestamp > 0)
2762 0 : s->set_timestamp (timestamp);
2763 0 : if (!stack->is_empty ())
2764 0 : s->set_inlined_to (stack->last ());
2765 0 : stack->safe_push (s);
2766 :
2767 0 : for (unsigned i = 0; i < num_pos_counts; i++)
2768 : {
2769 0 : unsigned offset = gcov_read_unsigned ();
2770 0 : unsigned num_targets = gcov_read_unsigned ();
2771 0 : gcov_type count = gcov_read_counter ();
2772 0 : s->pos_counts[offset].count = count;
2773 :
2774 0 : for (unsigned j = 0; j < stack->length (); j++)
2775 0 : (*stack)[j]->total_count_ += count;
2776 0 : for (unsigned j = 0; j < num_targets; j++)
2777 : {
2778 : /* Only indirect call target histogram is supported now. */
2779 0 : gcov_read_unsigned ();
2780 0 : gcov_type target_idx = gcov_read_counter ();
2781 0 : s->pos_counts[offset].targets[target_idx] = gcov_read_counter ();
2782 : }
2783 : }
2784 0 : for (unsigned i = 0; i < num_callsites; i++)
2785 : {
2786 0 : unsigned offset = gcov_read_unsigned ();
2787 0 : function_instance *callee_function_instance
2788 0 : = read_function_instance (stack, false);
2789 0 : s->callsites[std::make_pair (offset,
2790 0 : callee_function_instance->symbol_name ())]
2791 0 : = callee_function_instance;
2792 : }
2793 0 : stack->pop ();
2794 0 : return s;
2795 : }
2796 :
2797 : /* Member functions for autofdo_source_profile. */
2798 :
2799 0 : autofdo_source_profile::~autofdo_source_profile ()
2800 : {
2801 0 : for (name_function_instance_map::const_iterator iter = map_.begin ();
2802 0 : iter != map_.end (); ++iter)
2803 0 : delete iter->second;
2804 0 : }
2805 :
2806 : /* For a given DECL, returns the top-level function_instance. */
2807 :
2808 : function_instance *
2809 0 : autofdo_source_profile::get_function_instance_by_decl (tree decl, const char *filename) const
2810 : {
2811 0 : if (!filename)
2812 0 : filename = get_normalized_path (DECL_SOURCE_FILE (decl));
2813 0 : int index = afdo_string_table->get_index_by_decl (decl);
2814 0 : if (index == -1)
2815 : return NULL;
2816 :
2817 0 : function_instance_descriptor descriptor (
2818 0 : afdo_string_table->get_filename_index (filename), index);
2819 0 : return find_function_instance (descriptor);
2820 : }
2821 :
2822 : /* For a given DESCRIPTOR, return the matching instance if found. */
2823 :
2824 : function_instance *
2825 0 : autofdo_source_profile::get_function_instance_by_descriptor (
2826 : function_instance_descriptor descriptor) const
2827 : {
2828 0 : return find_function_instance (descriptor);
2829 : }
2830 :
2831 : /* Add function instance FN. */
2832 :
2833 : void
2834 0 : autofdo_source_profile::add_function_instance (function_instance *fn)
2835 : {
2836 0 : gcc_checking_assert (map_.find (fn->get_descriptor ()) == map_.end ());
2837 0 : map_[fn->get_descriptor ()] = fn;
2838 0 : }
2839 :
2840 : /* Find count_info for a given gimple STMT. If found, store the count_info
2841 : in INFO and return true; otherwise return false. */
2842 :
2843 : bool
2844 0 : autofdo_source_profile::get_count_info (gimple *stmt, count_info *info,
2845 : cgraph_node *node) const
2846 : {
2847 0 : gcc_checking_assert (stmt_loc_used_by_debug_info (stmt));
2848 0 : return get_count_info (gimple_location (stmt), info, node);
2849 : }
2850 :
2851 : bool
2852 0 : autofdo_source_profile::get_count_info (location_t gimple_loc,
2853 : count_info *info,
2854 : cgraph_node *node) const
2855 : {
2856 0 : if (LOCATION_LOCUS (gimple_loc) == cfun->function_end_locus)
2857 : return false;
2858 :
2859 0 : inline_stack stack;
2860 0 : get_inline_stack_in_node (gimple_loc, &stack, node);
2861 0 : if (stack.length () == 0)
2862 : return false;
2863 0 : function_instance *s = get_function_instance_by_inline_stack (stack);
2864 0 : if (s == NULL)
2865 : return false;
2866 0 : return s->get_count_info (stack[0].afdo_loc, info);
2867 0 : }
2868 :
2869 : /* Update value profile INFO for STMT from the inlined indirect callsite.
2870 : Return true if INFO is updated. */
2871 :
2872 : bool
2873 0 : autofdo_source_profile::update_inlined_ind_target (gcall *stmt,
2874 : count_info *info,
2875 : cgraph_node *node)
2876 : {
2877 0 : if (dump_file)
2878 : {
2879 0 : fprintf (dump_file, "Checking indirect call -> direct call ");
2880 0 : print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
2881 : }
2882 :
2883 0 : if (LOCATION_LOCUS (gimple_location (stmt)) == cfun->function_end_locus)
2884 : {
2885 0 : if (dump_file)
2886 0 : fprintf (dump_file, " bad locus (function end)\n");
2887 0 : return false;
2888 : }
2889 :
2890 0 : count_info old_info;
2891 0 : get_count_info (stmt, &old_info, node);
2892 0 : gcov_type total = 0;
2893 0 : for (icall_target_map::const_iterator iter = old_info.targets.begin ();
2894 0 : iter != old_info.targets.end (); ++iter)
2895 0 : total += iter->second;
2896 0 : total *= afdo_count_scale;
2897 :
2898 : /* Program behavior changed, original promoted (and inlined) target is not
2899 : hot any more. Will avoid promote the original target.
2900 :
2901 : To check if original promoted target is still hot, we check the total
2902 : count of the unpromoted targets (stored in TOTAL). If a callsite count
2903 : (stored in INFO) is smaller than half of the total count, the original
2904 : promoted target is considered not hot any more. */
2905 0 : if (info->count < total / 2)
2906 : {
2907 0 : if (dump_file)
2908 0 : fprintf (dump_file, " not hot anymore %ld < %ld",
2909 : (long)info->count,
2910 : (long)total /2);
2911 0 : return false;
2912 : }
2913 :
2914 0 : inline_stack stack;
2915 0 : get_inline_stack_in_node (gimple_location (stmt), &stack, node);
2916 0 : if (stack.length () == 0)
2917 : {
2918 0 : if (dump_file)
2919 0 : fprintf (dump_file, " no inline stack\n");
2920 0 : return false;
2921 : }
2922 0 : function_instance *s = get_function_instance_by_inline_stack (stack);
2923 0 : if (s == NULL)
2924 : {
2925 0 : if (dump_file)
2926 : {
2927 0 : fprintf (dump_file, " function not found in inline stack:");
2928 0 : dump_inline_stack (dump_file, &stack);
2929 : }
2930 0 : return false;
2931 : }
2932 0 : icall_target_map map;
2933 0 : if (s->find_icall_target_map (node ? node->decl
2934 : : current_function_decl,
2935 : stmt, &map) == 0)
2936 : {
2937 0 : if (dump_file)
2938 : {
2939 0 : fprintf (dump_file, " no target map for stack: ");
2940 0 : dump_inline_stack (dump_file, &stack);
2941 : }
2942 0 : return false;
2943 : }
2944 0 : for (icall_target_map::const_iterator iter = map.begin ();
2945 0 : iter != map.end (); ++iter)
2946 0 : info->targets[iter->first] = iter->second;
2947 0 : if (dump_file)
2948 : {
2949 0 : fprintf (dump_file, " looks good; stack:");
2950 0 : dump_inline_stack (dump_file, &stack);
2951 : }
2952 : return true;
2953 0 : }
2954 :
2955 : void
2956 0 : autofdo_source_profile::remove_icall_target (cgraph_edge *e)
2957 : {
2958 0 : autofdo::inline_stack stack;
2959 0 : autofdo::get_inline_stack_in_node (gimple_location (e->call_stmt),
2960 : &stack, e->caller);
2961 0 : autofdo::function_instance *s
2962 0 : = get_function_instance_by_inline_stack (stack);
2963 0 : s->remove_icall_target (e->caller->decl, e->call_stmt);
2964 0 : }
2965 :
2966 : /* Find total count of the callee of EDGE. */
2967 :
2968 : gcov_type
2969 0 : autofdo_source_profile::get_callsite_total_count (
2970 : struct cgraph_edge *edge) const
2971 : {
2972 0 : inline_stack stack;
2973 0 : stack.safe_push ({edge->callee->decl, 0, UNKNOWN_LOCATION});
2974 :
2975 0 : get_inline_stack_in_node (gimple_location (edge->call_stmt), &stack,
2976 : edge->caller);
2977 0 : if (dump_file)
2978 : {
2979 0 : if (!edge->caller->inlined_to)
2980 0 : fprintf (dump_file, "Looking up afdo profile for call %s -> %s stack:",
2981 0 : edge->caller->dump_name (), edge->callee->dump_name ());
2982 : else
2983 0 : fprintf (dump_file, "Looking up afdo profile for call %s -> %s transitively %s stack:",
2984 0 : edge->caller->dump_name (), edge->callee->dump_name (),
2985 : edge->caller->inlined_to->dump_name ());
2986 0 : dump_inline_stack (dump_file, &stack);
2987 : }
2988 :
2989 0 : function_instance *s = get_function_instance_by_inline_stack (stack);
2990 0 : if (s == NULL)
2991 : {
2992 0 : if (dump_file)
2993 0 : fprintf (dump_file, "No function instance found\n");
2994 0 : return 0;
2995 : }
2996 0 : if (afdo_string_table->get_index_by_decl (edge->callee->decl)
2997 0 : != s->symbol_name ())
2998 : {
2999 0 : if (dump_file)
3000 0 : fprintf (dump_file, "Mismatched name of callee %s and profile %s\n",
3001 0 : raw_symbol_name (edge->callee->decl),
3002 : afdo_string_table->get_symbol_name (s->symbol_name ()));
3003 0 : return 0;
3004 : }
3005 :
3006 0 : return s->total_count () * afdo_count_scale;
3007 0 : }
3008 :
3009 : /* Read AutoFDO profile and returns TRUE on success. */
3010 :
3011 : /* source profile format:
3012 :
3013 : GCOV_TAG_AFDO_FUNCTION: 4 bytes
3014 : LENGTH: 4 bytes
3015 : NUM_FUNCTIONS: 4 bytes
3016 : FUNCTION_INSTANCE_1
3017 : FUNCTION_INSTANCE_2
3018 : ...
3019 : FUNCTION_INSTANCE_N. */
3020 :
3021 : bool
3022 0 : autofdo_source_profile::read ()
3023 : {
3024 0 : if (gcov_read_unsigned () != GCOV_TAG_AFDO_FUNCTION)
3025 : {
3026 0 : inform (UNKNOWN_LOCATION, "Not expected TAG.");
3027 0 : return false;
3028 : }
3029 :
3030 0 : gcc_checking_assert (!afdo_source_profile);
3031 0 : afdo_source_profile = this;
3032 :
3033 : /* Skip the length of the section. */
3034 0 : gcov_read_unsigned ();
3035 :
3036 : /* Read in the function/callsite profile, and store it in local
3037 : data structure. */
3038 0 : unsigned function_num = gcov_read_unsigned ();
3039 0 : for (unsigned i = 0; i < function_num; i++)
3040 : {
3041 0 : function_instance::function_instance_stack stack;
3042 0 : function_instance *s
3043 0 : = function_instance::read_function_instance (&stack);
3044 :
3045 0 : if (find_function_instance (s->get_descriptor ()) == nullptr)
3046 0 : add_function_instance (s);
3047 : else
3048 0 : fatal_error (UNKNOWN_LOCATION,
3049 : "auto-profile contains duplicated function instance %s",
3050 : afdo_string_table->get_symbol_name (s->symbol_name ()));
3051 0 : s->prop_timestamp ();
3052 0 : timestamp_info_map.insert({s->timestamp (), 0});
3053 0 : }
3054 :
3055 : /* timestamp_info_map is std::map with timestamp as key,
3056 : so it's already sorted in ascending order wrt timestamps.
3057 : This loop maps function with lowest timestamp to 1, and so on.
3058 : In afdo_annotate_cfg, node->tp_first_run is then set to corresponding
3059 : tp_first_run value. */
3060 :
3061 0 : int tp_first_run = 1;
3062 0 : for (auto &p : timestamp_info_map)
3063 0 : p.second = tp_first_run++;
3064 :
3065 0 : afdo_profile_info->sum_max = afdo_summary_info->max_count;
3066 : /* Scale up the profile, but leave some bits in case some counts gets
3067 : bigger than sum_max eventually. */
3068 0 : if (afdo_profile_info->sum_max)
3069 0 : afdo_count_scale
3070 0 : = MAX (((gcov_type)1 << (profile_count::n_bits - 10))
3071 : / afdo_profile_info->sum_max, 1);
3072 0 : afdo_profile_info->cutoff *= afdo_count_scale;
3073 : /* Derive the hot count threshold from the profile summary. */
3074 0 : afdo_hot_bb_threshold = afdo_summary_info->get_threshold_count (
3075 0 : param_hot_bb_count_ws_permille * 1000)
3076 0 : * afdo_count_scale;
3077 0 : set_hot_bb_threshold (afdo_hot_bb_threshold);
3078 0 : if (dump_file)
3079 0 : fprintf (dump_file,
3080 : "Max count in profile %" PRIu64 "\n"
3081 : "Setting scale %" PRIu64 "\n"
3082 : "Scaled max count %" PRIu64 "\n"
3083 : "Cutoff %" PRIu64 "\n"
3084 : "Unscaled hot count threshold %" PRIu64 "\n"
3085 : "Hot count threshold %" PRIu64 "\n\n",
3086 : (int64_t) afdo_profile_info->sum_max, (int64_t) afdo_count_scale,
3087 0 : (int64_t) (afdo_profile_info->sum_max * afdo_count_scale),
3088 0 : (int64_t) afdo_profile_info->cutoff,
3089 0 : (int64_t) afdo_summary_info->get_threshold_count (
3090 0 : param_hot_bb_count_ws_permille * 1000),
3091 : (int64_t) afdo_hot_bb_threshold);
3092 0 : afdo_profile_info->sum_max *= afdo_count_scale;
3093 0 : return true;
3094 : }
3095 :
3096 : /* Return the function_instance in the profile that correspond to the
3097 : inline STACK. */
3098 :
3099 : function_instance *
3100 0 : autofdo_source_profile::get_function_instance_by_inline_stack (
3101 : const inline_stack &stack) const
3102 : {
3103 0 : function_instance_descriptor descriptor (
3104 : afdo_string_table->get_filename_index (
3105 0 : get_normalized_path (DECL_SOURCE_FILE (stack[stack.length () - 1].decl))),
3106 0 : afdo_string_table->get_index_by_decl (stack[stack.length () - 1].decl));
3107 0 : function_instance *s = find_function_instance (descriptor);
3108 :
3109 0 : if (s == NULL)
3110 : {
3111 0 : if (dump_file)
3112 0 : fprintf (dump_file, "No offline instance for %s\n",
3113 0 : raw_symbol_name (stack[stack.length () - 1].decl));
3114 0 : return NULL;
3115 : }
3116 :
3117 0 : for (unsigned i = stack.length () - 1; i > 0; i--)
3118 : {
3119 0 : s = s->get_function_instance_by_decl (stack[i].afdo_loc,
3120 0 : stack[i - 1].decl,
3121 0 : stack[i].location);
3122 0 : if (s == NULL)
3123 : {
3124 : /* afdo inliner extends the stack by last entry with unknown
3125 : location while checking if function was inlined during train run.
3126 : We do not want to print diagnostics about every function
3127 : which is not inlined. */
3128 : if (s && dump_enabled_p () && stack[i].location != UNKNOWN_LOCATION)
3129 : dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS,
3130 : dump_user_location_t::from_location_t
3131 : (stack[i].location),
3132 : "auto-profile has no inlined function instance "
3133 : "for inlined call of %s at relative "
3134 : " location +%i, discriminator %i\n",
3135 : raw_symbol_name (stack[i - 1].decl),
3136 : stack[i].afdo_loc >> 16,
3137 : stack[i].afdo_loc & 65535);
3138 : return NULL;
3139 : }
3140 : }
3141 : return s;
3142 : }
3143 :
3144 : /* Find the matching function instance which has DESCRIPTOR as its
3145 : descriptor. If not found, also try checking if an instance exists with the
3146 : same name which has no associated filename. */
3147 :
3148 : autofdo_source_profile::name_function_instance_map::const_iterator
3149 0 : autofdo_source_profile::find_iter_for_function_instance (
3150 : function_instance_descriptor descriptor) const
3151 : {
3152 0 : auto it = map_.find (descriptor);
3153 :
3154 : /* Try searching for the symbol not having a filename if it isn't found. */
3155 0 : if (it == map_.end ())
3156 0 : it = map_.find (
3157 0 : function_instance_descriptor (string_table::unknown_filename,
3158 0 : (int) descriptor.symbol_name ()));
3159 0 : return it;
3160 : }
3161 :
3162 : /* Similar to the above, but return a pointer to the instance instead of an
3163 : iterator. */
3164 :
3165 : function_instance *
3166 0 : autofdo_source_profile::find_function_instance (
3167 : function_instance_descriptor descriptor) const
3168 : {
3169 0 : auto it = find_iter_for_function_instance (descriptor);
3170 0 : return it == map_.end () ? NULL : it->second;
3171 : }
3172 :
3173 : /* Remove a function instance from the map. Returns true if the entry was
3174 : actually deleted. */
3175 :
3176 : bool
3177 0 : autofdo_source_profile::remove_function_instance (function_instance *inst)
3178 : {
3179 0 : auto iter = find_iter_for_function_instance (inst->get_descriptor ());
3180 0 : if (iter != map_.end ())
3181 : {
3182 0 : map_.erase (iter);
3183 0 : return true;
3184 : }
3185 : return false;
3186 : }
3187 :
3188 : /* Module profile is only used by LIPO. Here we simply ignore it. */
3189 :
3190 : static void
3191 0 : fake_read_autofdo_module_profile ()
3192 : {
3193 : /* Read in the module info. */
3194 0 : gcov_read_unsigned ();
3195 :
3196 : /* Skip the length of the section. */
3197 0 : gcov_read_unsigned ();
3198 :
3199 : /* Read in the file name table. */
3200 0 : unsigned total_module_num = gcov_read_unsigned ();
3201 0 : gcc_assert (total_module_num == 0);
3202 0 : }
3203 :
3204 : /* Read data from profile data file. */
3205 :
3206 : static void
3207 0 : read_profile (void)
3208 : {
3209 0 : if (gcov_open (auto_profile_file, 1) == 0)
3210 : {
3211 0 : error ("cannot open profile file %s", auto_profile_file);
3212 0 : return;
3213 : }
3214 :
3215 0 : if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
3216 : {
3217 0 : error ("AutoFDO profile magic number does not match");
3218 0 : return;
3219 : }
3220 :
3221 : /* Skip the version number. */
3222 0 : unsigned version = gcov_read_unsigned ();
3223 0 : if (version != AUTO_PROFILE_VERSION)
3224 : {
3225 0 : error ("AutoFDO profile version %u does not match %u",
3226 : version, AUTO_PROFILE_VERSION);
3227 0 : return;
3228 : }
3229 :
3230 : /* Skip the empty integer. */
3231 0 : gcov_read_unsigned ();
3232 :
3233 : /* summary_info. */
3234 0 : afdo_summary_info = new summary_info ();
3235 0 : if (!afdo_summary_info->read ())
3236 : {
3237 0 : error ("cannot read summary information from %s", auto_profile_file);
3238 0 : return;
3239 : }
3240 :
3241 : /* string_table. */
3242 0 : afdo_string_table = new string_table ();
3243 0 : if (!afdo_string_table->read ())
3244 : {
3245 0 : error ("cannot read string table from %s", auto_profile_file);
3246 0 : return;
3247 : }
3248 :
3249 : /* autofdo_source_profile. */
3250 0 : afdo_source_profile = autofdo_source_profile::create ();
3251 0 : if (afdo_source_profile == NULL
3252 0 : || gcov_is_error ())
3253 : {
3254 0 : error ("cannot read function profile from %s", auto_profile_file);
3255 0 : delete afdo_source_profile;
3256 0 : afdo_source_profile = NULL;
3257 0 : return;
3258 : }
3259 :
3260 : /* autofdo_module_profile. */
3261 0 : fake_read_autofdo_module_profile ();
3262 0 : if (gcov_is_error ())
3263 : {
3264 0 : error ("cannot read module profile from %s", auto_profile_file);
3265 0 : return;
3266 : }
3267 : }
3268 :
3269 : /* From AutoFDO profiles, find values inside STMT for that we want to measure
3270 : histograms for indirect-call optimization.
3271 :
3272 : This function is actually served for 2 purposes:
3273 : * before annotation, we need to mark histogram, promote and inline
3274 : * after annotation, we just need to mark, and let follow-up logic to
3275 : decide if it needs to promote and inline. */
3276 :
3277 : static bool
3278 0 : afdo_indirect_call (gcall *stmt, const icall_target_map &map,
3279 : bool transform, cgraph_edge *indirect_edge)
3280 : {
3281 0 : tree callee;
3282 :
3283 0 : if (map.size () == 0)
3284 : {
3285 0 : if (dump_file)
3286 0 : fprintf (dump_file, "No targets found\n");
3287 0 : return false;
3288 : }
3289 0 : if (!stmt)
3290 : {
3291 0 : if (dump_file)
3292 0 : fprintf (dump_file, "No call statement\n");
3293 0 : return false;
3294 : }
3295 0 : if (gimple_call_internal_p (stmt))
3296 : {
3297 0 : if (dump_file)
3298 0 : fprintf (dump_file, "Internal call\n");
3299 0 : return false;
3300 : }
3301 0 : if (gimple_call_fndecl (stmt) != NULL_TREE)
3302 : {
3303 0 : if (dump_file)
3304 0 : fprintf (dump_file, "Call is already direct\n");
3305 0 : return false;
3306 : }
3307 :
3308 0 : gcov_type total = 0;
3309 0 : icall_target_map::const_iterator max_iter = map.end ();
3310 :
3311 0 : for (icall_target_map::const_iterator iter = map.begin ();
3312 0 : iter != map.end (); ++iter)
3313 : {
3314 0 : total += iter->second;
3315 0 : if (max_iter == map.end () || max_iter->second < iter->second)
3316 : max_iter = iter;
3317 : }
3318 0 : total *= afdo_count_scale;
3319 0 : struct cgraph_node *direct_call = cgraph_node::get_for_asmname (
3320 0 : get_identifier (afdo_string_table->get_symbol_name (max_iter->first)));
3321 0 : if (direct_call == NULL)
3322 : {
3323 0 : if (dump_file)
3324 0 : fprintf (dump_file, "Failed to find cgraph node for %s\n",
3325 0 : afdo_string_table->get_symbol_name (max_iter->first));
3326 0 : return false;
3327 : }
3328 :
3329 0 : callee = gimple_call_fn (stmt);
3330 :
3331 0 : if (!transform)
3332 : {
3333 0 : if (!direct_call->profile_id)
3334 : {
3335 0 : if (dump_file)
3336 0 : fprintf (dump_file, "No profile id\n");
3337 0 : return false;
3338 : }
3339 0 : histogram_value hist = gimple_alloc_histogram_value (
3340 : cfun, HIST_TYPE_INDIR_CALL, stmt, callee);
3341 0 : hist->n_counters = 4;
3342 0 : hist->hvalue.counters = XNEWVEC (gcov_type, hist->n_counters);
3343 0 : gimple_add_histogram_value (cfun, stmt, hist);
3344 :
3345 : /* Total counter */
3346 0 : hist->hvalue.counters[0] = total;
3347 : /* Number of value/counter pairs */
3348 0 : hist->hvalue.counters[1] = 1;
3349 : /* Value */
3350 0 : hist->hvalue.counters[2] = direct_call->profile_id;
3351 : /* Counter */
3352 0 : hist->hvalue.counters[3] = max_iter->second * afdo_count_scale;
3353 :
3354 0 : if (!direct_call->profile_id)
3355 : {
3356 0 : if (dump_file)
3357 0 : fprintf (dump_file, "Histogram attached\n");
3358 0 : return false;
3359 : }
3360 : return false;
3361 : }
3362 :
3363 0 : if (dump_file)
3364 : {
3365 0 : fprintf (dump_file, "Indirect call -> direct call ");
3366 0 : print_generic_expr (dump_file, callee, TDF_SLIM);
3367 0 : fprintf (dump_file, " => ");
3368 0 : print_generic_expr (dump_file, direct_call->decl, TDF_SLIM);
3369 : }
3370 :
3371 0 : if (!direct_call->definition)
3372 : {
3373 0 : if (dump_file)
3374 0 : fprintf (dump_file, " no definition available\n");
3375 0 : return false;
3376 : }
3377 :
3378 0 : if (dump_file)
3379 : {
3380 0 : fprintf (dump_file, " transformation on insn ");
3381 0 : print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
3382 0 : fprintf (dump_file, "\n");
3383 : }
3384 :
3385 0 : indirect_edge->make_speculative
3386 0 : (direct_call,
3387 0 : gimple_bb (stmt)->count.apply_scale (99, 100));
3388 0 : return true;
3389 : }
3390 :
3391 : /* From AutoFDO profiles, find values inside STMT for that we want to measure
3392 : histograms and adds them to list VALUES. */
3393 :
3394 : static bool
3395 0 : afdo_vpt (gcall *gs, const icall_target_map &map,
3396 : bool transform, cgraph_edge *indirect_edge)
3397 : {
3398 0 : return afdo_indirect_call (gs, map, transform, indirect_edge);
3399 : }
3400 :
3401 : typedef std::set<basic_block> bb_set;
3402 :
3403 : static bool
3404 0 : is_bb_annotated (const basic_block bb, const bb_set &annotated)
3405 : {
3406 0 : if (annotated.find (bb) != annotated.end ())
3407 : {
3408 0 : gcc_checking_assert (bb->count.quality () == AFDO
3409 : || !bb->count.nonzero_p ());
3410 : return true;
3411 : }
3412 0 : gcc_checking_assert (bb->count.quality () != AFDO
3413 : || !bb->count.nonzero_p ());
3414 : return false;
3415 : }
3416 :
3417 : static void
3418 0 : set_bb_annotated (basic_block bb, bb_set *annotated)
3419 : {
3420 0 : gcc_checking_assert (bb->count.quality () == AFDO
3421 : || !bb->count.nonzero_p ());
3422 0 : annotated->insert (bb);
3423 0 : }
3424 :
3425 : /* Update COUNT by known autofdo count C. */
3426 : static void
3427 0 : update_count_by_afdo_count (profile_count *count, gcov_type c)
3428 : {
3429 0 : if (c)
3430 0 : *count = profile_count::from_gcov_type (c).afdo ();
3431 : /* In case we have guessed profile which is already zero, preserve
3432 : quality info. */
3433 0 : else if (count->nonzero_p ()
3434 0 : || count->quality () == GUESSED
3435 0 : || count->quality () == GUESSED_LOCAL)
3436 0 : *count = profile_count::zero ().afdo ();
3437 0 : }
3438 :
3439 : /* Update COUNT by known autofdo count C. */
3440 : static void
3441 0 : update_count_by_afdo_count (profile_count *count, profile_count c)
3442 : {
3443 0 : if (c.nonzero_p ())
3444 0 : *count = c;
3445 : /* In case we have guessed profile which is already zero, preserve
3446 : quality info. */
3447 0 : else if (count->nonzero_p ()
3448 0 : || count->quality () < c.quality ())
3449 0 : *count = c;
3450 0 : }
3451 :
3452 : /* Try to determine unscaled count of edge E.
3453 : Return -1 if nothing is known. */
3454 :
3455 : static gcov_type
3456 0 : afdo_unscaled_edge_count (edge e)
3457 : {
3458 0 : gcov_type max_count = -1;
3459 0 : basic_block bb_succ = e->dest;
3460 0 : count_info info;
3461 0 : if (afdo_source_profile->get_count_info (e->goto_locus, &info))
3462 : {
3463 0 : if (info.count > max_count)
3464 : max_count = info.count;
3465 0 : if (dump_file && info.count)
3466 : {
3467 0 : fprintf (dump_file,
3468 : " goto location of edge %i->%i with count %" PRIu64"\n",
3469 0 : e->src->index, e->dest->index, (int64_t)info.count);
3470 : }
3471 : }
3472 0 : for (gphi_iterator gpi = gsi_start_phis (bb_succ);
3473 0 : !gsi_end_p (gpi); gsi_next (&gpi))
3474 : {
3475 0 : gphi *phi = gpi.phi ();
3476 0 : location_t phi_loc
3477 0 : = gimple_phi_arg_location_from_edge (phi, e);
3478 0 : if (afdo_source_profile->get_count_info (phi_loc, &info))
3479 : {
3480 0 : if (info.count > max_count)
3481 : max_count = info.count;
3482 0 : if (dump_file && info.count)
3483 : {
3484 0 : fprintf (dump_file,
3485 : " phi op of edge %i->%i with count %" PRIu64": ",
3486 0 : e->src->index, e->dest->index, (int64_t)info.count);
3487 0 : print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
3488 : }
3489 : }
3490 : }
3491 0 : return max_count;
3492 0 : }
3493 :
3494 : /* For a given BB, set its execution count. Attach value profile if a stmt
3495 : is not in PROMOTED, because we only want to promote an indirect call once.
3496 : Return TRUE if BB is annotated. */
3497 :
3498 : static bool
3499 0 : afdo_set_bb_count (basic_block bb, hash_set <basic_block> &zero_bbs)
3500 : {
3501 0 : gimple_stmt_iterator gsi;
3502 0 : gcov_type max_count = -1;
3503 0 : if (dump_file)
3504 0 : fprintf (dump_file, " Looking up AFDO count of bb %i\n", bb->index);
3505 :
3506 0 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3507 : {
3508 0 : count_info info;
3509 0 : gimple *stmt = gsi_stmt (gsi);
3510 0 : if (!stmt_loc_used_by_debug_info (stmt))
3511 0 : continue;
3512 0 : if (afdo_source_profile->get_count_info (stmt, &info))
3513 : {
3514 0 : if (info.count > max_count)
3515 : max_count = info.count;
3516 0 : if (dump_file)
3517 : {
3518 0 : fprintf (dump_file, " count %" PRIu64 " in stmt: ",
3519 : (int64_t)info.count);
3520 0 : print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
3521 : }
3522 0 : gcall *call = dyn_cast <gcall *> (gsi_stmt (gsi));
3523 : /* TODO; if inlined early and indirect call was not optimized out,
3524 : we will end up speculating again. Early inliner should remove
3525 : all targets for edges it speculated into safely. */
3526 0 : if (call
3527 0 : && info.targets.size () > 0)
3528 0 : afdo_vpt (call, info.targets, false, NULL);
3529 : }
3530 0 : }
3531 :
3532 0 : if (max_count == -1 && single_succ_p (bb))
3533 0 : max_count = afdo_unscaled_edge_count (single_succ_edge (bb));
3534 :
3535 0 : if (max_count == -1)
3536 : return false;
3537 :
3538 0 : if (max_count)
3539 : {
3540 0 : update_count_by_afdo_count (&bb->count, max_count * afdo_count_scale);
3541 0 : if (dump_file)
3542 0 : fprintf (dump_file,
3543 : " Annotated bb %i with count %" PRId64
3544 : ", scaled to %" PRId64 "\n",
3545 : bb->index, (int64_t)max_count,
3546 0 : (int64_t)(max_count * afdo_count_scale));
3547 0 : return true;
3548 : }
3549 : else
3550 : {
3551 0 : if (dump_file)
3552 0 : fprintf (dump_file,
3553 : " bb %i has statements with 0 count\n", bb->index);
3554 0 : zero_bbs.add (bb);
3555 : }
3556 0 : return false;
3557 : }
3558 :
3559 : /* BB1 and BB2 are in an equivalent class iff:
3560 : 1. BB1 dominates BB2.
3561 : 2. BB2 post-dominates BB1.
3562 : 3. BB1 and BB2 are in the same loop nest.
3563 : This function finds the equivalent class for each basic block, and
3564 : stores a pointer to the first BB in its equivalent class. Meanwhile,
3565 : set bb counts for the same equivalent class to be idenical. Update
3566 : ANNOTATED_BB for the first BB in its equivalent class. */
3567 :
3568 : static void
3569 0 : afdo_find_equiv_class (bb_set *annotated_bb)
3570 : {
3571 0 : basic_block bb;
3572 :
3573 0 : FOR_ALL_BB_FN (bb, cfun)
3574 0 : bb->aux = NULL;
3575 :
3576 0 : FOR_ALL_BB_FN (bb, cfun)
3577 : {
3578 0 : if (bb->aux != NULL)
3579 0 : continue;
3580 0 : bb->aux = bb;
3581 0 : for (basic_block bb1 : get_dominated_by (CDI_DOMINATORS, bb))
3582 0 : if (bb1->aux == NULL && dominated_by_p (CDI_POST_DOMINATORS, bb, bb1)
3583 0 : && bb1->loop_father == bb->loop_father)
3584 : {
3585 0 : bb1->aux = bb;
3586 0 : if (is_bb_annotated (bb1, *annotated_bb)
3587 0 : && (!is_bb_annotated (bb, *annotated_bb)
3588 0 : || bb1->count > bb->count))
3589 : {
3590 0 : if (dump_file)
3591 : {
3592 0 : fprintf (dump_file,
3593 : " Copying count of bb %i to bb %i; count is:",
3594 : bb1->index,
3595 : bb->index);
3596 0 : bb1->count.dump (dump_file);
3597 0 : fprintf (dump_file, "\n");
3598 : }
3599 0 : update_count_by_afdo_count (&bb->count, bb1->count);
3600 0 : set_bb_annotated (bb, annotated_bb);
3601 : }
3602 0 : }
3603 :
3604 0 : for (basic_block bb1 : get_dominated_by (CDI_POST_DOMINATORS, bb))
3605 0 : if (bb1->aux == NULL && dominated_by_p (CDI_DOMINATORS, bb, bb1)
3606 0 : && bb1->loop_father == bb->loop_father)
3607 : {
3608 0 : bb1->aux = bb;
3609 0 : if (is_bb_annotated (bb1, *annotated_bb)
3610 0 : && (!is_bb_annotated (bb, *annotated_bb)
3611 0 : || bb1->count > bb->count))
3612 : {
3613 0 : if (dump_file)
3614 : {
3615 0 : fprintf (dump_file,
3616 : " Copying count of bb %i to bb %i; count is:",
3617 : bb1->index,
3618 : bb->index);
3619 0 : bb1->count.dump (dump_file);
3620 0 : fprintf (dump_file, "\n");
3621 : }
3622 0 : update_count_by_afdo_count (&bb->count, bb1->count);
3623 0 : set_bb_annotated (bb, annotated_bb);
3624 : }
3625 0 : }
3626 : }
3627 0 : }
3628 :
3629 : /* If a basic block's count is known, and only one of its in/out edges' count
3630 : is unknown, its count can be calculated. Meanwhile, if all of the in/out
3631 : edges' counts are known, then the basic block's unknown count can also be
3632 : calculated. Also, if a block has a single predecessor or successor, the block's
3633 : count can be propagated to that predecessor or successor.
3634 : IS_SUCC is true if out edges of a basic blocks are examined.
3635 : Update ANNOTATED_BB accordingly.
3636 : Return TRUE if any basic block/edge count is changed. */
3637 :
3638 : static bool
3639 0 : afdo_propagate_edge (bool is_succ, bb_set *annotated_bb)
3640 : {
3641 0 : basic_block bb;
3642 0 : bool changed = false;
3643 :
3644 0 : FOR_EACH_BB_FN (bb, cfun)
3645 : {
3646 0 : edge e, unknown_edge = NULL;
3647 0 : edge_iterator ei;
3648 0 : int num_unknown_edges = 0;
3649 0 : int num_edges = 0;
3650 0 : profile_count total_known_count = profile_count::zero ().afdo ();
3651 :
3652 0 : FOR_EACH_EDGE (e, ei, is_succ ? bb->succs : bb->preds)
3653 : {
3654 0 : gcc_assert (AFDO_EINFO (e) != NULL);
3655 0 : if (! AFDO_EINFO (e)->is_annotated ())
3656 0 : num_unknown_edges++, unknown_edge = e;
3657 : else
3658 0 : total_known_count += AFDO_EINFO (e)->get_count ();
3659 0 : num_edges++;
3660 : }
3661 0 : if (dump_file)
3662 : {
3663 0 : fprintf (dump_file, "bb %i %s propagating %s edges %i, "
3664 : "unknown edges %i, known count ",
3665 : bb->index,
3666 0 : is_bb_annotated (bb, *annotated_bb) ? "(annotated)" : "",
3667 : is_succ ? "successors" : "predecessors", num_edges,
3668 : num_unknown_edges);
3669 0 : total_known_count.dump (dump_file);
3670 0 : fprintf (dump_file, " bb count ");
3671 0 : bb->count.dump (dump_file);
3672 0 : fprintf (dump_file, "\n");
3673 : }
3674 :
3675 : /* Be careful not to annotate block with no successor in special cases. */
3676 0 : if (num_unknown_edges == 0 && num_edges
3677 0 : && !is_bb_annotated (bb, *annotated_bb))
3678 : {
3679 0 : if (dump_file)
3680 : {
3681 0 : fprintf (dump_file, " Annotating bb %i with count ", bb->index);
3682 0 : total_known_count.dump (dump_file);
3683 0 : fprintf (dump_file, "\n");
3684 : }
3685 0 : update_count_by_afdo_count (&bb->count, total_known_count);
3686 0 : set_bb_annotated (bb, annotated_bb);
3687 0 : changed = true;
3688 : }
3689 0 : else if (is_bb_annotated (bb, *annotated_bb)
3690 : /* We do not want to consider 0 (afdo) > 0 (precise) */
3691 0 : && total_known_count.nonzero_p ()
3692 0 : && bb->count < total_known_count)
3693 : {
3694 0 : if (dump_file)
3695 : {
3696 0 : fprintf (dump_file, " Increasing bb %i count from ",
3697 : bb->index);
3698 0 : bb->count.dump (dump_file);
3699 0 : fprintf (dump_file, " to ");
3700 0 : total_known_count.dump (dump_file);
3701 0 : fprintf (dump_file, " hoping to mitigate afdo inconsistency\n");
3702 : }
3703 0 : bb->count = total_known_count;
3704 0 : changed = true;
3705 : }
3706 0 : else if (num_unknown_edges == 1 && is_bb_annotated (bb, *annotated_bb))
3707 : {
3708 0 : if (bb->count > total_known_count)
3709 : {
3710 0 : profile_count new_count = bb->count - total_known_count;
3711 0 : AFDO_EINFO (unknown_edge)->set_count (new_count);
3712 : }
3713 : else
3714 0 : AFDO_EINFO (unknown_edge)->set_count
3715 0 : (profile_count::zero ().afdo ());
3716 0 : if (dump_file)
3717 : {
3718 0 : fprintf (dump_file, " Annotated edge %i->%i with count ",
3719 0 : unknown_edge->src->index, unknown_edge->dest->index);
3720 0 : AFDO_EINFO (unknown_edge)->get_count ().dump (dump_file);
3721 0 : fprintf (dump_file, "\n");
3722 : }
3723 0 : AFDO_EINFO (unknown_edge)->set_annotated ();
3724 0 : changed = true;
3725 : }
3726 0 : else if (num_unknown_edges > 1
3727 0 : && is_bb_annotated (bb, *annotated_bb)
3728 0 : && (total_known_count >= bb->count || !bb->count.nonzero_p ()))
3729 : {
3730 0 : FOR_EACH_EDGE (e, ei, is_succ ? bb->succs : bb->preds)
3731 : {
3732 0 : gcc_assert (AFDO_EINFO (e) != NULL);
3733 0 : if (! AFDO_EINFO (e)->is_annotated ())
3734 : {
3735 0 : AFDO_EINFO (e)->set_count
3736 0 : (profile_count::zero ().afdo ());
3737 0 : AFDO_EINFO (e)->set_annotated ();
3738 0 : if (dump_file)
3739 : {
3740 0 : fprintf (dump_file, " Annotated edge %i->%i with count ",
3741 0 : e->src->index, e->dest->index);
3742 0 : AFDO_EINFO (unknown_edge)->get_count ().dump (dump_file);
3743 0 : fprintf (dump_file, "\n");
3744 : }
3745 : }
3746 : }
3747 : }
3748 0 : else if (num_unknown_edges == 0
3749 0 : && is_bb_annotated (bb, *annotated_bb)
3750 0 : && (is_succ ? single_succ_p (bb) : single_pred_p (bb)))
3751 : {
3752 0 : edge e = is_succ ? single_succ_edge (bb) : single_pred_edge (bb);
3753 0 : if (AFDO_EINFO (e)->is_annotated ()
3754 0 : && AFDO_EINFO (e)->get_count () < bb->count)
3755 : {
3756 0 : if (dump_file)
3757 : {
3758 0 : fprintf (dump_file, " Increasing edge %i->%i count from ",
3759 0 : e->src->index, e->dest->index);
3760 0 : AFDO_EINFO (e)->get_count ().dump (dump_file);
3761 0 : fprintf (dump_file, " to ");
3762 0 : bb->count.dump (dump_file);
3763 0 : fprintf (dump_file, " hoping to mitigate afdo inconsistency\n");
3764 : }
3765 0 : AFDO_EINFO (e)->set_count (bb->count);
3766 0 : changed = true;
3767 : }
3768 : }
3769 : }
3770 0 : return changed;
3771 : }
3772 :
3773 : /* Special propagation for circuit expressions. Because GCC translates
3774 : control flow into data flow for circuit expressions. E.g.
3775 : BB1:
3776 : if (a && b)
3777 : BB2
3778 : else
3779 : BB3
3780 :
3781 : will be translated into:
3782 :
3783 : BB1:
3784 : if (a)
3785 : goto BB.t1
3786 : else
3787 : goto BB.t3
3788 : BB.t1:
3789 : if (b)
3790 : goto BB.t2
3791 : else
3792 : goto BB.t3
3793 : BB.t2:
3794 : goto BB.t3
3795 : BB.t3:
3796 : tmp = PHI (0 (BB1), 0 (BB.t1), 1 (BB.t2)
3797 : if (tmp)
3798 : goto BB2
3799 : else
3800 : goto BB3
3801 :
3802 : In this case, we need to propagate through PHI to determine the edge
3803 : count of BB1->BB.t1, BB.t1->BB.t2. */
3804 :
3805 : static void
3806 0 : afdo_propagate_circuit (const bb_set &annotated_bb)
3807 : {
3808 0 : basic_block bb;
3809 0 : FOR_ALL_BB_FN (bb, cfun)
3810 : {
3811 0 : gimple *def_stmt;
3812 0 : tree cmp_rhs, cmp_lhs;
3813 0 : gimple *cmp_stmt = last_nondebug_stmt (bb);
3814 0 : edge e;
3815 0 : edge_iterator ei;
3816 :
3817 0 : if (!cmp_stmt || gimple_code (cmp_stmt) != GIMPLE_COND)
3818 0 : continue;
3819 0 : cmp_rhs = gimple_cond_rhs (cmp_stmt);
3820 0 : cmp_lhs = gimple_cond_lhs (cmp_stmt);
3821 0 : if (!TREE_CONSTANT (cmp_rhs)
3822 0 : || !(integer_zerop (cmp_rhs) || integer_onep (cmp_rhs)))
3823 0 : continue;
3824 0 : if (TREE_CODE (cmp_lhs) != SSA_NAME)
3825 0 : continue;
3826 0 : if (!is_bb_annotated (bb, annotated_bb))
3827 0 : continue;
3828 0 : def_stmt = SSA_NAME_DEF_STMT (cmp_lhs);
3829 0 : while (def_stmt && gimple_code (def_stmt) == GIMPLE_ASSIGN
3830 0 : && gimple_assign_single_p (def_stmt)
3831 0 : && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
3832 0 : def_stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def_stmt));
3833 0 : if (!def_stmt)
3834 0 : continue;
3835 0 : gphi *phi_stmt = dyn_cast <gphi *> (def_stmt);
3836 0 : if (!phi_stmt)
3837 0 : continue;
3838 0 : FOR_EACH_EDGE (e, ei, bb->succs)
3839 : {
3840 0 : unsigned i, total = 0;
3841 0 : edge only_one;
3842 0 : bool check_value_one = (((integer_onep (cmp_rhs))
3843 0 : ^ (gimple_cond_code (cmp_stmt) == EQ_EXPR))
3844 0 : ^ ((e->flags & EDGE_TRUE_VALUE) != 0));
3845 0 : if (! AFDO_EINFO (e)->is_annotated ())
3846 0 : continue;
3847 0 : for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
3848 : {
3849 0 : tree val = gimple_phi_arg_def (phi_stmt, i);
3850 0 : edge ep = gimple_phi_arg_edge (phi_stmt, i);
3851 :
3852 0 : if (!TREE_CONSTANT (val)
3853 0 : || !(integer_zerop (val) || integer_onep (val)))
3854 0 : continue;
3855 0 : if (check_value_one ^ integer_onep (val))
3856 0 : continue;
3857 0 : total++;
3858 0 : only_one = ep;
3859 0 : if (! (AFDO_EINFO (e)->get_count ()).nonzero_p ()
3860 0 : && ! AFDO_EINFO (ep)->is_annotated ())
3861 : {
3862 0 : AFDO_EINFO (ep)->set_count (profile_count::zero ().afdo ());
3863 0 : AFDO_EINFO (ep)->set_annotated ();
3864 : }
3865 : }
3866 0 : if (total == 1 && ! AFDO_EINFO (only_one)->is_annotated ())
3867 : {
3868 0 : AFDO_EINFO (only_one)->set_count (AFDO_EINFO (e)->get_count ());
3869 0 : AFDO_EINFO (only_one)->set_annotated ();
3870 : }
3871 : }
3872 : }
3873 0 : }
3874 :
3875 : /* Propagate the basic block count and edge count on the control flow
3876 : graph. We do the propagation iteratively until stabilize. */
3877 :
3878 : static void
3879 0 : afdo_propagate (bb_set *annotated_bb)
3880 : {
3881 0 : bool changed = true;
3882 0 : int i = 0;
3883 :
3884 0 : basic_block bb;
3885 0 : FOR_ALL_BB_FN (bb, cfun)
3886 0 : if (!is_bb_annotated (bb, *annotated_bb)
3887 0 : && is_bb_annotated ((basic_block)bb->aux, *annotated_bb))
3888 : {
3889 0 : update_count_by_afdo_count (&bb->count, ((basic_block)bb->aux)->count);
3890 0 : set_bb_annotated (bb, annotated_bb);
3891 0 : if (dump_file)
3892 : {
3893 0 : fprintf (dump_file,
3894 : " Copying count of bb %i to bb %i; count is:",
3895 0 : ((basic_block)bb->aux)->index,
3896 : bb->index);
3897 0 : bb->count.dump (dump_file);
3898 0 : fprintf (dump_file, "\n");
3899 : }
3900 : }
3901 :
3902 0 : while (changed && i++ < 100)
3903 : {
3904 0 : changed = false;
3905 :
3906 0 : if (afdo_propagate_edge (true, annotated_bb))
3907 : changed = true;
3908 0 : if (afdo_propagate_edge (false, annotated_bb))
3909 0 : changed = true;
3910 0 : afdo_propagate_circuit (*annotated_bb);
3911 : }
3912 0 : if (dump_file)
3913 0 : fprintf (dump_file, "Propagation took %i iterations %s\n",
3914 : i, changed ? "; iteration limit reached\n" : "");
3915 0 : }
3916 :
3917 : /* qsort comparator of sreals. */
3918 : static int
3919 0 : cmp (const void *a, const void *b)
3920 : {
3921 0 : if (*(const sreal *)a < *(const sreal *)b)
3922 : return 1;
3923 0 : if (*(const sreal *)a > *(const sreal *)b)
3924 0 : return -1;
3925 : return 0;
3926 : }
3927 :
3928 : /* To scale a connected component of graph we collect desired scales of
3929 : basic blocks on the boundary and then compute a robust average. */
3930 :
3931 : struct scale
3932 : {
3933 : /* Scale desired. */
3934 : sreal scale;
3935 : /* Weight for averaging computed from execution count of the edge
3936 : scale originates from. */
3937 : uint64_t weight;
3938 : };
3939 :
3940 : /* Add scale ORIG/ANNOTATED to SCALES. */
3941 :
3942 : static void
3943 0 : add_scale (vec <scale> *scales, profile_count annotated, profile_count orig)
3944 : {
3945 0 : if (dump_file)
3946 : {
3947 0 : orig.dump (dump_file);
3948 0 : fprintf (dump_file, " should be ");
3949 0 : annotated.dump (dump_file);
3950 0 : fprintf (dump_file, "\n");
3951 : }
3952 0 : if (orig.nonzero_p ())
3953 : {
3954 0 : sreal scale
3955 0 : = annotated.guessed_local ()
3956 0 : .to_sreal_scale (orig);
3957 0 : if (dump_file)
3958 0 : fprintf (dump_file, " adding scale %.16f, weight %" PRId64 "\n",
3959 0 : scale.to_double (), annotated.value () + 1);
3960 0 : scales->safe_push ({scale, annotated.value () + 1});
3961 : }
3962 0 : }
3963 :
3964 : /* Scale counts of all basic blocks in BBS by SCALE and convert them to
3965 : IPA quality. */
3966 :
3967 : static void
3968 0 : scale_bbs (const vec <basic_block> &bbs, sreal scale)
3969 : {
3970 0 : if (dump_file)
3971 0 : fprintf (dump_file, " Scaling by %.16f\n", scale.to_double ());
3972 0 : for (basic_block b : bbs)
3973 0 : if (!(b->count == profile_count::zero ())
3974 0 : && b->count.initialized_p ())
3975 : {
3976 0 : profile_count o = b->count;
3977 0 : b->count = b->count.force_guessed () * scale;
3978 :
3979 : /* If we scaled to 0, make it auto-fdo since that is treated
3980 : less agressively. */
3981 0 : if (!b->count.nonzero_p () && o.nonzero_p ())
3982 0 : b->count = profile_count::zero ().afdo ();
3983 0 : if (dump_file)
3984 : {
3985 0 : fprintf (dump_file, " bb %i count updated ", b->index);
3986 0 : o.dump (dump_file);
3987 0 : fprintf (dump_file, " -> ");
3988 0 : b->count.dump (dump_file);
3989 0 : fprintf (dump_file, "\n");
3990 : }
3991 : }
3992 0 : }
3993 :
3994 : /* Determine scaling factor by taking robust average of SCALES
3995 : and taking into account limits.
3996 : MAX_COUNT is maximal guessed count to be scaled while MAC_COUNT_IN_FN
3997 : is maximal count in function determined by auto-fdo. */
3998 :
3999 : sreal
4000 0 : determine_scale (vec <scale> *scales, profile_count max_count,
4001 : profile_count max_count_in_fn)
4002 : {
4003 0 : scales->qsort (cmp);
4004 :
4005 0 : uint64_t overall_weight = 0;
4006 0 : for (scale &e : *scales)
4007 0 : overall_weight += e.weight;
4008 :
4009 0 : uint64_t cummulated = 0, weight_sum = 0;
4010 0 : sreal scale_sum = 0;
4011 0 : for (scale &e : *scales)
4012 : {
4013 0 : uint64_t prev = cummulated;
4014 0 : cummulated += e.weight;
4015 0 : if (cummulated >= overall_weight / 4
4016 0 : && prev <= 3 * overall_weight / 4)
4017 : {
4018 0 : scale_sum += e.scale * e.weight;
4019 0 : weight_sum += e.weight;
4020 0 : if (dump_file)
4021 0 : fprintf (dump_file, " accounting scale %.16f, weight %" PRId64 "\n",
4022 : e.scale.to_double (), e.weight);
4023 : }
4024 0 : else if (dump_file)
4025 0 : fprintf (dump_file, " ignoring scale %.16f, weight %" PRId64 "\n",
4026 : e.scale.to_double (), e.weight);
4027 : }
4028 0 : sreal scale = scale_sum / (sreal)weight_sum;
4029 :
4030 : /* Avoid scaled regions to have very large counts.
4031 : Otherwise they may dominate ipa-profile's histogram computing cutoff
4032 : of hot basic blocks. */
4033 0 : if (max_count * scale > max_count_in_fn.guessed_local ().apply_scale (128, 1))
4034 : {
4035 0 : if (dump_file)
4036 : {
4037 0 : fprintf (dump_file, "Scaling by %.16f produces max count ",
4038 : scale.to_double ());
4039 0 : (max_count * scale).dump (dump_file);
4040 0 : fprintf (dump_file, " that exceeds max count in fn ");
4041 0 : max_count_in_fn.dump (dump_file);
4042 0 : fprintf (dump_file, "; capping\n");
4043 : }
4044 0 : scale = max_count_in_fn.guessed_local ().to_sreal_scale (max_count);
4045 : }
4046 0 : return scale;
4047 : }
4048 :
4049 : /* Scale profile of the whole function to approximately match auto-profile. */
4050 :
4051 : bool
4052 0 : scale_bb_profile ()
4053 : {
4054 0 : const function_instance *s
4055 : = afdo_source_profile->get_function_instance_by_decl
4056 0 : (current_function_decl);
4057 :
4058 : /* In the first pass only store non-zero counts. */
4059 0 : gcov_type head_count = s->head_count () * autofdo::afdo_count_scale;
4060 0 : hash_set <basic_block> zero_bbs;
4061 0 : auto_vec <basic_block, 20> bbs (n_basic_blocks_for_fn (cfun));
4062 0 : auto_vec <scale, 20> scales;
4063 0 : basic_block bb;
4064 0 : profile_count max_count = profile_count::zero ();
4065 0 : profile_count max_count_in_fn = profile_count::zero ();
4066 0 : bbs.quick_push (ENTRY_BLOCK_PTR_FOR_FN (cfun));
4067 0 : bbs.quick_push (EXIT_BLOCK_PTR_FOR_FN (cfun));
4068 0 : if (head_count > 0)
4069 : {
4070 0 : profile_count entry_count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
4071 0 : max_count = entry_count;
4072 0 : update_count_by_afdo_count (&entry_count, head_count);
4073 0 : max_count_in_fn = entry_count;
4074 0 : add_scale (&scales, entry_count, ENTRY_BLOCK_PTR_FOR_FN (cfun)->count);
4075 : }
4076 0 : FOR_EACH_BB_FN (bb, cfun)
4077 : {
4078 0 : profile_count cnt = bb->count;
4079 0 : bbs.safe_push (bb);
4080 0 : max_count = profile_count::max_prefer_initialized (max_count, cnt);
4081 0 : if (afdo_set_bb_count (bb, zero_bbs))
4082 : {
4083 0 : std::swap (cnt, bb->count);
4084 0 : max_count_in_fn
4085 0 : = profile_count::max_prefer_initialized (max_count_in_fn, cnt);
4086 0 : add_scale (&scales, cnt, bb->count);
4087 : }
4088 : }
4089 0 : if (scales.length ())
4090 : {
4091 0 : sreal scale = determine_scale (&scales, max_count, max_count_in_fn);
4092 0 : scale_bbs (bbs, scale);
4093 0 : return true;
4094 : }
4095 : return false;
4096 0 : }
4097 :
4098 : /* In case given basic block was fully optimized out, AutoFDO
4099 : will have no data about it. In this case try to preserve static profile.
4100 : Identify connected components (in undirected form of CFG) which has
4101 : no annotations at all. Look at thir boundaries and try to determine
4102 : scaling factor and scale. */
4103 :
4104 : void
4105 0 : afdo_adjust_guessed_profile (bb_set *annotated_bb)
4106 : {
4107 : /* Basic blocks of connected component currently processed. */
4108 0 : auto_vec <basic_block, 20> bbs (n_basic_blocks_for_fn (cfun));
4109 : /* Scale factors found. */
4110 0 : auto_vec <scale, 20> scales;
4111 0 : auto_vec <basic_block, 20> stack (n_basic_blocks_for_fn (cfun));
4112 :
4113 0 : basic_block seed_bb;
4114 0 : unsigned int component_id = 1;
4115 :
4116 : /* Map from basic block to its component.
4117 : 0 is used for univisited BBs,
4118 : 1 means that BB is annotated,
4119 : >=2 is an id of the component BB belongs to. */
4120 0 : auto_vec <unsigned int, 20> component;
4121 0 : component.safe_grow (last_basic_block_for_fn (cfun));
4122 0 : profile_count max_count_in_fn = profile_count::zero ();
4123 0 : FOR_ALL_BB_FN (seed_bb, cfun)
4124 0 : if (is_bb_annotated (seed_bb, *annotated_bb))
4125 : {
4126 0 : component[seed_bb->index] = 1;
4127 0 : max_count_in_fn
4128 0 : = profile_count::max_prefer_initialized (max_count_in_fn, seed_bb->count);
4129 : }
4130 : else
4131 0 : component[seed_bb->index] = 0;
4132 0 : FOR_ALL_BB_FN (seed_bb, cfun)
4133 0 : if (!component[seed_bb->index])
4134 : {
4135 0 : stack.quick_push (seed_bb);
4136 0 : component_id++;
4137 0 : bbs.truncate (0);
4138 0 : scales.truncate (0);
4139 0 : component[seed_bb->index] = component_id;
4140 0 : profile_count max_count = profile_count::zero ();
4141 :
4142 : /* Identify connected component starting in BB. */
4143 0 : if (dump_file)
4144 0 : fprintf (dump_file, "Starting connected component in bb %i\n",
4145 : seed_bb->index);
4146 0 : do
4147 : {
4148 0 : basic_block b = stack.pop ();
4149 :
4150 0 : bbs.quick_push (b);
4151 0 : max_count = profile_count::max_prefer_initialized (max_count, b->count);
4152 :
4153 0 : for (edge e: b->preds)
4154 0 : if (!component[e->src->index])
4155 : {
4156 0 : stack.quick_push (e->src);
4157 0 : component[e->src->index] = component_id;
4158 : }
4159 0 : for (edge e: b->succs)
4160 0 : if (!component[e->dest->index])
4161 : {
4162 0 : stack.quick_push (e->dest);
4163 0 : component[e->dest->index] = component_id;
4164 : }
4165 : }
4166 0 : while (!stack.is_empty ());
4167 :
4168 : /* If all blocks in components has 0 count, we do not need
4169 : to scale, only we must convert to IPA quality. */
4170 0 : if (!max_count.nonzero_p ())
4171 : {
4172 0 : if (dump_file)
4173 0 : fprintf (dump_file, " All counts are 0; scale = 1\n");
4174 0 : scale_bbs (bbs, 1);
4175 0 : continue;
4176 : }
4177 :
4178 : /* Now visit the component and try to figure out its desired
4179 : frequency. */
4180 0 : for (basic_block b : bbs)
4181 : {
4182 0 : if (dump_file)
4183 : {
4184 0 : fprintf (dump_file, " visiting bb %i with count ", b->index);
4185 0 : b->count.dump (dump_file);
4186 0 : fprintf (dump_file, "\n");
4187 : }
4188 0 : if (!b->count.nonzero_p ())
4189 0 : continue;
4190 : /* Sum of counts of annotated edges into B. */
4191 0 : profile_count annotated_count = profile_count::zero ();
4192 : /* Sum of counts of edges into B with source in current
4193 : component. */
4194 0 : profile_count current_component_count = profile_count::zero ();
4195 0 : bool boundary = false;
4196 :
4197 0 : for (edge e: b->preds)
4198 0 : if (AFDO_EINFO (e)->is_annotated ())
4199 : {
4200 0 : if (dump_file)
4201 : {
4202 0 : fprintf (dump_file, " Annotated pred edge to %i "
4203 0 : "with count ", e->src->index);
4204 0 : AFDO_EINFO (e)->get_count ().dump (dump_file);
4205 0 : fprintf (dump_file, "\n");
4206 : }
4207 0 : boundary = true;
4208 0 : annotated_count += AFDO_EINFO (e)->get_count ();
4209 : }
4210 : /* If source is anotated, combine with static
4211 : probability prediction.
4212 : TODO: We can do better in case some of edges out are
4213 : annotated and distribute only remaining count out of BB. */
4214 0 : else if (is_bb_annotated (e->src, *annotated_bb))
4215 : {
4216 0 : boundary = true;
4217 0 : if (dump_file)
4218 : {
4219 0 : fprintf (dump_file, " Annotated predecessor %i "
4220 : "with count ", e->src->index);
4221 0 : e->src->count.dump (dump_file);
4222 0 : fprintf (dump_file, " edge count using static profile ");
4223 0 : e->count ().dump (dump_file);
4224 0 : fprintf (dump_file, "\n");
4225 : }
4226 0 : annotated_count += e->count ();
4227 : }
4228 : else
4229 : {
4230 0 : current_component_count += e->count ();
4231 0 : gcc_checking_assert (component[e->src->index] == component_id);
4232 : }
4233 0 : if (boundary && current_component_count.initialized_p ())
4234 : {
4235 0 : if (dump_file)
4236 0 : fprintf (dump_file, " bb %i in count ", b->index);
4237 0 : add_scale (&scales,
4238 : annotated_count,
4239 : b->count - current_component_count);
4240 : }
4241 0 : for (edge e: b->succs)
4242 0 : if (AFDO_EINFO (e)->is_annotated ())
4243 : {
4244 0 : if (dump_file)
4245 0 : fprintf (dump_file, " edge %i->%i count ",
4246 0 : b->index, e->dest->index);
4247 0 : add_scale (&scales, AFDO_EINFO (e)->get_count (), e->count ());
4248 : }
4249 0 : else if (is_bb_annotated (e->dest, *annotated_bb))
4250 : {
4251 0 : profile_count annotated_count = e->dest->count;
4252 0 : profile_count out_count = profile_count::zero ();
4253 0 : bool ok = true;
4254 :
4255 0 : for (edge e2: e->dest->preds)
4256 0 : if (AFDO_EINFO (e2)->is_annotated ())
4257 0 : annotated_count -= AFDO_EINFO (e2)->get_count ();
4258 0 : else if (component[e2->src->index] == component_id)
4259 0 : out_count += e2->count ();
4260 0 : else if (is_bb_annotated (e2->src, *annotated_bb))
4261 0 : annotated_count -= e2->count ();
4262 0 : else if (e2->probability.nonzero_p ())
4263 : {
4264 : ok = false;
4265 : break;
4266 : }
4267 0 : if (!ok)
4268 0 : continue;
4269 0 : if (dump_file)
4270 0 : fprintf (dump_file,
4271 : " edge %i->%i has annotated successor; count ",
4272 0 : b->index, e->dest->index);
4273 0 : add_scale (&scales, annotated_count, e->count ());
4274 : }
4275 :
4276 : }
4277 :
4278 : /* If we failed to find annotated entry or exit edge,
4279 : look for exit edges and scale profile so the dest
4280 : BB get all flow it needs. This is imprecise because
4281 : the edge is not annotated and thus BB has more than
4282 : one such predecessor. */
4283 0 : if (!scales.length ())
4284 0 : for (basic_block b : bbs)
4285 0 : if (b->count.nonzero_p ())
4286 0 : for (edge e: b->succs)
4287 0 : if (is_bb_annotated (e->dest, *annotated_bb))
4288 : {
4289 0 : profile_count annotated_count = e->dest->count;
4290 0 : for (edge e2: e->dest->preds)
4291 0 : if (AFDO_EINFO (e2)->is_annotated ())
4292 0 : annotated_count -= AFDO_EINFO (e2)->get_count ();
4293 0 : if (dump_file)
4294 0 : fprintf (dump_file,
4295 : " edge %i->%i has annotated successor;"
4296 : " upper bound count ",
4297 0 : b->index, e->dest->index);
4298 0 : add_scale (&scales, annotated_count, e->count ());
4299 : }
4300 0 : if (!scales.length ())
4301 : {
4302 0 : if (dump_file)
4303 0 : fprintf (dump_file,
4304 : " Can not determine count from the boundary; giving up\n");
4305 0 : continue;
4306 : }
4307 0 : gcc_checking_assert (scales.length ());
4308 0 : sreal scale = determine_scale (&scales, max_count, max_count_in_fn);
4309 0 : scale_bbs (bbs, scale);
4310 : }
4311 0 : }
4312 :
4313 : /* Propagate counts on control flow graph and calculate branch
4314 : probabilities. */
4315 :
4316 : static void
4317 0 : afdo_calculate_branch_prob (bb_set *annotated_bb)
4318 : {
4319 0 : edge e;
4320 0 : edge_iterator ei;
4321 0 : basic_block bb;
4322 :
4323 0 : FOR_ALL_BB_FN (bb, cfun)
4324 : {
4325 0 : gcc_assert (bb->aux == NULL);
4326 0 : FOR_EACH_EDGE (e, ei, bb->succs)
4327 : {
4328 0 : gcc_assert (e->aux == NULL);
4329 0 : e->aux = new edge_info ();
4330 0 : gcov_type c = afdo_unscaled_edge_count (e);
4331 0 : if (c == 0 && e->count () == profile_count::zero ())
4332 : {
4333 0 : AFDO_EINFO (e)->set_count (profile_count::zero ());
4334 0 : if (dump_file)
4335 0 : fprintf (dump_file,
4336 : " Annotating edge %i->%i with count 0;"
4337 : " static profile aggress",
4338 0 : e->src->index, e->dest->index);
4339 : }
4340 0 : else if (c > 0)
4341 : {
4342 0 : AFDO_EINFO (e)->set_count
4343 0 : (profile_count::from_gcov_type
4344 0 : (c * autofdo::afdo_count_scale).afdo ());
4345 0 : if (dump_file)
4346 : {
4347 0 : fprintf (dump_file,
4348 : " Annotating edge %i->%i with count ",
4349 0 : e->src->index, e->dest->index);
4350 0 : AFDO_EINFO (e)->get_count ().dump (dump_file);
4351 0 : fprintf (dump_file, "\n");
4352 : }
4353 : }
4354 : }
4355 : }
4356 :
4357 0 : afdo_find_equiv_class (annotated_bb);
4358 0 : afdo_propagate (annotated_bb);
4359 :
4360 0 : FOR_EACH_BB_FN (bb, cfun)
4361 0 : if (is_bb_annotated (bb, *annotated_bb))
4362 : {
4363 0 : bool all_known = true;
4364 0 : profile_count total_count = profile_count::zero ().afdo ();
4365 :
4366 0 : FOR_EACH_EDGE (e, ei, bb->succs)
4367 : {
4368 0 : gcc_assert (AFDO_EINFO (e) != NULL);
4369 0 : if (! AFDO_EINFO (e)->is_annotated ())
4370 : {
4371 : /* If by static profile this edge never happens,
4372 : still propagate the rest. */
4373 0 : if (e->probability.nonzero_p ())
4374 : {
4375 : all_known = false;
4376 : break;
4377 : }
4378 : }
4379 : else
4380 0 : total_count += AFDO_EINFO (e)->get_count ();
4381 : }
4382 0 : if (!all_known || !total_count.nonzero_p ())
4383 0 : continue;
4384 0 : if (dump_file)
4385 : {
4386 0 : fprintf (dump_file, "Total count of bb %i is ", bb->index);
4387 0 : total_count.dump (dump_file);
4388 0 : fprintf (dump_file, "\n");
4389 : }
4390 :
4391 0 : FOR_EACH_EDGE (e, ei, bb->succs)
4392 0 : if (AFDO_EINFO (e)->is_annotated ())
4393 : {
4394 0 : profile_count cnt = AFDO_EINFO (e)->get_count ();
4395 : /* If probability is 1, preserve reliable static prediction
4396 : (This is, for example the case of single fallthru edge
4397 : or single fallthru plus unlikely EH edge.) */
4398 0 : if (cnt == total_count
4399 0 : && e->probability == profile_probability::always ())
4400 : ;
4401 0 : else if (cnt.nonzero_p ())
4402 0 : e->probability
4403 0 : = cnt.probability_in (total_count);
4404 : /* If probability is zero, preserve reliable static
4405 : prediction. */
4406 0 : else if (e->probability.nonzero_p ()
4407 0 : || e->probability.quality () == GUESSED)
4408 0 : e->probability = profile_probability::never ().afdo ();
4409 0 : if (dump_file)
4410 : {
4411 0 : fprintf (dump_file, " probability of edge %i->%i"
4412 : " with count ",
4413 0 : e->src->index, e->dest->index);
4414 0 : cnt.dump (dump_file);
4415 0 : fprintf (dump_file, " set to ");
4416 0 : e->probability.dump (dump_file);
4417 0 : fprintf (dump_file, "\n");
4418 : }
4419 : }
4420 : }
4421 0 : afdo_adjust_guessed_profile (annotated_bb);
4422 0 : FOR_ALL_BB_FN (bb, cfun)
4423 : {
4424 0 : bb->aux = NULL;
4425 0 : FOR_EACH_EDGE (e, ei, bb->succs)
4426 0 : if (AFDO_EINFO (e) != NULL)
4427 : {
4428 0 : delete AFDO_EINFO (e);
4429 0 : e->aux = NULL;
4430 : }
4431 : }
4432 0 : }
4433 :
4434 : /* Annotate auto profile to the control flow graph. */
4435 :
4436 : static void
4437 0 : afdo_annotate_cfg (void)
4438 : {
4439 0 : basic_block bb;
4440 0 : bb_set annotated_bb;
4441 0 : const function_instance *s
4442 0 : = afdo_source_profile->get_function_instance_by_decl (
4443 : current_function_decl);
4444 :
4445 : /* FIXME: This is a workaround for sourcefile tracking, if afdo_string_table
4446 : ends up with empty filename or incorrect filename for the function and
4447 : should be removed once issues with sourcefile tracking get fixed. */
4448 0 : if (s == NULL)
4449 0 : for (unsigned i = 0; i < afdo_string_table->filenames ().length (); i++)
4450 : {
4451 0 : s = afdo_source_profile->get_function_instance_by_decl (current_function_decl, afdo_string_table->filenames()[i]);
4452 0 : if (s)
4453 : break;
4454 : }
4455 :
4456 0 : if (s == NULL)
4457 : {
4458 0 : if (dump_file)
4459 0 : fprintf (dump_file, "No afdo profile for %s\n",
4460 0 : cgraph_node::get (current_function_decl)->dump_name ());
4461 : /* create_gcov only dumps symbols with some samples in them.
4462 : This means that we get nonempty zero_bbs only if some
4463 : nonzero counts in profile were not matched with statements. */
4464 0 : if (!flag_profile_partial_training
4465 0 : && !param_auto_profile_reorder_only)
4466 : {
4467 0 : FOR_ALL_BB_FN (bb, cfun)
4468 0 : if (bb->count.quality () == GUESSED_LOCAL)
4469 0 : bb->count = bb->count.global0afdo ();
4470 0 : update_max_bb_count ();
4471 : }
4472 0 : return;
4473 : }
4474 :
4475 0 : auto ts_it = timestamp_info_map.find (s->timestamp ());
4476 0 : if (ts_it != timestamp_info_map.end ())
4477 : {
4478 0 : cgraph_node *node = cgraph_node::get (current_function_decl);
4479 0 : node->tp_first_run = ts_it->second;
4480 :
4481 0 : if (dump_file)
4482 0 : fprintf (dump_file, "Setting %s->tp_first_run to %d\n",
4483 : node->asm_name (), node->tp_first_run);
4484 : }
4485 :
4486 0 : if (param_auto_profile_reorder_only)
4487 : return;
4488 :
4489 0 : calculate_dominance_info (CDI_POST_DOMINATORS);
4490 0 : calculate_dominance_info (CDI_DOMINATORS);
4491 0 : loop_optimizer_init (0);
4492 :
4493 0 : if (dump_file)
4494 : {
4495 0 : fprintf (dump_file, "\n\nAnnotating BB profile of %s\n",
4496 0 : cgraph_node::get (current_function_decl)->dump_name ());
4497 0 : fprintf (dump_file, "\n");
4498 0 : s->dump (dump_file);
4499 0 : fprintf (dump_file, "\n");
4500 : }
4501 0 : bool profile_found = false;
4502 0 : hash_set <basic_block> zero_bbs;
4503 0 : gcov_type head_count = s->head_count () * autofdo::afdo_count_scale;
4504 :
4505 0 : if (!param_auto_profile_bbs)
4506 : {
4507 0 : if (scale_bb_profile ())
4508 : return;
4509 : }
4510 : else
4511 : {
4512 : /* In the first pass only store non-zero counts. */
4513 0 : profile_found = head_count > 0;
4514 0 : FOR_EACH_BB_FN (bb, cfun)
4515 : {
4516 0 : if (afdo_set_bb_count (bb, zero_bbs))
4517 : {
4518 0 : if (bb->count.quality () == AFDO)
4519 : {
4520 0 : gcc_assert (bb->count.nonzero_p ());
4521 : profile_found = true;
4522 : }
4523 0 : set_bb_annotated (bb, &annotated_bb);
4524 : }
4525 : }
4526 : }
4527 : /* Exit without clobbering static profile if there was no
4528 : non-zero count. */
4529 0 : if (!profile_found)
4530 : {
4531 : /* create_gcov only dumps symbols with some samples in them.
4532 : This means that we get nonempty zero_bbs only if some
4533 : nonzero counts in profile were not matched with statements.
4534 : ??? We can adjust create_gcov to also recordinfo
4535 : about function with no samples. Then we can distinguish
4536 : between lost profiles which should be kept local and
4537 : real functions with 0 samples during train run. */
4538 0 : if (zero_bbs.is_empty ())
4539 : {
4540 0 : if (dump_file)
4541 0 : fprintf (dump_file, "No afdo samples found"
4542 : "; Setting global count to afdo0\n");
4543 : }
4544 : else
4545 : {
4546 0 : if (dump_file)
4547 0 : fprintf (dump_file, "Setting global count to afdo0\n");
4548 : }
4549 0 : if (!flag_profile_partial_training)
4550 : {
4551 0 : FOR_ALL_BB_FN (bb, cfun)
4552 0 : if (bb->count.quality () == GUESSED_LOCAL)
4553 0 : bb->count = bb->count.global0afdo ();
4554 0 : update_max_bb_count ();
4555 : }
4556 :
4557 0 : loop_optimizer_finalize ();
4558 0 : free_dominance_info (CDI_DOMINATORS);
4559 0 : free_dominance_info (CDI_POST_DOMINATORS);
4560 0 : return;
4561 : }
4562 : /* We try to preserve static profile for BBs with 0
4563 : afdo samples, but if even static profile agrees with 0,
4564 : consider it final so propagation works better. */
4565 0 : for (basic_block bb : zero_bbs)
4566 0 : if (!bb->count.nonzero_p ())
4567 : {
4568 0 : update_count_by_afdo_count (&bb->count, 0);
4569 0 : set_bb_annotated (bb, &annotated_bb);
4570 0 : if (dump_file)
4571 : {
4572 0 : fprintf (dump_file, " Annotating bb %i with count ", bb->index);
4573 0 : bb->count.dump (dump_file);
4574 0 : fprintf (dump_file,
4575 : " (has 0 count in both static and afdo profile)\n");
4576 : }
4577 : }
4578 :
4579 : /* Update profile. */
4580 0 : if (head_count > 0)
4581 : {
4582 0 : update_count_by_afdo_count (&ENTRY_BLOCK_PTR_FOR_FN (cfun)->count,
4583 : head_count);
4584 0 : set_bb_annotated (ENTRY_BLOCK_PTR_FOR_FN (cfun), &annotated_bb);
4585 0 : if (!is_bb_annotated (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb, annotated_bb)
4586 0 : || ENTRY_BLOCK_PTR_FOR_FN (cfun)->count
4587 0 : > ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb->count)
4588 : {
4589 0 : ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb->count
4590 0 : = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
4591 0 : set_bb_annotated (ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb,
4592 : &annotated_bb);
4593 : }
4594 0 : if (!is_bb_annotated (EXIT_BLOCK_PTR_FOR_FN (cfun), annotated_bb)
4595 0 : || ENTRY_BLOCK_PTR_FOR_FN (cfun)->count
4596 0 : > EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb->count)
4597 : {
4598 0 : EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb->count
4599 0 : = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
4600 0 : set_bb_annotated (EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb, &annotated_bb);
4601 : }
4602 : }
4603 :
4604 : /* Calculate, propagate count and probability information on CFG. */
4605 0 : afdo_calculate_branch_prob (&annotated_bb);
4606 :
4607 : /* If we failed to turn some of original guessed profile to global,
4608 : set basic blocks uninitialized. */
4609 0 : FOR_ALL_BB_FN (bb, cfun)
4610 0 : if (!bb->count.ipa_p ())
4611 : {
4612 : /* We skip annotating entry profile if it is 0
4613 : in hope to be able to determine it better from the
4614 : static profile.
4615 :
4616 : Now we know we can not derive it from other info,
4617 : so set it since it is better than UNKNOWN. */
4618 0 : if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
4619 0 : bb->count = profile_count::zero ().afdo ();
4620 : else
4621 0 : bb->count = profile_count::uninitialized ();
4622 0 : if (dump_file)
4623 0 : fprintf (dump_file, " Unknown count of bb %i\n", bb->index);
4624 0 : cfun->cfg->full_profile = false;
4625 : }
4626 :
4627 0 : cgraph_node::get (current_function_decl)->count
4628 0 : = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
4629 0 : update_max_bb_count ();
4630 0 : profile_status_for_fn (cfun) = PROFILE_READ;
4631 0 : if (flag_value_profile_transformations)
4632 : {
4633 0 : gimple_value_profile_transformations ();
4634 0 : free_dominance_info (CDI_DOMINATORS);
4635 0 : free_dominance_info (CDI_POST_DOMINATORS);
4636 0 : update_ssa (TODO_update_ssa);
4637 : }
4638 :
4639 0 : loop_optimizer_finalize ();
4640 0 : free_dominance_info (CDI_DOMINATORS);
4641 0 : free_dominance_info (CDI_POST_DOMINATORS);
4642 0 : }
4643 :
4644 : /* Use AutoFDO profile to annotate the control flow graph.
4645 : Return the todo flag. */
4646 :
4647 : static unsigned int
4648 0 : auto_profile (void)
4649 : {
4650 0 : struct cgraph_node *node;
4651 :
4652 0 : if (symtab->state == FINISHED || !afdo_source_profile)
4653 : return 0;
4654 :
4655 0 : init_node_map (true);
4656 0 : profile_info = autofdo::afdo_profile_info;
4657 0 : afdo_source_profile->offline_unrealized_inlines ();
4658 :
4659 0 : FOR_EACH_FUNCTION (node)
4660 : {
4661 0 : if (!gimple_has_body_p (node->decl))
4662 0 : continue;
4663 :
4664 : /* Don't profile functions produced for builtin stuff. */
4665 0 : if (DECL_SOURCE_LOCATION (node->decl) == BUILTINS_LOCATION)
4666 0 : continue;
4667 :
4668 0 : push_cfun (DECL_STRUCT_FUNCTION (node->decl));
4669 :
4670 : /* Local pure-const may imply need to fixup the cfg.
4671 : This is similar to what is done in tree-profile.cc. */
4672 0 : if ((execute_fixup_cfg () & TODO_cleanup_cfg))
4673 0 : cleanup_tree_cfg ();
4674 :
4675 0 : autofdo::afdo_annotate_cfg ();
4676 0 : compute_function_frequency ();
4677 :
4678 0 : free_dominance_info (CDI_DOMINATORS);
4679 0 : free_dominance_info (CDI_POST_DOMINATORS);
4680 0 : cgraph_edge::rebuild_edges ();
4681 0 : pop_cfun ();
4682 : }
4683 :
4684 : return 0;
4685 : }
4686 : } /* namespace autofdo. */
4687 :
4688 : /* Read the profile from the profile data file. */
4689 :
4690 : void
4691 0 : read_autofdo_file (void)
4692 : {
4693 0 : if (auto_profile_file == NULL)
4694 0 : auto_profile_file = DEFAULT_AUTO_PROFILE_FILE;
4695 :
4696 0 : autofdo::afdo_profile_info = XNEW (gcov_summary);
4697 0 : autofdo::afdo_profile_info->runs = 1;
4698 0 : autofdo::afdo_profile_info->sum_max = 0;
4699 0 : autofdo::afdo_profile_info->cutoff = 1;
4700 :
4701 : /* Read the profile from the profile file. */
4702 0 : autofdo::read_profile ();
4703 0 : }
4704 :
4705 : /* Free the resources. */
4706 :
4707 : void
4708 0 : end_auto_profile (void)
4709 : {
4710 0 : delete autofdo::afdo_source_profile;
4711 0 : delete autofdo::afdo_string_table;
4712 0 : delete autofdo::afdo_summary_info;
4713 0 : profile_info = NULL;
4714 0 : }
4715 :
4716 : /* Returns TRUE if EDGE is hot enough to be inlined early. */
4717 :
4718 : bool
4719 0 : afdo_callsite_hot_enough_for_early_inline (struct cgraph_edge *edge)
4720 : {
4721 0 : gcov_type count
4722 0 : = autofdo::afdo_source_profile->get_callsite_total_count (edge);
4723 :
4724 0 : if (count > 0)
4725 : {
4726 0 : bool is_hot;
4727 0 : profile_count pcount = profile_count::from_gcov_type (count).afdo ();
4728 0 : is_hot = maybe_hot_afdo_count_p (pcount);
4729 0 : if (dump_file)
4730 : {
4731 0 : fprintf (dump_file, "Call %s -> %s has %s afdo profile count ",
4732 0 : edge->caller->dump_name (), edge->callee->dump_name (),
4733 : is_hot ? "hot" : "cold");
4734 0 : pcount.dump (dump_file);
4735 0 : fprintf (dump_file, "\n");
4736 : }
4737 0 : return is_hot;
4738 : }
4739 :
4740 : return false;
4741 : }
4742 :
4743 : /* Do indirect call promotion during early inlining to make the
4744 : IR match the profiled binary before actual annotation.
4745 :
4746 : This is needed because an indirect call might have been promoted
4747 : and inlined in the profiled binary. If we do not promote and
4748 : inline these indirect calls before annotation, the profile for
4749 : these promoted functions will be lost.
4750 :
4751 : e.g. foo() --indirect_call--> bar()
4752 : In profiled binary, the callsite is promoted and inlined, making
4753 : the profile look like:
4754 :
4755 : foo: {
4756 : loc_foo_1: count_1
4757 : bar@loc_foo_2: {
4758 : loc_bar_1: count_2
4759 : loc_bar_2: count_3
4760 : }
4761 : }
4762 :
4763 : Before AutoFDO pass, loc_foo_2 is not promoted thus not inlined.
4764 : If we perform annotation on it, the profile inside bar@loc_foo2
4765 : will be wasted.
4766 :
4767 : To avoid this, we promote loc_foo_2 and inline the promoted bar
4768 : function before annotation, so the profile inside bar@loc_foo2
4769 : will be useful. */
4770 :
4771 : bool
4772 0 : afdo_vpt_for_early_inline (cgraph_node *node)
4773 : {
4774 0 : if (!node->indirect_calls)
4775 : return false;
4776 0 : bool changed = false;
4777 0 : cgraph_node *outer = node->inlined_to ? node->inlined_to : node;
4778 0 : if (autofdo::afdo_source_profile->get_function_instance_by_decl
4779 0 : (outer->decl) == NULL)
4780 : return false;
4781 0 : for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
4782 : {
4783 0 : gcov_type bb_count = 0;
4784 0 : autofdo::count_info info;
4785 0 : basic_block bb = gimple_bb (e->call_stmt);
4786 :
4787 : /* TODO: This is quadratic; cache the value. */
4788 0 : for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
4789 0 : !gsi_end_p (gsi); gsi_next (&gsi))
4790 : {
4791 0 : gimple *stmt = gsi_stmt (gsi);
4792 0 : if (!stmt_loc_used_by_debug_info (stmt))
4793 0 : continue;
4794 0 : autofdo::count_info info;
4795 0 : if (autofdo::afdo_source_profile->get_count_info (stmt, &info, node))
4796 0 : bb_count = MAX (bb_count, info.count);
4797 0 : }
4798 0 : autofdo::afdo_source_profile->get_count_info (e->call_stmt, &info, node);
4799 0 : info.count = bb_count;
4800 0 : if (!autofdo::afdo_source_profile->update_inlined_ind_target
4801 0 : (e->call_stmt, &info, node))
4802 0 : continue;
4803 0 : changed |= autofdo::afdo_vpt (e->call_stmt, info.targets, true, e);
4804 0 : }
4805 : return changed;
4806 : }
4807 :
4808 : /* If speculation used during early inline, remove the target
4809 : so we do not speculate the indirect edge again during afdo pass. */
4810 :
4811 : void
4812 0 : remove_afdo_speculative_target (cgraph_edge *e)
4813 : {
4814 0 : autofdo::afdo_source_profile->remove_icall_target (e);
4815 0 : }
4816 :
4817 : namespace
4818 : {
4819 :
4820 : const pass_data pass_data_ipa_auto_profile = {
4821 : SIMPLE_IPA_PASS, "afdo", /* name */
4822 : OPTGROUP_NONE, /* optinfo_flags */
4823 : TV_IPA_AUTOFDO, /* tv_id */
4824 : 0, /* properties_required */
4825 : 0, /* properties_provided */
4826 : 0, /* properties_destroyed */
4827 : 0, /* todo_flags_start */
4828 : 0, /* todo_flags_finish */
4829 : };
4830 :
4831 : class pass_ipa_auto_profile : public simple_ipa_opt_pass
4832 : {
4833 : public:
4834 285722 : pass_ipa_auto_profile (gcc::context *ctxt)
4835 571444 : : simple_ipa_opt_pass (pass_data_ipa_auto_profile, ctxt)
4836 : {
4837 : }
4838 :
4839 : /* opt_pass methods: */
4840 : bool
4841 229960 : gate (function *) final override
4842 : {
4843 229960 : return flag_auto_profile;
4844 : }
4845 : unsigned int
4846 0 : execute (function *) final override
4847 : {
4848 0 : return autofdo::auto_profile ();
4849 : }
4850 : }; // class pass_ipa_auto_profile
4851 :
4852 : } // anon namespace
4853 :
4854 : simple_ipa_opt_pass *
4855 285722 : make_pass_ipa_auto_profile (gcc::context *ctxt)
4856 : {
4857 285722 : return new pass_ipa_auto_profile (ctxt);
4858 : }
4859 :
4860 : namespace
4861 : {
4862 :
4863 : const pass_data pass_data_ipa_auto_profile_offline = {
4864 : SIMPLE_IPA_PASS, "afdo_offline", /* name */
4865 : OPTGROUP_NONE, /* optinfo_flags */
4866 : TV_IPA_AUTOFDO_OFFLINE, /* tv_id */
4867 : 0, /* properties_required */
4868 : 0, /* properties_provided */
4869 : 0, /* properties_destroyed */
4870 : 0, /* todo_flags_start */
4871 : 0, /* todo_flags_finish */
4872 : };
4873 :
4874 : class pass_ipa_auto_profile_offline : public simple_ipa_opt_pass
4875 : {
4876 : public:
4877 285722 : pass_ipa_auto_profile_offline (gcc::context *ctxt)
4878 571444 : : simple_ipa_opt_pass (pass_data_ipa_auto_profile_offline, ctxt)
4879 : {
4880 : }
4881 :
4882 : /* opt_pass methods: */
4883 : bool
4884 229960 : gate (function *) final override
4885 : {
4886 229960 : return flag_auto_profile;
4887 : }
4888 : unsigned int
4889 0 : execute (function *) final override
4890 : {
4891 0 : read_autofdo_file ();
4892 0 : if (autofdo::afdo_source_profile)
4893 0 : autofdo::afdo_source_profile->offline_external_functions ();
4894 0 : return 0;
4895 : }
4896 : }; // class pass_ipa_auto_profile
4897 :
4898 : } // anon namespace
4899 :
4900 : simple_ipa_opt_pass *
4901 285722 : make_pass_ipa_auto_profile_offline (gcc::context *ctxt)
4902 : {
4903 285722 : return new pass_ipa_auto_profile_offline (ctxt);
4904 : }
|