Line data Source code
1 : /* Strongly-connected copy propagation pass for the GNU compiler.
2 : Copyright (C) 2023-2026 Free Software Foundation, Inc.
3 : Contributed by Filip Kastl <fkastl@suse.cz>
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 : #define INCLUDE_ALGORITHM
22 : #include "config.h"
23 : #include "system.h"
24 : #include "coretypes.h"
25 : #include "backend.h"
26 : #include "tree.h"
27 : #include "gimple.h"
28 : #include "tree-pass.h"
29 : #include "ssa.h"
30 : #include "gimple-iterator.h"
31 : #include "vec.h"
32 : #include "hash-set.h"
33 : #include "ssa-iterators.h"
34 : #include "gimple-fold.h"
35 : #include "gimplify.h"
36 : #include "tree-cfg.h"
37 : #include "tree-eh.h"
38 : #include "builtins.h"
39 : #include "tree-ssa-dce.h"
40 : #include "fold-const.h"
41 : #include "tree-pretty-print.h"
42 :
43 : /* Strongly connected copy propagation pass.
44 :
45 : This is a lightweight copy propagation pass that is also able to eliminate
46 : redundant PHI statements. The pass considers the following types of copy
47 : statements:
48 :
49 : 1 An assignment statement with a single argument.
50 :
51 : _3 = _2;
52 : _4 = 5;
53 :
54 : 2 A degenerate PHI statement. A degenerate PHI is a PHI that only refers to
55 : itself or one other value.
56 :
57 : _5 = PHI <_1>;
58 : _6 = PHI <_6, _6, _1, _1>;
59 : _7 = PHI <16, _7>;
60 :
61 : 3 A set of PHI statements that only refer to each other or to one other
62 : value.
63 :
64 : _8 = PHI <_9, _10>;
65 : _9 = PHI <_8, _10>;
66 : _10 = PHI <_8, _9, _1>;
67 :
68 : All of these statements produce copies and can be eliminated from the
69 : program. For a copy statement we identify the value it creates a copy of
70 : and replace references to the statement with the value -- we propagate the
71 : copy.
72 :
73 : _3 = _2; // Replace all occurrences of _3 by _2
74 :
75 : _8 = PHI <_9, _10>;
76 : _9 = PHI <_8, _10>;
77 : _10 = PHI <_8, _9, _1>; // Replace all occurrences of _8, _9 and _10 by _1
78 :
79 : To find all three types of copy statements we use an algorithm based on
80 : strongly-connected components (SCCs) in dataflow graph. The algorithm was
81 : introduced in an article from 2013[1]. We describe the algorithm below.
82 :
83 : To identify SCCs we implement the Robert Tarjan's SCC algorithm. For the
84 : SCC computation we wrap potential copy statements in the 'vertex' struct.
85 : To each of these statements we also assign a vertex number ('vxnum'). Since
86 : the main algorithm has to be able to compute SCCs of subgraphs of the whole
87 : dataflow graph we use GIMPLE stmt flags to prevent Tarjan's algorithm from
88 : leaving the subgraph.
89 :
90 : References:
91 :
92 : [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
93 : Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
94 : Section 3.2. */
95 :
96 : namespace {
97 :
98 : /* State of vertex during SCC discovery.
99 :
100 : unvisited Vertex hasn't yet been popped from worklist.
101 : vopen DFS has visited vertex for the first time. Vertex has been put
102 : on Tarjan stack.
103 : closed DFS has backtracked through vertex. At this point, vertex
104 : doesn't have any unvisited neighbors.
105 : in_scc Vertex has been popped from Tarjan stack. */
106 :
107 : enum vstate
108 : {
109 : unvisited,
110 : vopen,
111 : closed,
112 : in_scc
113 : };
114 :
115 : /* Information about a vertex. Used by SCC discovery. */
116 :
117 : struct vertex
118 : {
119 : bool active; /* scc_discovery::compute_sccs () only considers a subgraph of
120 : the whole dataflow graph. It uses this flag so that it knows
121 : which vertices are part of this subgraph. */
122 : vstate state;
123 : unsigned index;
124 : unsigned lowlink;
125 : };
126 :
127 : /* SCC discovery.
128 :
129 : Used to find SCCs in a dataflow graph. Implements Tarjan's SCC
130 : algorithm. */
131 :
132 : class scc_discovery
133 : {
134 : public:
135 : scc_discovery ();
136 : ~scc_discovery ();
137 : auto_vec<vec<gimple *>> compute_sccs (vec<gimple *> &stmts);
138 :
139 : private:
140 : vertex* vertices; /* Indexed by SSA_NAME_VERSION. */
141 : auto_vec<unsigned> worklist; /* DFS stack. */
142 : auto_vec<unsigned> stack; /* Tarjan stack. */
143 :
144 : void visit_neighbor (tree neigh_tree, unsigned parent_vxnum);
145 : };
146 :
147 3583169 : scc_discovery::scc_discovery ()
148 : {
149 : /* Create vertex struct for each SSA name. */
150 7166338 : vertices = XNEWVEC (struct vertex, num_ssa_names);
151 3583169 : unsigned i = 0;
152 134734118 : for (i = 0; i < num_ssa_names; i++)
153 131150949 : vertices[i].active = false;
154 3583169 : }
155 :
156 3583169 : scc_discovery::~scc_discovery ()
157 : {
158 3583169 : XDELETEVEC (vertices);
159 3583169 : }
160 :
161 : /* Part of 'scc_discovery::compute_sccs ()'. */
162 :
163 : void
164 51971593 : scc_discovery::visit_neighbor (tree neigh_tree, unsigned parent_version)
165 : {
166 51971593 : if (TREE_CODE (neigh_tree) != SSA_NAME)
167 38962946 : return; /* Skip any neighbor that isn't an SSA name. */
168 47234437 : unsigned neigh_version = SSA_NAME_VERSION (neigh_tree);
169 :
170 : /* Skip neighbors outside the subgraph that Tarjan currently works
171 : with. */
172 47234437 : if (!vertices[neigh_version].active)
173 : return;
174 :
175 13008647 : vstate neigh_state = vertices[neigh_version].state;
176 13008647 : vstate parent_state = vertices[parent_version].state;
177 13008647 : if (parent_state == vopen) /* We're currently opening parent. */
178 : {
179 : /* Put unvisited neighbors on worklist. Update lowlink of parent
180 : vertex according to indices of neighbors present on stack. */
181 4554626 : switch (neigh_state)
182 : {
183 3283545 : case unvisited:
184 3283545 : worklist.safe_push (neigh_version);
185 3283545 : break;
186 579529 : case vopen:
187 579529 : case closed:
188 579529 : vertices[parent_version].lowlink
189 579529 : = std::min (vertices[parent_version].lowlink,
190 : vertices[neigh_version].index);
191 579529 : break;
192 : case in_scc:
193 : /* Ignore these edges. */
194 : break;
195 : }
196 : }
197 8454021 : else if (parent_state == closed) /* We're currently closing parent. */
198 : {
199 : /* Update lowlink of parent vertex according to lowlinks of
200 : children of parent (in terms of DFS tree). */
201 4728317 : if (neigh_state == closed)
202 : {
203 763306 : vertices[parent_version].lowlink
204 763306 : = std::min (vertices[parent_version].lowlink,
205 : vertices[neigh_version].lowlink);
206 : }
207 : }
208 : }
209 :
210 : /* Compute SCCs in dataflow graph on given statements 'stmts'. Ignore
211 : statements outside 'stmts'. Return the SCCs in a reverse topological
212 : order.
213 :
214 : stmt_may_generate_copy () must be true for all statements from 'stmts'! */
215 :
216 : auto_vec<vec<gimple *>>
217 10742843 : scc_discovery::compute_sccs (vec<gimple *> &stmts)
218 : {
219 10742843 : auto_vec<vec<gimple *>> sccs;
220 :
221 21965204 : for (gimple *stmt : stmts)
222 : {
223 8690105 : unsigned i;
224 8690105 : switch (gimple_code (stmt))
225 : {
226 33265 : case GIMPLE_ASSIGN:
227 33265 : i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
228 33265 : break;
229 8656840 : case GIMPLE_PHI:
230 8656840 : i = SSA_NAME_VERSION (gimple_phi_result (stmt));
231 8656840 : break;
232 0 : default:
233 0 : gcc_unreachable ();
234 : }
235 :
236 8690105 : vertices[i].index = 0;
237 8690105 : vertices[i].lowlink = 0;
238 8690105 : vertices[i].state = unvisited;
239 8690105 : vertices[i].active = true; /* Mark the subgraph we'll be working on so
240 : that we don't leave it. */
241 :
242 8690105 : worklist.safe_push (i);
243 : }
244 :
245 : /* Worklist loop. */
246 : unsigned curr_index = 0;
247 31406598 : while (!worklist.is_empty ())
248 : {
249 20663755 : unsigned i = worklist.pop ();
250 20663755 : gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i));
251 20663755 : vstate state = vertices[i].state;
252 :
253 20663755 : if (state == unvisited)
254 : {
255 8690105 : vertices[i].state = vopen;
256 :
257 : /* Assign index to this vertex. */
258 8690105 : vertices[i].index = curr_index;
259 8690105 : vertices[i].lowlink = curr_index;
260 8690105 : curr_index++;
261 :
262 : /* Put vertex on stack and also on worklist to be closed later. */
263 8690105 : stack.safe_push (i);
264 8690105 : worklist.safe_push (i);
265 : }
266 11973650 : else if (state == vopen)
267 8690105 : vertices[i].state = closed;
268 :
269 : /* Visit neighbors of this vertex. */
270 20663755 : tree op;
271 20663755 : gphi *phi;
272 20663755 : switch (gimple_code (stmt))
273 : {
274 20594802 : case GIMPLE_PHI:
275 20594802 : phi = as_a <gphi *> (stmt);
276 20594802 : unsigned j;
277 93092244 : for (j = 0; j < gimple_phi_num_args (phi); j++)
278 : {
279 51902640 : op = gimple_phi_arg_def (phi, j);
280 51902640 : visit_neighbor (op, i);
281 : }
282 : break;
283 68953 : case GIMPLE_ASSIGN:
284 68953 : op = gimple_assign_rhs1 (stmt);
285 68953 : visit_neighbor (op, i);
286 68953 : break;
287 0 : default:
288 0 : gcc_unreachable ();
289 : }
290 :
291 : /* If we've just closed a root vertex of an scc, pop scc from stack. */
292 20663755 : if (state == vopen && vertices[i].lowlink == vertices[i].index)
293 : {
294 8173403 : vec<gimple *> scc = vNULL;
295 :
296 8690105 : unsigned j;
297 8690105 : do
298 : {
299 8690105 : j = stack.pop ();
300 8690105 : scc.safe_push (SSA_NAME_DEF_STMT (ssa_name (j)));
301 8690105 : vertices[j].state = in_scc;
302 : }
303 8690105 : while (j != i);
304 :
305 8173403 : sccs.safe_push (scc);
306 : }
307 : }
308 :
309 10742843 : if (!stack.is_empty ())
310 0 : gcc_unreachable ();
311 :
312 : /* Clear 'active' flags. */
313 21965204 : for (gimple *stmt : stmts)
314 : {
315 8690105 : unsigned i;
316 8690105 : switch (gimple_code (stmt))
317 : {
318 33265 : case GIMPLE_ASSIGN:
319 33265 : i = SSA_NAME_VERSION (gimple_assign_lhs (stmt));
320 33265 : break;
321 8656840 : case GIMPLE_PHI:
322 8656840 : i = SSA_NAME_VERSION (gimple_phi_result (stmt));
323 8656840 : break;
324 0 : default:
325 0 : gcc_unreachable ();
326 : }
327 :
328 8690105 : vertices[i].active = false;
329 : }
330 :
331 10742843 : return sccs;
332 : }
333 :
334 : } // anon namespace
335 :
336 : /* Could this statement potentially be a copy statement?
337 :
338 : This pass only considers statements for which this function returns 'true'.
339 : Those are basically PHI functions and assignment statements similar to
340 :
341 : _2 = _1;
342 : or
343 : _2 = 5; */
344 :
345 : static bool
346 175419136 : stmt_may_generate_copy (gimple *stmt)
347 : {
348 : /* A PHI may generate a copy. */
349 175419136 : if (gimple_code (stmt) == GIMPLE_PHI)
350 : {
351 8822304 : gphi *phi = as_a <gphi *> (stmt);
352 :
353 : /* No OCCURS_IN_ABNORMAL_PHI SSA names in lhs nor rhs. */
354 8822304 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (phi)))
355 : return false;
356 :
357 : unsigned i;
358 31438434 : for (i = 0; i < gimple_phi_num_args (phi); i++)
359 : {
360 22630224 : tree op = gimple_phi_arg_def (phi, i);
361 22630224 : if (TREE_CODE (op) == SSA_NAME
362 22630224 : && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op))
363 : return false;
364 : }
365 :
366 : /* If PHI has more than one unique non-SSA arguments, it won't generate a
367 : copy. */
368 : tree const_op = NULL_TREE;
369 30588570 : for (i = 0; i < gimple_phi_num_args (phi); i++)
370 : {
371 22111076 : tree op = gimple_phi_arg_def (phi, i);
372 22111076 : if (TREE_CODE (op) != SSA_NAME)
373 : {
374 2713562 : if (const_op && !operand_equal_p (op, const_op))
375 : return false;
376 : const_op = op;
377 : }
378 : }
379 :
380 : return true;
381 : }
382 :
383 : /* Or a statement of type _2 = _1; OR _2 = 5; may generate a copy. */
384 :
385 166596832 : if (!gimple_assign_single_p (stmt))
386 : return false;
387 :
388 32513860 : tree lhs = gimple_assign_lhs (stmt);
389 32513860 : tree rhs = gimple_assign_rhs1 (stmt);
390 :
391 32513860 : if (TREE_CODE (lhs) != SSA_NAME)
392 : return false;
393 :
394 : /* lhs shouldn't flow through any abnormal edges. */
395 14325757 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
396 : return false;
397 :
398 14324933 : if (is_gimple_min_invariant (rhs))
399 : return true; /* A statement of type _2 = 5;. */
400 :
401 14317679 : if (TREE_CODE (rhs) != SSA_NAME)
402 : return false;
403 :
404 : /* rhs shouldn't flow through any abnormal edges. */
405 27185 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs))
406 : return false;
407 :
408 : return true; /* A statement of type _2 = _1;. */
409 : }
410 :
411 : /* Return all statements in cfun that could generate copies. All statements
412 : for which stmt_may_generate_copy returns 'true'. */
413 :
414 : static auto_vec<gimple *>
415 3583169 : get_all_stmt_may_generate_copy (void)
416 : {
417 3583169 : auto_vec<gimple *> result;
418 :
419 3583169 : basic_block bb;
420 26768336 : FOR_EACH_BB_FN (bb, cfun)
421 : {
422 23185167 : gimple_stmt_iterator gsi;
423 212967166 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
424 : {
425 166596832 : gimple *s = gsi_stmt (gsi);
426 166596832 : if (stmt_may_generate_copy (s))
427 33265 : result.safe_push (s);
428 : }
429 :
430 23185167 : gphi_iterator pi;
431 32007471 : for (pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
432 : {
433 8822304 : gimple *s = pi.phi ();
434 8822304 : if (stmt_may_generate_copy (s))
435 8477494 : result.safe_push (s);
436 : }
437 : }
438 :
439 3583169 : return result;
440 : }
441 :
442 : /* SCC copy propagation
443 :
444 : 'scc_copy_prop::propagate ()' is the main function of this pass. */
445 :
446 : class scc_copy_prop
447 : {
448 : public:
449 : scc_copy_prop ();
450 : ~scc_copy_prop ();
451 : bool propagate ();
452 :
453 : private:
454 : /* Bitmap tracking statements which were propagated so that they can be
455 : removed at the end of the pass. */
456 : bitmap dead_stmts;
457 :
458 : void visit_op (tree op, hash_set<tree> &outer_ops,
459 : hash_set<gimple *> &scc_set, bool &is_inner,
460 : tree &last_outer_op);
461 : bool replace_scc_by_value (vec<gimple *> scc, tree val);
462 : };
463 :
464 : /* For each statement from given SCC, replace its usages by value
465 : VAL. */
466 :
467 : bool
468 1013729 : scc_copy_prop::replace_scc_by_value (vec<gimple *> scc, tree val)
469 : {
470 1013729 : bool didsomething = false;
471 4065888 : for (gimple *stmt : scc)
472 : {
473 1024701 : tree name = gimple_get_lhs (stmt);
474 1024701 : if (dump_file && (dump_flags & TDF_DETAILS))
475 : {
476 0 : fprintf (dump_file, "Replacing ");
477 0 : print_generic_expr (dump_file, name);
478 0 : fprintf (dump_file, " with ");
479 0 : print_generic_expr (dump_file, val);
480 0 : fprintf (dump_file, "\n");
481 :
482 : }
483 1024701 : replace_uses_by (name, val);
484 1024701 : if (TREE_CODE (val) == SSA_NAME)
485 1014775 : maybe_duplicate_ssa_info_at_copy (name, val);
486 1024701 : bitmap_set_bit (dead_stmts, SSA_NAME_VERSION (name));
487 1024701 : didsomething = true;
488 : }
489 :
490 1013729 : if (dump_file)
491 56 : fprintf (dump_file, "Replacing SCC of size %d\n", scc.length ());
492 1013729 : return didsomething;
493 : }
494 :
495 : /* Part of 'scc_copy_prop::propagate ()'. */
496 :
497 : void
498 21734566 : scc_copy_prop::visit_op (tree op, hash_set<tree> &outer_ops,
499 : hash_set<gimple *> &scc_set, bool &is_inner,
500 : tree &last_outer_op)
501 : {
502 21734566 : bool op_in_scc = false;
503 :
504 21734566 : if (TREE_CODE (op) == SSA_NAME)
505 : {
506 19743516 : gimple *op_stmt = SSA_NAME_DEF_STMT (op);
507 19743516 : if (scc_set.contains (op_stmt))
508 1208963 : op_in_scc = true;
509 : }
510 :
511 19743516 : if (!op_in_scc)
512 : {
513 20525603 : outer_ops.add (op);
514 20525603 : last_outer_op = op;
515 20525603 : is_inner = false;
516 : }
517 21734566 : }
518 :
519 : /* Main function of this pass. Find and propagate all three types of copy
520 : statements (see pass description above).
521 :
522 : This is an implementation of an algorithm from the paper Simple and
523 : Efficient Construction of Static Single Assignmemnt Form[1]. It is based
524 : on strongly-connected components (SCCs) in dataflow graph. The original
525 : algorithm only considers PHI statements. We extend it to also consider
526 : assignment statements of type _2 = _1;.
527 :
528 : The algorithm is based on this definition of a set of redundant PHIs[1]:
529 :
530 : A non-empty set P of PHI functions is redundant iff the PHI functions just
531 : reference each other or one other value
532 :
533 : It uses this lemma[1]:
534 :
535 : Let P be a redundant set of PHI functions. Then there is a
536 : strongly-connected component S subset of P that is also redundant.
537 :
538 : The algorithm works in this way:
539 :
540 : 1 Find SCCs
541 : 2 For each SCC S in topological order:
542 : 3 Construct set 'inner' of statements that only have other statements
543 : from S on their right hand side
544 : 4 Construct set 'outer' of values that originate outside S and appear on
545 : right hand side of some statement from S
546 : 5 If |outer| = 1, outer only contains a value v. Statements in S only
547 : refer to each other or to v -- they are redundant. Propagate v.
548 : Else, recurse on statements in inner.
549 :
550 : The implementation is non-recursive.
551 :
552 : References:
553 :
554 : [1] Simple and Efficient Construction of Static Single Assignmemnt Form,
555 : Braun, Buchwald, Hack, Leissa, Mallon, Zwinkau, 2013, LNCS vol. 7791,
556 : Section 3.2. */
557 :
558 : bool
559 3583169 : scc_copy_prop::propagate ()
560 : {
561 3583169 : bool didsomething = false;
562 3583169 : auto_vec<gimple *> useful_stmts = get_all_stmt_may_generate_copy ();
563 3583169 : scc_discovery discovery;
564 :
565 3583169 : auto_vec<vec<gimple *>> worklist = discovery.compute_sccs (useful_stmts);
566 :
567 15339741 : while (!worklist.is_empty ())
568 : {
569 8173403 : vec<gimple *> scc = worklist.pop ();
570 :
571 : /* When we do 'replace_scc_by_value' it may happen that some EH edges
572 : get removed. That means parts of CFG get removed. Those may
573 : contain copy statements. For that reason we prune SCCs here. */
574 8173403 : unsigned i;
575 16863508 : for (i = 0; i < scc.length ();)
576 8690105 : if (gimple_bb (scc[i]) == NULL)
577 0 : scc.unordered_remove (i);
578 : else
579 8690105 : i++;
580 8173403 : if (scc.is_empty ())
581 : {
582 0 : scc.release ();
583 0 : continue;
584 : }
585 :
586 8173403 : auto_vec<gimple *> inner;
587 8173403 : hash_set<tree> outer_ops;
588 8173403 : tree last_outer_op = NULL_TREE;
589 :
590 : /* Prepare hash set of PHIs in scc to query later. */
591 8173403 : hash_set<gimple *> scc_set;
592 16863508 : for (gimple *stmt : scc)
593 8690105 : scc_set.add (stmt);
594 :
595 16863508 : for (gimple *stmt : scc)
596 : {
597 8690105 : bool is_inner = true;
598 :
599 8690105 : gphi *phi;
600 8690105 : tree op;
601 :
602 8690105 : switch (gimple_code (stmt))
603 : {
604 8656840 : case GIMPLE_PHI:
605 8656840 : phi = as_a <gphi *> (stmt);
606 8656840 : unsigned j;
607 39014981 : for (j = 0; j < gimple_phi_num_args (phi); j++)
608 : {
609 21701301 : op = gimple_phi_arg_def (phi, j);
610 21701301 : visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
611 : }
612 : break;
613 33265 : case GIMPLE_ASSIGN:
614 33265 : op = gimple_assign_rhs1 (stmt);
615 33265 : visit_op (op, outer_ops, scc_set, is_inner, last_outer_op);
616 33265 : break;
617 0 : default:
618 0 : gcc_unreachable ();
619 : }
620 :
621 8690105 : if (is_inner)
622 189815 : inner.safe_push (stmt);
623 : }
624 :
625 8173403 : if (outer_ops.elements () == 1)
626 : {
627 : /* The only operand in outer_ops. */
628 1013729 : tree outer_op = last_outer_op;
629 1013729 : didsomething |= replace_scc_by_value (scc, outer_op);
630 : }
631 7159674 : else if (outer_ops.elements () > 1)
632 : {
633 : /* Add inner sccs to worklist. */
634 7159674 : auto_vec<vec<gimple *>> inner_sccs
635 7159674 : = discovery.compute_sccs (inner);
636 7490499 : for (vec<gimple *> inner_scc : inner_sccs)
637 150229 : worklist.safe_push (inner_scc);
638 7159674 : }
639 : else
640 0 : gcc_unreachable ();
641 :
642 8173403 : scc.release ();
643 8173403 : }
644 3583169 : return didsomething;
645 3583169 : }
646 :
647 3583169 : scc_copy_prop::scc_copy_prop ()
648 : {
649 : /* For propagated statements. */
650 3583169 : dead_stmts = BITMAP_ALLOC (NULL);
651 3583169 : }
652 :
653 3583169 : scc_copy_prop::~scc_copy_prop ()
654 : {
655 : /* Remove all propagated statements. */
656 3583169 : simple_dce_from_worklist (dead_stmts);
657 3583169 : BITMAP_FREE (dead_stmts);
658 :
659 : /* Propagating a constant may create dead eh edges. */
660 3583169 : basic_block bb;
661 26768334 : FOR_EACH_BB_FN (bb, cfun)
662 23185165 : gimple_purge_dead_eh_edges (bb);
663 3583169 : }
664 :
665 : namespace {
666 :
667 : const pass_data pass_data_sccopy =
668 : {
669 : GIMPLE_PASS, /* type */
670 : "sccopy", /* name */
671 : OPTGROUP_NONE, /* optinfo_flags */
672 : TV_NONE, /* tv_id */
673 : ( PROP_cfg | PROP_ssa ), /* properties_required */
674 : 0, /* properties_provided */
675 : 0, /* properties_destroyed */
676 : 0, /* todo_flags_start */
677 : 0, /* todo_flags_finish */
678 : };
679 :
680 : class pass_sccopy : public gimple_opt_pass
681 : {
682 : public:
683 584742 : pass_sccopy (gcc::context *ctxt)
684 1169484 : : gimple_opt_pass (pass_data_sccopy, ctxt)
685 : {}
686 :
687 : /* opt_pass methods: */
688 3583290 : virtual bool gate (function *) final override { return true; }
689 : virtual unsigned int execute (function *) final override;
690 292371 : opt_pass * clone () final override { return new pass_sccopy (m_ctxt); }
691 : }; // class pass_sccopy
692 :
693 : unsigned
694 3583169 : pass_sccopy::execute (function *)
695 : {
696 3583169 : scc_copy_prop sccopy;
697 3583169 : return sccopy.propagate () ? TODO_cleanup_cfg : 0;
698 3583169 : }
699 :
700 : } // anon namespace
701 :
702 : gimple_opt_pass *
703 292371 : make_pass_sccopy (gcc::context *ctxt)
704 : {
705 292371 : return new pass_sccopy (ctxt);
706 : }
|