Branch data Line data Source code
1 : : /* The tracer pass for the GNU compiler.
2 : : Contributed by Jan Hubicka, SuSE Labs.
3 : : Adapted to work on GIMPLE instead of RTL by Robert Kidd, UIUC.
4 : : Copyright (C) 2001-2025 Free Software Foundation, Inc.
5 : :
6 : : This file is part of GCC.
7 : :
8 : : GCC is free software; you can redistribute it and/or modify it
9 : : under the terms of the GNU General Public License as published by
10 : : the Free Software Foundation; either version 3, or (at your option)
11 : : any later version.
12 : :
13 : : GCC is distributed in the hope that it will be useful, but WITHOUT
14 : : ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 : : or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 : : License for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with GCC; see the file COPYING3. If not see
20 : : <http://www.gnu.org/licenses/>. */
21 : :
22 : : /* This pass performs the tail duplication needed for superblock formation.
23 : : For more information see:
24 : :
25 : : Design and Analysis of Profile-Based Optimization in Compaq's
26 : : Compilation Tools for Alpha; Journal of Instruction-Level
27 : : Parallelism 3 (2000) 1-25
28 : :
29 : : Unlike Compaq's implementation we don't do the loop peeling as most
30 : : probably a better job can be done by a special pass and we don't
31 : : need to worry too much about the code size implications as the tail
32 : : duplicates are crossjumped again if optimizations are not
33 : : performed. */
34 : :
35 : :
36 : : #include "config.h"
37 : : #include "system.h"
38 : : #include "coretypes.h"
39 : : #include "backend.h"
40 : : #include "rtl.h"
41 : : #include "tree.h"
42 : : #include "gimple.h"
43 : : #include "cfghooks.h"
44 : : #include "tree-pass.h"
45 : : #include "profile.h"
46 : : #include "cfganal.h"
47 : : #include "gimple-iterator.h"
48 : : #include "tree-cfg.h"
49 : : #include "tree-ssa.h"
50 : : #include "tree-inline.h"
51 : : #include "cfgloop.h"
52 : : #include "alloc-pool.h"
53 : : #include "fibonacci_heap.h"
54 : : #include "tracer.h"
55 : :
56 : : static void analyze_bb (basic_block, int *);
57 : : static bool better_p (const_edge, const_edge);
58 : : static edge find_best_successor (basic_block);
59 : : static edge find_best_predecessor (basic_block);
60 : : static int find_trace (basic_block, basic_block *);
61 : :
62 : : /* Minimal outgoing edge probability considered for superblock formation. */
63 : : static int probability_cutoff;
64 : : static int branch_ratio_cutoff;
65 : :
66 : : /* A bit BB->index is set if BB has already been seen, i.e. it is
67 : : connected to some trace already. */
68 : : static sbitmap bb_seen;
69 : :
70 : : static inline void
71 : 78233 : mark_bb_seen (basic_block bb)
72 : : {
73 : 78233 : unsigned int size = SBITMAP_SIZE (bb_seen);
74 : :
75 : 78233 : if ((unsigned int)bb->index >= size)
76 : 0 : bb_seen = sbitmap_resize (bb_seen, size * 2, 0);
77 : :
78 : 78233 : bitmap_set_bit (bb_seen, bb->index);
79 : 78233 : }
80 : :
81 : : static inline bool
82 : 427529 : bb_seen_p (basic_block bb)
83 : : {
84 : 427529 : return bitmap_bit_p (bb_seen, bb->index);
85 : : }
86 : :
87 : : static sbitmap can_duplicate_bb;
88 : :
89 : : /* Cache VAL as value of can_duplicate_bb_p for BB. */
90 : : static inline void
91 : 256926 : cache_can_duplicate_bb_p (const_basic_block bb, bool val)
92 : : {
93 : 256926 : if (val)
94 : 256900 : bitmap_set_bit (can_duplicate_bb, bb->index);
95 : 256926 : }
96 : :
97 : : /* Return cached value of can_duplicate_bb_p for BB. */
98 : : static bool
99 : 1136447 : cached_can_duplicate_bb_p (const_basic_block bb)
100 : : {
101 : 1136447 : if (can_duplicate_bb)
102 : : {
103 : 1084236 : unsigned int size = SBITMAP_SIZE (can_duplicate_bb);
104 : 1084236 : if ((unsigned int)bb->index < size)
105 : 1064128 : return bitmap_bit_p (can_duplicate_bb, bb->index);
106 : :
107 : : /* Assume added bb's should not be duplicated. */
108 : : return false;
109 : : }
110 : :
111 : 52211 : return can_duplicate_block_p (bb);
112 : : }
113 : :
114 : : /* Return true if we should ignore the basic block for purposes of tracing. */
115 : : bool
116 : 1213296 : ignore_bb_p (const_basic_block bb)
117 : : {
118 : 1213296 : if (bb->index < NUM_FIXED_BLOCKS)
119 : : return true;
120 : 1197526 : if (optimize_bb_for_size_p (bb))
121 : : return true;
122 : :
123 : 1136447 : return !cached_can_duplicate_bb_p (bb);
124 : : }
125 : :
126 : : /* Return number of instructions in the block. */
127 : :
128 : : static void
129 : 256926 : analyze_bb (basic_block bb, int *count)
130 : : {
131 : 256926 : gimple_stmt_iterator gsi;
132 : 256926 : gimple *stmt;
133 : 256926 : int n = 0;
134 : :
135 : 1618697 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
136 : : {
137 : 1104845 : stmt = gsi_stmt (gsi);
138 : 1104845 : n += estimate_num_insns (stmt, &eni_size_weights);
139 : : }
140 : 256926 : *count = n;
141 : :
142 : 256926 : cache_can_duplicate_bb_p (bb, can_duplicate_block_p (CONST_CAST_BB (bb)));
143 : 256926 : }
144 : :
145 : : /* Return true if E1 is more frequent than E2. */
146 : : static bool
147 : 585938 : better_p (const_edge e1, const_edge e2)
148 : : {
149 : 861765 : if ((e1->count () > e2->count ()) || (e1->count () < e2->count ()))
150 : 555117 : return e1->count () > e2->count ();
151 : : /* This is needed to avoid changes in the decision after
152 : : CFG is modified. */
153 : 30821 : if (e1->src != e2->src)
154 : 18729 : return e1->src->index > e2->src->index;
155 : 12092 : return e1->dest->index > e2->dest->index;
156 : : }
157 : :
158 : : /* Return most frequent successor of basic block BB. */
159 : :
160 : : static edge
161 : 395870 : find_best_successor (basic_block bb)
162 : : {
163 : 395870 : edge e;
164 : 395870 : edge best = NULL;
165 : 395870 : edge_iterator ei;
166 : :
167 : 1118622 : FOR_EACH_EDGE (e, ei, bb->succs)
168 : : {
169 : 722849 : if (!e->count ().initialized_p ())
170 : : return NULL;
171 : 722752 : if (!best || better_p (e, best))
172 : : best = e;
173 : : }
174 : 395773 : if (!best || ignore_bb_p (best->dest))
175 : 12677 : return NULL;
176 : 383096 : if (!best->probability.initialized_p ()
177 : 383096 : || best->probability.to_reg_br_prob_base () <= probability_cutoff)
178 : : return NULL;
179 : : return best;
180 : : }
181 : :
182 : : /* Return most frequent predecessor of basic block BB. */
183 : :
184 : : static edge
185 : 392570 : find_best_predecessor (basic_block bb)
186 : : {
187 : 392570 : edge e;
188 : 392570 : edge best = NULL;
189 : 392570 : edge_iterator ei;
190 : :
191 : 1043858 : FOR_EACH_EDGE (e, ei, bb->preds)
192 : : {
193 : 651390 : if (!e->count ().initialized_p ())
194 : : return NULL;
195 : 651288 : if (!best || better_p (e, best))
196 : : best = e;
197 : : }
198 : 392468 : if (!best || ignore_bb_p (best->src))
199 : 16447 : return NULL;
200 : 376021 : if (bb->count.initialized_p ()
201 : 1127884 : && (best->count ().to_frequency (cfun) * REG_BR_PROB_BASE
202 : 376021 : < bb->count.to_frequency (cfun) * branch_ratio_cutoff))
203 : 179 : return NULL;
204 : : return best;
205 : : }
206 : :
207 : : /* Find the trace using bb and record it in the TRACE array.
208 : : Return number of basic blocks recorded. */
209 : :
210 : : static int
211 : 37233 : find_trace (basic_block bb, basic_block *trace)
212 : : {
213 : 37233 : int i = 0;
214 : 37233 : edge e;
215 : :
216 : 37233 : if (dump_file)
217 : 17 : fprintf (dump_file, "Trace seed %i [%i]", bb->index, bb->count.to_frequency (cfun));
218 : :
219 : 98176 : while ((e = find_best_predecessor (bb)) != NULL)
220 : : {
221 : 82544 : basic_block bb2 = e->src;
222 : 163731 : if (bb_seen_p (bb2) || (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
223 : 152429 : || find_best_successor (bb2) != e)
224 : : break;
225 : 60943 : if (dump_file)
226 : 15 : fprintf (dump_file, ",%i [%i]", bb->index, bb->count.to_frequency (cfun));
227 : : bb = bb2;
228 : : }
229 : 37233 : if (dump_file)
230 : 17 : fprintf (dump_file, " forward %i [%i]", bb->index, bb->count.to_frequency (cfun));
231 : 37233 : trace[i++] = bb;
232 : :
233 : : /* Follow the trace in forward direction. */
234 : 325985 : while ((e = find_best_successor (bb)) != NULL)
235 : : {
236 : 307752 : bb = e->dest;
237 : 615449 : if (bb_seen_p (bb) || (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
238 : 602146 : || find_best_predecessor (bb) != e)
239 : : break;
240 : 288752 : if (dump_file)
241 : 30 : fprintf (dump_file, ",%i [%i]", bb->index, bb->count.to_frequency (cfun));
242 : 288752 : trace[i++] = bb;
243 : : }
244 : 37233 : if (dump_file)
245 : 17 : fprintf (dump_file, "\n");
246 : 37233 : return i;
247 : : }
248 : :
249 : : /* Duplicate block BB2, placing it after BB in the CFG. Return the
250 : : newly created block. */
251 : : basic_block
252 : 14492 : transform_duplicate (basic_block bb, basic_block bb2)
253 : : {
254 : 14492 : edge e;
255 : 14492 : basic_block copy;
256 : :
257 : 14492 : e = find_edge (bb, bb2);
258 : :
259 : 14492 : copy = duplicate_block (bb2, e, bb);
260 : 14492 : flush_pending_stmts (e);
261 : :
262 : 14492 : add_phi_args_after_copy (©, 1, NULL);
263 : :
264 : 14492 : return (copy);
265 : : }
266 : :
267 : : /* Look for basic blocks in frequency order, construct traces and tail duplicate
268 : : if profitable. */
269 : :
270 : : static bool
271 : 10931 : tail_duplicate (void)
272 : : {
273 : 10931 : auto_vec<fibonacci_node<long, basic_block_def>*> blocks;
274 : 10931 : blocks.safe_grow_cleared (last_basic_block_for_fn (cfun), true);
275 : :
276 : 10931 : basic_block *trace = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
277 : 10931 : int *counts = XNEWVEC (int, last_basic_block_for_fn (cfun));
278 : 10931 : int ninsns = 0, nduplicated = 0;
279 : 10931 : gcov_type weighted_insns = 0, traced_insns = 0;
280 : 10931 : fibonacci_heap<long, basic_block_def> heap (LONG_MIN);
281 : 10931 : gcov_type cover_insns;
282 : 10931 : int max_dup_insns;
283 : 10931 : basic_block bb;
284 : 10931 : bool changed = false;
285 : :
286 : : /* Create an oversized sbitmap to reduce the chance that we need to
287 : : resize it. */
288 : 10931 : bb_seen = sbitmap_alloc (last_basic_block_for_fn (cfun) * 2);
289 : 10931 : bitmap_clear (bb_seen);
290 : 10931 : can_duplicate_bb = sbitmap_alloc (last_basic_block_for_fn (cfun));
291 : 10931 : bitmap_clear (can_duplicate_bb);
292 : 10931 : initialize_original_copy_tables ();
293 : :
294 : 10931 : if (profile_info && profile_status_for_fn (cfun) == PROFILE_READ)
295 : 177 : probability_cutoff = param_tracer_min_branch_probability_feedback;
296 : : else
297 : 10754 : probability_cutoff = param_tracer_min_branch_probability;
298 : 10931 : probability_cutoff = REG_BR_PROB_BASE / 100 * probability_cutoff;
299 : :
300 : 10931 : branch_ratio_cutoff =
301 : 10931 : (REG_BR_PROB_BASE / 100 * param_tracer_min_branch_ratio);
302 : :
303 : 267857 : FOR_EACH_BB_FN (bb, cfun)
304 : : {
305 : 256926 : int n;
306 : 256926 : analyze_bb (bb, &n);
307 : 256926 : if (!ignore_bb_p (bb))
308 : 202373 : blocks[bb->index] = heap.insert (-bb->count.to_frequency (cfun), bb);
309 : :
310 : 256926 : counts [bb->index] = n;
311 : 256926 : ninsns += n;
312 : 256926 : weighted_insns += n * bb->count.to_frequency (cfun);
313 : : }
314 : :
315 : 10931 : if (profile_info && profile_status_for_fn (cfun) == PROFILE_READ)
316 : 177 : cover_insns = param_tracer_dynamic_coverage_feedback;
317 : : else
318 : 10754 : cover_insns = param_tracer_dynamic_coverage;
319 : 10931 : cover_insns = (weighted_insns * cover_insns + 50) / 100;
320 : 10931 : max_dup_insns = (ninsns * param_tracer_max_code_growth + 50) / 100;
321 : :
322 : 10931 : while (traced_insns < cover_insns && nduplicated < max_dup_insns
323 : 48618 : && !heap.empty ())
324 : : {
325 : 37687 : basic_block bb = heap.extract_min ();
326 : 37687 : int n, pos;
327 : :
328 : 37687 : if (!bb)
329 : : break;
330 : :
331 : 37687 : blocks[bb->index] = NULL;
332 : :
333 : 37687 : if (ignore_bb_p (bb))
334 : 454 : continue;
335 : 37233 : gcc_assert (!bb_seen_p (bb));
336 : :
337 : 37233 : n = find_trace (bb, trace);
338 : :
339 : 37233 : bb = trace[0];
340 : 37233 : traced_insns += bb->count.to_frequency (cfun) * counts [bb->index];
341 : 37233 : if (blocks[bb->index])
342 : : {
343 : 10150 : heap.delete_node (blocks[bb->index]);
344 : 10150 : blocks[bb->index] = NULL;
345 : : }
346 : :
347 : 102584 : for (pos = 1; pos < n; pos++)
348 : : {
349 : 78233 : basic_block bb2 = trace[pos];
350 : :
351 : 78233 : if (blocks[bb2->index])
352 : : {
353 : 70387 : heap.delete_node (blocks[bb2->index]);
354 : 70387 : blocks[bb2->index] = NULL;
355 : : }
356 : 78233 : traced_insns += bb2->count.to_frequency (cfun) * counts [bb2->index];
357 : 78233 : if (EDGE_COUNT (bb2->preds) > 1
358 : 14154 : && can_duplicate_block_p (bb2)
359 : : /* We have the tendency to duplicate the loop header
360 : : of all do { } while loops. Do not do that - it is
361 : : not profitable and it might create a loop with multiple
362 : : entries or at least rotate the loop. */
363 : 92387 : && bb2->loop_father->header != bb2)
364 : : {
365 : 12882 : nduplicated += counts [bb2->index];
366 : 12882 : basic_block copy = transform_duplicate (bb, bb2);
367 : :
368 : : /* Reconsider the original copy of block we've duplicated.
369 : : Removing the most common predecessor may make it to be
370 : : head. */
371 : 12882 : blocks[bb2->index] = heap.insert (-bb2->count.to_frequency (cfun), bb2);
372 : :
373 : 12882 : if (dump_file)
374 : 7 : fprintf (dump_file, "Duplicated %i as %i [%i]\n",
375 : : bb2->index, copy->index, copy->count.to_frequency (cfun));
376 : :
377 : : bb2 = copy;
378 : : changed = true;
379 : : }
380 : 78233 : mark_bb_seen (bb2);
381 : 78233 : bb = bb2;
382 : : /* In case the trace became infrequent, stop duplicating. */
383 : 78233 : if (ignore_bb_p (bb))
384 : : break;
385 : : }
386 : 37233 : if (dump_file)
387 : 17 : fprintf (dump_file, " covered now %.1f\n\n",
388 : 17 : traced_insns * 100.0 / weighted_insns);
389 : : }
390 : 10931 : if (dump_file)
391 : 10 : fprintf (dump_file, "Duplicated %i insns (%i%%)\n", nduplicated,
392 : 10 : nduplicated * 100 / ninsns);
393 : :
394 : 10931 : free_original_copy_tables ();
395 : 10931 : sbitmap_free (bb_seen);
396 : 10931 : sbitmap_free (can_duplicate_bb);
397 : 10931 : can_duplicate_bb = NULL;
398 : 10931 : free (trace);
399 : 10931 : free (counts);
400 : :
401 : 21862 : return changed;
402 : 10931 : }
403 : :
404 : : namespace {
405 : :
406 : : const pass_data pass_data_tracer =
407 : : {
408 : : GIMPLE_PASS, /* type */
409 : : "tracer", /* name */
410 : : OPTGROUP_NONE, /* optinfo_flags */
411 : : TV_TRACER, /* tv_id */
412 : : 0, /* properties_required */
413 : : 0, /* properties_provided */
414 : : 0, /* properties_destroyed */
415 : : 0, /* todo_flags_start */
416 : : TODO_update_ssa, /* todo_flags_finish */
417 : : };
418 : :
419 : : class pass_tracer : public gimple_opt_pass
420 : : {
421 : : public:
422 : 283157 : pass_tracer (gcc::context *ctxt)
423 : 566314 : : gimple_opt_pass (pass_data_tracer, ctxt)
424 : : {}
425 : :
426 : : /* opt_pass methods: */
427 : 1006350 : bool gate (function *) final override
428 : : {
429 : 1006350 : return (optimize > 0 && flag_tracer && flag_reorder_blocks);
430 : : }
431 : :
432 : : unsigned int execute (function *) final override;
433 : :
434 : : }; // class pass_tracer
435 : :
436 : : unsigned int
437 : 19525 : pass_tracer::execute (function *fun)
438 : : {
439 : 19525 : bool changed;
440 : :
441 : 19525 : if (n_basic_blocks_for_fn (fun) <= NUM_FIXED_BLOCKS + 1)
442 : : return 0;
443 : :
444 : 10931 : mark_dfs_back_edges ();
445 : 10931 : if (dump_file)
446 : 10 : brief_dump_cfg (dump_file, dump_flags);
447 : :
448 : : /* Trace formation is done on the fly inside tail_duplicate */
449 : 10931 : changed = tail_duplicate ();
450 : 10931 : if (changed)
451 : : {
452 : 4715 : free_dominance_info (CDI_DOMINATORS);
453 : : /* If we changed the CFG schedule loops for fixup by cleanup_cfg. */
454 : 4715 : loops_state_set (LOOPS_NEED_FIXUP);
455 : : }
456 : :
457 : 10931 : if (dump_file)
458 : 10 : brief_dump_cfg (dump_file, dump_flags);
459 : :
460 : 10931 : return changed ? TODO_cleanup_cfg : 0;
461 : : }
462 : : } // anon namespace
463 : :
464 : : gimple_opt_pass *
465 : 283157 : make_pass_tracer (gcc::context *ctxt)
466 : : {
467 : 283157 : return new pass_tracer (ctxt);
468 : : }
|