Line data Source code
1 : /* Exception handling semantics and decomposition for trees.
2 : Copyright (C) 2003-2026 Free Software Foundation, Inc.
3 :
4 : This file is part of GCC.
5 :
6 : GCC is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3, or (at your option)
9 : any later version.
10 :
11 : GCC is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with GCC; see the file COPYING3. If not see
18 : <http://www.gnu.org/licenses/>. */
19 :
20 : #include "config.h"
21 : #include "system.h"
22 : #include "coretypes.h"
23 : #include "backend.h"
24 : #include "rtl.h"
25 : #include "tree.h"
26 : #include "gimple.h"
27 : #include "cfghooks.h"
28 : #include "tree-pass.h"
29 : #include "ssa.h"
30 : #include "cgraph.h"
31 : #include "diagnostic-core.h"
32 : #include "fold-const.h"
33 : #include "calls.h"
34 : #include "except.h"
35 : #include "cfganal.h"
36 : #include "cfgcleanup.h"
37 : #include "tree-eh.h"
38 : #include "gimple-iterator.h"
39 : #include "tree-cfg.h"
40 : #include "tree-into-ssa.h"
41 : #include "tree-ssa.h"
42 : #include "tree-inline.h"
43 : #include "langhooks.h"
44 : #include "cfgloop.h"
45 : #include "gimple-low.h"
46 : #include "stringpool.h"
47 : #include "attribs.h"
48 : #include "asan.h"
49 : #include "gimplify.h"
50 :
51 : /* In some instances a tree and a gimple need to be stored in a same table,
52 : i.e. in hash tables. This is a structure to do this. */
53 : typedef union {tree *tp; tree t; gimple *g;} treemple;
54 :
55 : /* Misc functions used in this file. */
56 :
57 : /* Remember and lookup EH landing pad data for arbitrary statements.
58 : Really this means any statement that could_throw_p. We could
59 : stuff this information into the stmt_ann data structure, but:
60 :
61 : (1) We absolutely rely on this information being kept until
62 : we get to rtl. Once we're done with lowering here, if we lose
63 : the information there's no way to recover it!
64 :
65 : (2) There are many more statements that *cannot* throw as
66 : compared to those that can. We should be saving some amount
67 : of space by only allocating memory for those that can throw. */
68 :
69 : /* Add statement T in function IFUN to landing pad NUM. */
70 :
71 : static void
72 6840571 : add_stmt_to_eh_lp_fn (struct function *ifun, gimple *t, int num)
73 : {
74 6840571 : gcc_assert (num != 0);
75 :
76 6840571 : if (!get_eh_throw_stmt_table (ifun))
77 425282 : set_eh_throw_stmt_table (ifun, hash_map<gimple *, int>::create_ggc (31));
78 :
79 6840571 : bool existed = get_eh_throw_stmt_table (ifun)->put (t, num);
80 6840571 : gcc_assert (!existed);
81 6840571 : }
82 :
83 : /* Add statement T in the current function (cfun) to EH landing pad NUM. */
84 :
85 : void
86 2684190 : add_stmt_to_eh_lp (gimple *t, int num)
87 : {
88 2684190 : add_stmt_to_eh_lp_fn (cfun, t, num);
89 2684190 : }
90 :
91 : /* Add statement T to the single EH landing pad in REGION. */
92 :
93 : static void
94 3320216 : record_stmt_eh_region (eh_region region, gimple *t)
95 : {
96 3320216 : if (region == NULL)
97 : return;
98 3320216 : if (region->type == ERT_MUST_NOT_THROW)
99 98761 : add_stmt_to_eh_lp_fn (cfun, t, -region->index);
100 : else
101 : {
102 3221455 : eh_landing_pad lp = region->landing_pads;
103 3221455 : if (lp == NULL)
104 948533 : lp = gen_eh_landing_pad (region);
105 : else
106 2272922 : gcc_assert (lp->next_lp == NULL);
107 3221455 : add_stmt_to_eh_lp_fn (cfun, t, lp->index);
108 : }
109 : }
110 :
111 :
112 : /* Remove statement T in function IFUN from its EH landing pad. */
113 :
114 : bool
115 310754679 : remove_stmt_from_eh_lp_fn (struct function *ifun, gimple *t)
116 : {
117 310754679 : if (!get_eh_throw_stmt_table (ifun))
118 : return false;
119 :
120 145060250 : if (!get_eh_throw_stmt_table (ifun)->get (t))
121 : return false;
122 :
123 5970125 : get_eh_throw_stmt_table (ifun)->remove (t);
124 5970125 : return true;
125 : }
126 :
127 :
128 : /* Remove statement T in the current function (cfun) from its
129 : EH landing pad. */
130 :
131 : bool
132 128632756 : remove_stmt_from_eh_lp (gimple *t)
133 : {
134 128632756 : return remove_stmt_from_eh_lp_fn (cfun, t);
135 : }
136 :
137 : /* Determine if statement T is inside an EH region in function IFUN.
138 : Positive numbers indicate a landing pad index; negative numbers
139 : indicate a MUST_NOT_THROW region index; zero indicates that the
140 : statement is not recorded in the region table. */
141 :
142 : int
143 16266622737 : lookup_stmt_eh_lp_fn (struct function *ifun, const gimple *t)
144 : {
145 16266622737 : if (ifun->eh->throw_stmt_table == NULL)
146 : return 0;
147 :
148 8922029100 : int *lp_nr = ifun->eh->throw_stmt_table->get (const_cast <gimple *> (t));
149 8922029100 : return lp_nr ? *lp_nr : 0;
150 : }
151 :
152 : /* Likewise, but always use the current function. */
153 :
154 : int
155 15586260174 : lookup_stmt_eh_lp (const gimple *t)
156 : {
157 : /* We can get called from initialized data when -fnon-call-exceptions
158 : is on; prevent crash. */
159 15586260174 : if (!cfun)
160 : return 0;
161 15586260174 : return lookup_stmt_eh_lp_fn (cfun, t);
162 : }
163 :
164 : /* First pass of EH node decomposition. Build up a tree of GIMPLE_TRY_FINALLY
165 : nodes and LABEL_DECL nodes. We will use this during the second phase to
166 : determine if a goto leaves the body of a TRY_FINALLY_EXPR node. */
167 :
168 : struct finally_tree_node
169 : {
170 : /* When storing a GIMPLE_TRY, we have to record a gimple. However
171 : when deciding whether a GOTO to a certain LABEL_DECL (which is a
172 : tree) leaves the TRY block, its necessary to record a tree in
173 : this field. Thus a treemple is used. */
174 : treemple child;
175 : gtry *parent;
176 : };
177 :
178 : /* Hashtable helpers. */
179 :
180 : struct finally_tree_hasher : free_ptr_hash <finally_tree_node>
181 : {
182 : static inline hashval_t hash (const finally_tree_node *);
183 : static inline bool equal (const finally_tree_node *,
184 : const finally_tree_node *);
185 : };
186 :
187 : inline hashval_t
188 149961287 : finally_tree_hasher::hash (const finally_tree_node *v)
189 : {
190 149961287 : return (intptr_t)v->child.t >> 4;
191 : }
192 :
193 : inline bool
194 133373556 : finally_tree_hasher::equal (const finally_tree_node *v,
195 : const finally_tree_node *c)
196 : {
197 133373556 : return v->child.t == c->child.t;
198 : }
199 :
200 : /* Note that this table is *not* marked GTY. It is short-lived. */
201 : static hash_table<finally_tree_hasher> *finally_tree;
202 :
203 : static void
204 18494773 : record_in_finally_tree (treemple child, gtry *parent)
205 : {
206 18494773 : struct finally_tree_node *n;
207 18494773 : finally_tree_node **slot;
208 :
209 18494773 : n = XNEW (struct finally_tree_node);
210 18494773 : n->child = child;
211 18494773 : n->parent = parent;
212 :
213 18494773 : slot = finally_tree->find_slot (n, INSERT);
214 18494773 : gcc_assert (!*slot);
215 18494773 : *slot = n;
216 18494773 : }
217 :
218 : static void
219 : collect_finally_tree (gimple *stmt, gtry *region);
220 :
221 : /* Go through the gimple sequence. Works with collect_finally_tree to
222 : record all GIMPLE_LABEL and GIMPLE_TRY statements. */
223 :
224 : static void
225 9373757 : collect_finally_tree_1 (gimple_seq seq, gtry *region)
226 : {
227 9373757 : gimple_stmt_iterator gsi;
228 :
229 101139136 : for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
230 91765379 : collect_finally_tree (gsi_stmt (gsi), region);
231 5240532 : }
232 :
233 : static void
234 91765379 : collect_finally_tree (gimple *stmt, gtry *region)
235 : {
236 91765379 : treemple temp;
237 :
238 91765379 : switch (gimple_code (stmt))
239 : {
240 16694408 : case GIMPLE_LABEL:
241 16694408 : temp.t = gimple_label_label (as_a <glabel *> (stmt));
242 16694408 : record_in_finally_tree (temp, region);
243 16694408 : break;
244 :
245 2587253 : case GIMPLE_TRY:
246 2587253 : if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
247 : {
248 1744926 : temp.g = stmt;
249 1744926 : record_in_finally_tree (temp, region);
250 1744926 : collect_finally_tree_1 (gimple_try_eval (stmt),
251 : as_a <gtry *> (stmt));
252 1744926 : collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
253 : }
254 842327 : else if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
255 : {
256 842327 : collect_finally_tree_1 (gimple_try_eval (stmt), region);
257 842327 : collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
258 : }
259 : break;
260 :
261 58531 : case GIMPLE_CATCH:
262 117062 : collect_finally_tree_1 (gimple_catch_handler (
263 58531 : as_a <gcatch *> (stmt)),
264 : region);
265 58531 : break;
266 :
267 5841 : case GIMPLE_EH_FILTER:
268 5841 : collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
269 5841 : break;
270 :
271 827 : case GIMPLE_EH_ELSE:
272 827 : {
273 827 : geh_else *eh_else_stmt = as_a <geh_else *> (stmt);
274 827 : collect_finally_tree_1 (gimple_eh_else_n_body (eh_else_stmt), region);
275 827 : collect_finally_tree_1 (gimple_eh_else_e_body (eh_else_stmt), region);
276 : }
277 827 : break;
278 :
279 : default:
280 : /* A type, a decl, or some kind of statement that we're not
281 : interested in. Don't walk them. */
282 : break;
283 : }
284 91765379 : }
285 :
286 :
287 : /* Use the finally tree to determine if a jump from START to TARGET
288 : would leave the try_finally node that START lives in. */
289 :
290 : static bool
291 8981899 : outside_finally_tree (treemple start, gimple *target)
292 : {
293 9720766 : struct finally_tree_node n, *p;
294 :
295 9720766 : do
296 : {
297 9720766 : n.child = start;
298 9720766 : p = finally_tree->find (&n);
299 9720766 : if (!p)
300 : return true;
301 9015403 : start.g = p->parent;
302 : }
303 9015403 : while (start.g != target);
304 :
305 : return false;
306 : }
307 :
308 : /* Second pass of EH node decomposition. Actually transform the GIMPLE_TRY
309 : nodes into a set of gotos, magic labels, and eh regions.
310 : The eh region creation is straight-forward, but frobbing all the gotos
311 : and such into shape isn't. */
312 :
313 : /* The sequence into which we record all EH stuff. This will be
314 : placed at the end of the function when we're all done. */
315 : static gimple_seq eh_seq;
316 :
317 : /* Record whether an EH region contains something that can throw,
318 : indexed by EH region number. */
319 : static bitmap eh_region_may_contain_throw_map;
320 :
321 : /* The GOTO_QUEUE is an array of GIMPLE_GOTO and GIMPLE_RETURN
322 : statements that are seen to escape this GIMPLE_TRY_FINALLY node.
323 : The idea is to record a gimple statement for everything except for
324 : the conditionals, which get their labels recorded. Since labels are
325 : of type 'tree', we need this node to store both gimple and tree
326 : objects. REPL_STMT is the sequence used to replace the goto/return
327 : statement. CONT_STMT is used to store the statement that allows
328 : the return/goto to jump to the original destination. */
329 :
330 : struct goto_queue_node
331 : {
332 : treemple stmt;
333 : location_t location;
334 : gimple_seq repl_stmt;
335 : gimple *cont_stmt;
336 : int index;
337 : /* This is used when index >= 0 to indicate that stmt is a label (as
338 : opposed to a goto stmt). */
339 : int is_label;
340 : };
341 :
342 : /* State of the world while lowering. */
343 :
344 : struct leh_state
345 : {
346 : /* What's "current" while constructing the eh region tree. These
347 : correspond to variables of the same name in cfun->eh, which we
348 : don't have easy access to. */
349 : eh_region cur_region;
350 :
351 : /* What's "current" for the purposes of __builtin_eh_pointer. For
352 : a CATCH, this is the associated TRY. For an EH_FILTER, this is
353 : the associated ALLOWED_EXCEPTIONS, etc. */
354 : eh_region ehp_region;
355 :
356 : /* Processing of TRY_FINALLY requires a bit more state. This is
357 : split out into a separate structure so that we don't have to
358 : copy so much when processing other nodes. */
359 : struct leh_tf_state *tf;
360 :
361 : /* Outer non-clean up region. */
362 : eh_region outer_non_cleanup;
363 : };
364 :
365 : struct leh_tf_state
366 : {
367 : /* Pointer to the GIMPLE_TRY_FINALLY node under discussion. The
368 : try_finally_expr is the original GIMPLE_TRY_FINALLY. We need to retain
369 : this so that outside_finally_tree can reliably reference the tree used
370 : in the collect_finally_tree data structures. */
371 : gtry *try_finally_expr;
372 : gtry *top_p;
373 :
374 : /* While lowering a top_p usually it is expanded into multiple statements,
375 : thus we need the following field to store them. */
376 : gimple_seq top_p_seq;
377 :
378 : /* The state outside this try_finally node. */
379 : struct leh_state *outer;
380 :
381 : /* The exception region created for it. */
382 : eh_region region;
383 :
384 : /* The goto queue. */
385 : struct goto_queue_node *goto_queue;
386 : size_t goto_queue_size;
387 : size_t goto_queue_active;
388 :
389 : /* Pointer map to help in searching goto_queue when it is large. */
390 : hash_map<gimple *, goto_queue_node *> *goto_queue_map;
391 :
392 : /* The set of unique labels seen as entries in the goto queue. */
393 : vec<tree> dest_array;
394 :
395 : /* A label to be added at the end of the completed transformed
396 : sequence. It will be set if may_fallthru was true *at one time*,
397 : though subsequent transformations may have cleared that flag. */
398 : tree fallthru_label;
399 :
400 : /* True if it is possible to fall out the bottom of the try block.
401 : Cleared if the fallthru is converted to a goto. */
402 : bool may_fallthru;
403 :
404 : /* True if any entry in goto_queue is a GIMPLE_RETURN. */
405 : bool may_return;
406 :
407 : /* True if the finally block can receive an exception edge.
408 : Cleared if the exception case is handled by code duplication. */
409 : bool may_throw;
410 : };
411 :
412 : static gimple_seq lower_eh_must_not_throw (struct leh_state *, gtry *);
413 :
414 : /* Search for STMT in the goto queue. Return the replacement,
415 : or null if the statement isn't in the queue. */
416 :
417 : #define LARGE_GOTO_QUEUE 20
418 :
419 : static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq *seq);
420 :
421 : static gimple_seq
422 7075779 : find_goto_replacement (struct leh_tf_state *tf, treemple stmt)
423 : {
424 7075779 : unsigned int i;
425 :
426 7075779 : if (tf->goto_queue_active < LARGE_GOTO_QUEUE)
427 : {
428 21126990 : for (i = 0; i < tf->goto_queue_active; i++)
429 14828089 : if ( tf->goto_queue[i].stmt.g == stmt.g)
430 690368 : return tf->goto_queue[i].repl_stmt;
431 : return NULL;
432 : }
433 :
434 : /* If we have a large number of entries in the goto_queue, create a
435 : pointer map and use that for searching. */
436 :
437 86510 : if (!tf->goto_queue_map)
438 : {
439 609 : tf->goto_queue_map = new hash_map<gimple *, goto_queue_node *>;
440 15604 : for (i = 0; i < tf->goto_queue_active; i++)
441 : {
442 29990 : bool existed = tf->goto_queue_map->put (tf->goto_queue[i].stmt.g,
443 14995 : &tf->goto_queue[i]);
444 14995 : gcc_assert (!existed);
445 : }
446 : }
447 :
448 86510 : goto_queue_node **slot = tf->goto_queue_map->get (stmt.g);
449 86510 : if (slot != NULL)
450 14995 : return ((*slot)->repl_stmt);
451 :
452 : return NULL;
453 : }
454 :
455 : /* A subroutine of replace_goto_queue_1. Handles the sub-clauses of a
456 : lowered GIMPLE_COND. If, by chance, the replacement is a simple goto,
457 : then we can just splat it in, otherwise we add the new stmts immediately
458 : after the GIMPLE_COND and redirect. */
459 :
460 : static void
461 4476388 : replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
462 : gimple_stmt_iterator *gsi)
463 : {
464 4476388 : tree label;
465 4476388 : gimple_seq new_seq;
466 4476388 : treemple temp;
467 4476388 : location_t loc = gimple_location (gsi_stmt (*gsi));
468 :
469 4476388 : temp.tp = tp;
470 4476388 : new_seq = find_goto_replacement (tf, temp);
471 4476388 : if (!new_seq)
472 4476309 : return;
473 :
474 1834 : if (gimple_seq_singleton_p (new_seq)
475 1755 : && gimple_code (gimple_seq_first_stmt (new_seq)) == GIMPLE_GOTO)
476 : {
477 1755 : *tp = gimple_goto_dest (gimple_seq_first_stmt (new_seq));
478 1755 : return;
479 : }
480 :
481 79 : label = create_artificial_label (loc);
482 : /* Set the new label for the GIMPLE_COND */
483 79 : *tp = label;
484 :
485 79 : gsi_insert_after (gsi, gimple_build_label (label), GSI_CONTINUE_LINKING);
486 79 : gsi_insert_seq_after (gsi, gimple_seq_copy (new_seq), GSI_CONTINUE_LINKING);
487 : }
488 :
489 : /* The real work of replace_goto_queue. Returns with TSI updated to
490 : point to the next statement. */
491 :
492 : static void replace_goto_queue_stmt_list (gimple_seq *, struct leh_tf_state *);
493 :
494 : static void
495 35679544 : replace_goto_queue_1 (gimple *stmt, struct leh_tf_state *tf,
496 : gimple_stmt_iterator *gsi)
497 : {
498 35679544 : gimple_seq seq;
499 35679544 : treemple temp;
500 35679544 : temp.g = NULL;
501 :
502 35679544 : switch (gimple_code (stmt))
503 : {
504 2599221 : case GIMPLE_GOTO:
505 2599221 : case GIMPLE_RETURN:
506 2599221 : temp.g = stmt;
507 2599221 : seq = find_goto_replacement (tf, temp);
508 2599221 : if (seq)
509 : {
510 703494 : gimple_stmt_iterator i;
511 703494 : seq = gimple_seq_copy (seq);
512 2111720 : for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
513 1256536 : gimple_set_location (gsi_stmt (i), gimple_location (stmt));
514 703494 : gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
515 703494 : gsi_remove (gsi, false);
516 703494 : return;
517 : }
518 : break;
519 :
520 12932 : case GIMPLE_ASM:
521 12932 : if (int n = gimple_asm_nlabels (as_a <gasm *> (stmt)))
522 : {
523 114 : temp.g = stmt;
524 114 : gasm *asm_stmt = as_a <gasm *> (stmt);
525 114 : location_t loc = gimple_location (stmt);
526 114 : tree bypass_label = NULL_TREE;
527 284 : for (int i = 0; i < n; ++i)
528 : {
529 170 : tree elt = gimple_asm_label_op (asm_stmt, i);
530 170 : temp.tp = &TREE_VALUE (elt);
531 170 : seq = find_goto_replacement (tf, temp);
532 170 : if (!seq)
533 135 : continue;
534 35 : if (gimple_seq_singleton_p (seq)
535 30 : && gimple_code (gimple_seq_first_stmt (seq)) == GIMPLE_GOTO)
536 : {
537 30 : TREE_VALUE (elt)
538 30 : = gimple_goto_dest (gimple_seq_first_stmt (seq));
539 30 : continue;
540 : }
541 :
542 5 : if (bypass_label == NULL_TREE)
543 : {
544 3 : bypass_label = create_artificial_label (loc);
545 3 : gsi_insert_after (gsi, gimple_build_goto (bypass_label),
546 : GSI_CONTINUE_LINKING);
547 : }
548 :
549 5 : tree label = create_artificial_label (loc);
550 5 : TREE_VALUE (elt) = label;
551 5 : gsi_insert_after (gsi, gimple_build_label (label),
552 : GSI_CONTINUE_LINKING);
553 5 : gsi_insert_seq_after (gsi, gimple_seq_copy (seq),
554 : GSI_CONTINUE_LINKING);
555 : }
556 114 : if (bypass_label)
557 3 : gsi_insert_after (gsi, gimple_build_label (bypass_label),
558 : GSI_CONTINUE_LINKING);
559 : }
560 : break;
561 :
562 2238194 : case GIMPLE_COND:
563 2238194 : replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 2), tf, gsi);
564 2238194 : replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 3), tf, gsi);
565 2238194 : break;
566 :
567 0 : case GIMPLE_TRY:
568 0 : replace_goto_queue_stmt_list (gimple_try_eval_ptr (stmt), tf);
569 0 : replace_goto_queue_stmt_list (gimple_try_cleanup_ptr (stmt), tf);
570 0 : break;
571 0 : case GIMPLE_CATCH:
572 0 : replace_goto_queue_stmt_list (gimple_catch_handler_ptr (
573 : as_a <gcatch *> (stmt)),
574 : tf);
575 0 : break;
576 0 : case GIMPLE_EH_FILTER:
577 0 : replace_goto_queue_stmt_list (gimple_eh_filter_failure_ptr (stmt), tf);
578 0 : break;
579 0 : case GIMPLE_EH_ELSE:
580 0 : {
581 0 : geh_else *eh_else_stmt = as_a <geh_else *> (stmt);
582 0 : replace_goto_queue_stmt_list (gimple_eh_else_n_body_ptr (eh_else_stmt),
583 : tf);
584 0 : replace_goto_queue_stmt_list (gimple_eh_else_e_body_ptr (eh_else_stmt),
585 : tf);
586 : }
587 0 : break;
588 :
589 : default:
590 : /* These won't have gotos in them. */
591 : break;
592 : }
593 :
594 34976050 : gsi_next (gsi);
595 : }
596 :
597 : /* A subroutine of replace_goto_queue. Handles GIMPLE_SEQ. */
598 :
599 : static void
600 1067124 : replace_goto_queue_stmt_list (gimple_seq *seq, struct leh_tf_state *tf)
601 : {
602 1067124 : gimple_stmt_iterator gsi = gsi_start (*seq);
603 :
604 36746668 : while (!gsi_end_p (gsi))
605 35679544 : replace_goto_queue_1 (gsi_stmt (gsi), tf, &gsi);
606 1067124 : }
607 :
608 : /* Replace all goto queue members. */
609 :
610 : static void
611 536330 : replace_goto_queue (struct leh_tf_state *tf)
612 : {
613 536330 : if (tf->goto_queue_active == 0)
614 : return;
615 533562 : replace_goto_queue_stmt_list (&tf->top_p_seq, tf);
616 533562 : replace_goto_queue_stmt_list (&eh_seq, tf);
617 : }
618 :
619 : /* Add a new record to the goto queue contained in TF. NEW_STMT is the
620 : data to be added, IS_LABEL indicates whether NEW_STMT is a label or
621 : a gimple return. */
622 :
623 : static void
624 705363 : record_in_goto_queue (struct leh_tf_state *tf,
625 : treemple new_stmt,
626 : int index,
627 : bool is_label,
628 : location_t location)
629 : {
630 705363 : size_t active, size;
631 705363 : struct goto_queue_node *q;
632 :
633 705363 : gcc_assert (!tf->goto_queue_map);
634 :
635 705363 : active = tf->goto_queue_active;
636 705363 : size = tf->goto_queue_size;
637 705363 : if (active >= size)
638 : {
639 533605 : size = (size ? size * 2 : 32);
640 533605 : tf->goto_queue_size = size;
641 533605 : tf->goto_queue
642 533605 : = XRESIZEVEC (struct goto_queue_node, tf->goto_queue, size);
643 : }
644 :
645 705363 : q = &tf->goto_queue[active];
646 705363 : tf->goto_queue_active = active + 1;
647 :
648 705363 : memset (q, 0, sizeof (*q));
649 705363 : q->stmt = new_stmt;
650 705363 : q->index = index;
651 705363 : q->location = location;
652 705363 : q->is_label = is_label;
653 705363 : }
654 :
655 : /* Record the LABEL label in the goto queue contained in TF.
656 : TF is not null. */
657 :
658 : static void
659 8765051 : record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label,
660 : location_t location)
661 : {
662 8765051 : int index;
663 8765051 : treemple temp, new_stmt;
664 :
665 8765051 : if (!label)
666 8059688 : return;
667 :
668 : /* Computed and non-local gotos do not get processed. Given
669 : their nature we can neither tell whether we've escaped the
670 : finally block nor redirect them if we knew. */
671 8765051 : if (TREE_CODE (label) != LABEL_DECL)
672 : return;
673 :
674 : /* No need to record gotos that don't leave the try block. */
675 8764811 : temp.t = label;
676 8764811 : if (!outside_finally_tree (temp, tf->try_finally_expr))
677 : return;
678 :
679 705363 : if (! tf->dest_array.exists ())
680 : {
681 533562 : tf->dest_array.create (10);
682 533562 : tf->dest_array.quick_push (label);
683 533562 : index = 0;
684 : }
685 : else
686 : {
687 171801 : int n = tf->dest_array.length ();
688 189064 : for (index = 0; index < n; ++index)
689 184804 : if (tf->dest_array[index] == label)
690 : break;
691 171801 : if (index == n)
692 4260 : tf->dest_array.safe_push (label);
693 : }
694 :
695 : /* In the case of a GOTO we want to record the destination label,
696 : since with a GIMPLE_COND we have an easy access to the then/else
697 : labels. */
698 705363 : new_stmt = stmt;
699 705363 : record_in_goto_queue (tf, new_stmt, index, true, location);
700 : }
701 :
702 : /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
703 : node, and if so record that fact in the goto queue associated with that
704 : try_finally node. */
705 :
706 : static void
707 14786176 : maybe_record_in_goto_queue (struct leh_state *state, gimple *stmt)
708 : {
709 14786176 : struct leh_tf_state *tf = state->tf;
710 14786176 : treemple new_stmt;
711 :
712 14786176 : if (!tf)
713 14786176 : return;
714 :
715 5760122 : switch (gimple_code (stmt))
716 : {
717 3021430 : case GIMPLE_COND:
718 3021430 : {
719 3021430 : gcond *cond_stmt = as_a <gcond *> (stmt);
720 3021430 : new_stmt.tp = gimple_op_ptr (cond_stmt, 2);
721 3021430 : record_in_goto_queue_label (tf, new_stmt,
722 : gimple_cond_true_label (cond_stmt),
723 3021430 : EXPR_LOCATION (*new_stmt.tp));
724 3021430 : new_stmt.tp = gimple_op_ptr (cond_stmt, 3);
725 0 : record_in_goto_queue_label (tf, new_stmt,
726 : gimple_cond_false_label (cond_stmt),
727 3021430 : EXPR_LOCATION (*new_stmt.tp));
728 : }
729 3021430 : break;
730 :
731 2722102 : case GIMPLE_GOTO:
732 2722102 : new_stmt.g = stmt;
733 2722102 : record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt),
734 : gimple_location (stmt));
735 2722102 : break;
736 :
737 16590 : case GIMPLE_ASM:
738 16590 : if (int n = gimple_asm_nlabels (as_a <gasm *> (stmt)))
739 : {
740 164 : new_stmt.g = stmt;
741 : gasm *asm_stmt = as_a <gasm *> (stmt);
742 164 : for (int i = 0; i < n; ++i)
743 : {
744 89 : tree elt = gimple_asm_label_op (asm_stmt, i);
745 89 : new_stmt.tp = &TREE_VALUE (elt);
746 89 : record_in_goto_queue_label (tf, new_stmt, TREE_VALUE (elt),
747 : gimple_location (stmt));
748 : }
749 : }
750 : break;
751 :
752 0 : case GIMPLE_RETURN:
753 0 : tf->may_return = true;
754 0 : new_stmt.g = stmt;
755 0 : record_in_goto_queue (tf, new_stmt, -1, false, gimple_location (stmt));
756 0 : break;
757 :
758 0 : default:
759 0 : gcc_unreachable ();
760 : }
761 : }
762 :
763 :
764 : #if CHECKING_P
765 : /* We do not process GIMPLE_SWITCHes for now. As long as the original source
766 : was in fact structured, and we've not yet done jump threading, then none
767 : of the labels will leave outer GIMPLE_TRY_FINALLY nodes. Verify this. */
768 :
769 : static void
770 50176 : verify_norecord_switch_expr (struct leh_state *state,
771 : gswitch *switch_expr)
772 : {
773 50176 : struct leh_tf_state *tf = state->tf;
774 50176 : size_t i, n;
775 :
776 50176 : if (!tf)
777 : return;
778 :
779 29977 : n = gimple_switch_num_labels (switch_expr);
780 :
781 247065 : for (i = 0; i < n; ++i)
782 : {
783 217088 : treemple temp;
784 217088 : tree lab = CASE_LABEL (gimple_switch_label (switch_expr, i));
785 217088 : temp.t = lab;
786 217088 : gcc_assert (!outside_finally_tree (temp, tf->try_finally_expr));
787 : }
788 : }
789 : #else
790 : #define verify_norecord_switch_expr(state, switch_expr)
791 : #endif
792 :
793 : /* Redirect a RETURN_EXPR pointed to by Q to FINLAB. If MOD is
794 : non-null, insert it before the new branch. */
795 :
796 : static void
797 0 : do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod)
798 : {
799 0 : gimple *x;
800 :
801 : /* In the case of a return, the queue node must be a gimple statement. */
802 0 : gcc_assert (!q->is_label);
803 :
804 : /* Note that the return value may have already been computed, e.g.,
805 :
806 : int x;
807 : int foo (void)
808 : {
809 : x = 0;
810 : try {
811 : return x;
812 : } finally {
813 : x++;
814 : }
815 : }
816 :
817 : should return 0, not 1. We don't have to do anything to make
818 : this happens because the return value has been placed in the
819 : RESULT_DECL already. */
820 :
821 0 : q->cont_stmt = q->stmt.g;
822 :
823 0 : if (mod)
824 0 : gimple_seq_add_seq (&q->repl_stmt, mod);
825 :
826 0 : x = gimple_build_goto (finlab);
827 0 : gimple_set_location (x, q->location);
828 0 : gimple_seq_add_stmt (&q->repl_stmt, x);
829 0 : }
830 :
831 : /* Similar, but easier, for GIMPLE_GOTO. */
832 :
833 : static void
834 705363 : do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
835 : struct leh_tf_state *tf)
836 : {
837 705363 : ggoto *x;
838 :
839 705363 : gcc_assert (q->is_label);
840 :
841 705363 : q->cont_stmt = gimple_build_goto (tf->dest_array[q->index]);
842 :
843 705363 : if (mod)
844 1322 : gimple_seq_add_seq (&q->repl_stmt, mod);
845 :
846 705363 : x = gimple_build_goto (finlab);
847 705363 : gimple_set_location (x, q->location);
848 705363 : gimple_seq_add_stmt (&q->repl_stmt, x);
849 705363 : }
850 :
851 : /* Emit a standard landing pad sequence into SEQ for REGION. */
852 :
853 : static void
854 948533 : emit_post_landing_pad (gimple_seq *seq, eh_region region)
855 : {
856 948533 : eh_landing_pad lp = region->landing_pads;
857 948533 : glabel *x;
858 :
859 948533 : if (lp == NULL)
860 0 : lp = gen_eh_landing_pad (region);
861 :
862 948533 : lp->post_landing_pad = create_artificial_label (UNKNOWN_LOCATION);
863 948533 : EH_LANDING_PAD_NR (lp->post_landing_pad) = lp->index;
864 :
865 948533 : x = gimple_build_label (lp->post_landing_pad);
866 948533 : gimple_seq_add_stmt (seq, x);
867 948533 : }
868 :
869 : /* Emit a RESX statement into SEQ for REGION. */
870 :
871 : static void
872 948531 : emit_resx (gimple_seq *seq, eh_region region)
873 : {
874 948531 : gresx *x = gimple_build_resx (region->index);
875 948531 : gimple_seq_add_stmt (seq, x);
876 948531 : if (region->outer)
877 559965 : record_stmt_eh_region (region->outer, x);
878 948531 : }
879 :
880 : /* Note that the current EH region may contain a throw, or a
881 : call to a function which itself may contain a throw. */
882 :
883 : static void
884 2760251 : note_eh_region_may_contain_throw (eh_region region)
885 : {
886 3320216 : while (bitmap_set_bit (eh_region_may_contain_throw_map, region->index))
887 : {
888 1026980 : if (region->type == ERT_MUST_NOT_THROW)
889 : break;
890 948533 : region = region->outer;
891 948533 : if (region == NULL)
892 : break;
893 : }
894 2760251 : }
895 :
896 : /* Check if REGION has been marked as containing a throw. If REGION is
897 : NULL, this predicate is false. */
898 :
899 : static inline bool
900 1364170 : eh_region_may_contain_throw (eh_region r)
901 : {
902 1364170 : return r && bitmap_bit_p (eh_region_may_contain_throw_map, r->index);
903 : }
904 :
905 : /* We want to transform
906 : try { body; } catch { stuff; }
907 : to
908 : normal_sequence:
909 : body;
910 : over:
911 : eh_sequence:
912 : landing_pad:
913 : stuff;
914 : goto over;
915 :
916 : TP is a GIMPLE_TRY node. REGION is the region whose post_landing_pad
917 : should be placed before the second operand, or NULL. OVER is
918 : an existing label that should be put at the exit, or NULL. */
919 :
920 : static gimple_seq
921 42785 : frob_into_branch_around (gtry *tp, eh_region region, tree over)
922 : {
923 42785 : gimple *x;
924 42785 : gimple_seq cleanup, result;
925 42785 : location_t loc = gimple_location (tp);
926 :
927 42785 : cleanup = gimple_try_cleanup (tp);
928 42785 : result = gimple_try_eval (tp);
929 :
930 42785 : if (region)
931 42785 : emit_post_landing_pad (&eh_seq, region);
932 :
933 42785 : if (gimple_seq_may_fallthru (cleanup))
934 : {
935 0 : if (!over)
936 0 : over = create_artificial_label (loc);
937 0 : x = gimple_build_goto (over);
938 0 : gimple_set_location (x, loc);
939 0 : gimple_seq_add_stmt (&cleanup, x);
940 : }
941 42785 : gimple_seq_add_seq (&eh_seq, cleanup);
942 :
943 42785 : if (over)
944 : {
945 14053 : x = gimple_build_label (over);
946 14053 : gimple_seq_add_stmt (&result, x);
947 : }
948 42785 : return result;
949 : }
950 :
951 : /* A subroutine of lower_try_finally. Duplicate the tree rooted at T.
952 : Make sure to record all new labels found. */
953 :
954 : static gimple_seq
955 1108509 : lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state,
956 : location_t loc)
957 : {
958 1108509 : gtry *region = NULL;
959 1108509 : gimple_seq new_seq;
960 1108509 : gimple_stmt_iterator gsi;
961 :
962 1108509 : new_seq = copy_gimple_seq_and_replace_locals (seq);
963 :
964 3763532 : for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
965 : {
966 1546514 : gimple *stmt = gsi_stmt (gsi);
967 1546514 : if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
968 : {
969 990536 : tree block = gimple_block (stmt);
970 990536 : gimple_set_location (stmt, loc);
971 990536 : gimple_set_block (stmt, block);
972 : }
973 : }
974 :
975 1108509 : if (outer_state->tf)
976 615027 : region = outer_state->tf->try_finally_expr;
977 1108509 : collect_finally_tree_1 (new_seq, region);
978 :
979 1108509 : return new_seq;
980 : }
981 :
982 : /* A subroutine of lower_try_finally. Create a fallthru label for
983 : the given try_finally state. The only tricky bit here is that
984 : we have to make sure to record the label in our outer context. */
985 :
986 : static tree
987 115590 : lower_try_finally_fallthru_label (struct leh_tf_state *tf)
988 : {
989 115590 : tree label = tf->fallthru_label;
990 115590 : treemple temp;
991 :
992 115590 : if (!label)
993 : {
994 115590 : label = create_artificial_label (gimple_location (tf->try_finally_expr));
995 115590 : tf->fallthru_label = label;
996 115590 : if (tf->outer->tf)
997 : {
998 55439 : temp.t = label;
999 55439 : record_in_finally_tree (temp, tf->outer->tf->try_finally_expr);
1000 : }
1001 : }
1002 115590 : return label;
1003 : }
1004 :
1005 : /* A subroutine of lower_try_finally. If FINALLY consists of a
1006 : GIMPLE_EH_ELSE node, return it. */
1007 :
1008 : static inline geh_else *
1009 2837739 : get_eh_else (gimple_seq finally)
1010 : {
1011 2837739 : gimple *x = gimple_seq_first_stmt (finally);
1012 2837739 : if (x && gimple_code (x) == GIMPLE_EH_ELSE)
1013 : {
1014 840 : gcc_assert (gimple_seq_singleton_p (finally));
1015 840 : return as_a <geh_else *> (x);
1016 : }
1017 : return NULL;
1018 : }
1019 :
1020 : /* A subroutine of lower_try_finally. If the eh_protect_cleanup_actions
1021 : langhook returns non-null, then the language requires that the exception
1022 : path out of a try_finally be treated specially. To wit: the code within
1023 : the finally block may not itself throw an exception. We have two choices
1024 : here. First we can duplicate the finally block and wrap it in a
1025 : must_not_throw region. Second, we can generate code like
1026 :
1027 : try {
1028 : finally_block;
1029 : } catch {
1030 : if (fintmp == eh_edge)
1031 : protect_cleanup_actions;
1032 : }
1033 :
1034 : where "fintmp" is the temporary used in the switch statement generation
1035 : alternative considered below. For the nonce, we always choose the first
1036 : option.
1037 :
1038 : THIS_STATE may be null if this is a try-cleanup, not a try-finally. */
1039 :
1040 : static void
1041 905748 : honor_protect_cleanup_actions (struct leh_state *outer_state,
1042 : struct leh_state *this_state,
1043 : struct leh_tf_state *tf)
1044 : {
1045 905748 : gimple_seq finally = gimple_try_cleanup (tf->top_p);
1046 :
1047 : /* EH_ELSE doesn't come from user code; only compiler generated stuff.
1048 : It does need to be handled here, so as to separate the (different)
1049 : EH path from the normal path. But we should not attempt to wrap
1050 : it with a must-not-throw node (which indeed gets in the way). */
1051 905748 : if (geh_else *eh_else = get_eh_else (finally))
1052 : {
1053 311 : gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
1054 311 : finally = gimple_eh_else_e_body (eh_else);
1055 :
1056 : /* Let the ELSE see the exception that's being processed, but
1057 : since the cleanup is outside the try block, process it with
1058 : outer_state, otherwise it may be used as a cleanup for
1059 : itself, and Bad Things (TM) ensue. */
1060 311 : eh_region save_ehp = outer_state->ehp_region;
1061 311 : outer_state->ehp_region = this_state->cur_region;
1062 311 : lower_eh_constructs_1 (outer_state, &finally);
1063 311 : outer_state->ehp_region = save_ehp;
1064 : }
1065 : else
1066 : {
1067 : /* First check for nothing to do. */
1068 905437 : if (lang_hooks.eh_protect_cleanup_actions == NULL)
1069 181795 : return;
1070 723642 : tree actions = lang_hooks.eh_protect_cleanup_actions ();
1071 723642 : if (actions == NULL)
1072 : return;
1073 :
1074 723642 : if (this_state)
1075 663818 : finally = lower_try_finally_dup_block (finally, outer_state,
1076 663818 : gimple_location (tf->try_finally_expr));
1077 :
1078 : /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
1079 : set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
1080 : to be in an enclosing scope, but needs to be implemented at this level
1081 : to avoid a nesting violation (see wrap_temporary_cleanups in
1082 : cp/decl.cc). Since it's logically at an outer level, we should call
1083 : terminate before we get to it, so strip it away before adding the
1084 : MUST_NOT_THROW filter. */
1085 723642 : gimple_stmt_iterator gsi = gsi_start (finally);
1086 723642 : gimple *x = !gsi_end_p (gsi) ? gsi_stmt (gsi) : NULL;
1087 723626 : if (x
1088 723626 : && gimple_code (x) == GIMPLE_TRY
1089 6143 : && gimple_try_kind (x) == GIMPLE_TRY_CATCH
1090 6143 : && gimple_try_catch_is_cleanup (x))
1091 : {
1092 69 : gsi_insert_seq_before (&gsi, gimple_try_eval (x), GSI_SAME_STMT);
1093 69 : gsi_remove (&gsi, false);
1094 : }
1095 :
1096 : /* Wrap the block with protect_cleanup_actions as the action. */
1097 723642 : geh_mnt *eh_mnt = gimple_build_eh_must_not_throw (actions);
1098 723642 : gtry *try_stmt = gimple_build_try (finally,
1099 : gimple_seq_alloc_with_stmt (eh_mnt),
1100 : GIMPLE_TRY_CATCH);
1101 723642 : finally = lower_eh_must_not_throw (outer_state, try_stmt);
1102 : }
1103 :
1104 : /* Drop all of this into the exception sequence. */
1105 723953 : emit_post_landing_pad (&eh_seq, tf->region);
1106 723953 : gimple_seq_add_seq (&eh_seq, finally);
1107 723953 : if (gimple_seq_may_fallthru (finally))
1108 723953 : emit_resx (&eh_seq, tf->region);
1109 :
1110 : /* Having now been handled, EH isn't to be considered with
1111 : the rest of the outgoing edges. */
1112 723953 : tf->may_throw = false;
1113 : }
1114 :
1115 : /* A subroutine of lower_try_finally. We have determined that there is
1116 : no fallthru edge out of the finally block. This means that there is
1117 : no outgoing edge corresponding to any incoming edge. Restructure the
1118 : try_finally node for this special case. */
1119 :
1120 : static void
1121 2 : lower_try_finally_nofallthru (struct leh_state *state,
1122 : struct leh_tf_state *tf)
1123 : {
1124 2 : tree lab;
1125 2 : gimple *x;
1126 2 : geh_else *eh_else;
1127 2 : gimple_seq finally;
1128 2 : struct goto_queue_node *q, *qe;
1129 :
1130 2 : lab = create_artificial_label (gimple_location (tf->try_finally_expr));
1131 :
1132 : /* We expect that tf->top_p is a GIMPLE_TRY. */
1133 2 : finally = gimple_try_cleanup (tf->top_p);
1134 2 : tf->top_p_seq = gimple_try_eval (tf->top_p);
1135 :
1136 2 : x = gimple_build_label (lab);
1137 2 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1138 :
1139 2 : q = tf->goto_queue;
1140 2 : qe = q + tf->goto_queue_active;
1141 2 : for (; q < qe; ++q)
1142 0 : if (q->index < 0)
1143 0 : do_return_redirection (q, lab, NULL);
1144 : else
1145 0 : do_goto_redirection (q, lab, NULL, tf);
1146 :
1147 2 : replace_goto_queue (tf);
1148 :
1149 : /* Emit the finally block into the stream. Lower EH_ELSE at this time. */
1150 2 : eh_else = get_eh_else (finally);
1151 2 : if (eh_else)
1152 : {
1153 0 : finally = gimple_eh_else_n_body (eh_else);
1154 0 : lower_eh_constructs_1 (state, &finally);
1155 0 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1156 :
1157 0 : if (tf->may_throw)
1158 : {
1159 0 : finally = gimple_eh_else_e_body (eh_else);
1160 0 : lower_eh_constructs_1 (state, &finally);
1161 :
1162 0 : emit_post_landing_pad (&eh_seq, tf->region);
1163 0 : gimple_seq_add_seq (&eh_seq, finally);
1164 : }
1165 : }
1166 : else
1167 : {
1168 2 : lower_eh_constructs_1 (state, &finally);
1169 2 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1170 :
1171 2 : if (tf->may_throw)
1172 : {
1173 2 : emit_post_landing_pad (&eh_seq, tf->region);
1174 :
1175 2 : x = gimple_build_goto (lab);
1176 2 : gimple_set_location (x, gimple_location (tf->try_finally_expr));
1177 2 : gimple_seq_add_stmt (&eh_seq, x);
1178 : }
1179 : }
1180 2 : }
1181 :
1182 : /* A subroutine of lower_try_finally. We have determined that there is
1183 : exactly one destination of the finally block. Restructure the
1184 : try_finally node for this special case. */
1185 :
1186 : static void
1187 1510517 : lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
1188 : {
1189 1510517 : struct goto_queue_node *q, *qe;
1190 1510517 : geh_else *eh_else;
1191 1510517 : glabel *label_stmt;
1192 1510517 : gimple *x;
1193 1510517 : gimple_seq finally;
1194 1510517 : gimple_stmt_iterator gsi;
1195 1510517 : tree finally_label;
1196 1510517 : location_t loc = gimple_location (tf->try_finally_expr);
1197 :
1198 1510517 : finally = gimple_try_cleanup (tf->top_p);
1199 1510517 : tf->top_p_seq = gimple_try_eval (tf->top_p);
1200 :
1201 : /* Since there's only one destination, and the destination edge can only
1202 : either be EH or non-EH, that implies that all of our incoming edges
1203 : are of the same type. Therefore we can lower EH_ELSE immediately. */
1204 1510517 : eh_else = get_eh_else (finally);
1205 1510517 : if (eh_else)
1206 : {
1207 497 : if (tf->may_throw)
1208 0 : finally = gimple_eh_else_e_body (eh_else);
1209 : else
1210 497 : finally = gimple_eh_else_n_body (eh_else);
1211 : }
1212 :
1213 1510517 : lower_eh_constructs_1 (state, &finally);
1214 :
1215 3791395 : for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
1216 : {
1217 2280878 : gimple *stmt = gsi_stmt (gsi);
1218 2280878 : if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
1219 : {
1220 1156691 : tree block = gimple_block (stmt);
1221 1156691 : gimple_set_location (stmt, gimple_location (tf->try_finally_expr));
1222 1156691 : gimple_set_block (stmt, block);
1223 : }
1224 : }
1225 :
1226 1510517 : if (tf->may_throw)
1227 : {
1228 : /* Only reachable via the exception edge. Add the given label to
1229 : the head of the FINALLY block. Append a RESX at the end. */
1230 1128 : emit_post_landing_pad (&eh_seq, tf->region);
1231 1128 : gimple_seq_add_seq (&eh_seq, finally);
1232 1128 : emit_resx (&eh_seq, tf->region);
1233 1129634 : return;
1234 : }
1235 :
1236 1509389 : if (tf->may_fallthru)
1237 : {
1238 : /* Only reachable via the fallthru edge. Do nothing but let
1239 : the two blocks run together; we'll fall out the bottom. */
1240 1127378 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1241 1127378 : return;
1242 : }
1243 :
1244 382011 : finally_label = create_artificial_label (loc);
1245 382011 : label_stmt = gimple_build_label (finally_label);
1246 382011 : gimple_seq_add_stmt (&tf->top_p_seq, label_stmt);
1247 :
1248 382011 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1249 :
1250 382011 : q = tf->goto_queue;
1251 382011 : qe = q + tf->goto_queue_active;
1252 :
1253 382011 : if (tf->may_return)
1254 : {
1255 : /* Reachable by return expressions only. Redirect them. */
1256 0 : for (; q < qe; ++q)
1257 0 : do_return_redirection (q, finally_label, NULL);
1258 0 : replace_goto_queue (tf);
1259 : }
1260 : else
1261 : {
1262 : /* Reachable by goto expressions only. Redirect them. */
1263 830197 : for (; q < qe; ++q)
1264 448186 : do_goto_redirection (q, finally_label, NULL, tf);
1265 382011 : replace_goto_queue (tf);
1266 :
1267 382011 : if (tf->dest_array[0] == tf->fallthru_label)
1268 : {
1269 : /* Reachable by goto to fallthru label only. Redirect it
1270 : to the new label (already created, sadly), and do not
1271 : emit the final branch out, or the fallthru label. */
1272 0 : tf->fallthru_label = NULL;
1273 0 : return;
1274 : }
1275 : }
1276 :
1277 : /* Place the original return/goto to the original destination
1278 : immediately after the finally block. */
1279 382011 : x = tf->goto_queue[0].cont_stmt;
1280 382011 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1281 382011 : maybe_record_in_goto_queue (state, x);
1282 : }
1283 :
1284 : /* A subroutine of lower_try_finally. There are multiple edges incoming
1285 : and outgoing from the finally block. Implement this by duplicating the
1286 : finally block for every destination. */
1287 :
1288 : static void
1289 207127 : lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
1290 : {
1291 207127 : gimple_seq finally;
1292 207127 : gimple_seq new_stmt;
1293 207127 : gimple_seq seq;
1294 207127 : gimple *x;
1295 207127 : geh_else *eh_else;
1296 207127 : tree tmp;
1297 207127 : location_t tf_loc = gimple_location (tf->try_finally_expr);
1298 :
1299 207127 : finally = gimple_try_cleanup (tf->top_p);
1300 :
1301 : /* Notice EH_ELSE, and simplify some of the remaining code
1302 : by considering FINALLY to be the normal return path only. */
1303 207127 : eh_else = get_eh_else (finally);
1304 207127 : if (eh_else)
1305 6 : finally = gimple_eh_else_n_body (eh_else);
1306 :
1307 207127 : tf->top_p_seq = gimple_try_eval (tf->top_p);
1308 207127 : new_stmt = NULL;
1309 :
1310 207127 : if (tf->may_fallthru)
1311 : {
1312 112180 : seq = lower_try_finally_dup_block (finally, state, tf_loc);
1313 112180 : lower_eh_constructs_1 (state, &seq);
1314 112180 : gimple_seq_add_seq (&new_stmt, seq);
1315 :
1316 112180 : tmp = lower_try_finally_fallthru_label (tf);
1317 112180 : x = gimple_build_goto (tmp);
1318 112180 : gimple_set_location (x, tf_loc);
1319 112180 : gimple_seq_add_stmt (&new_stmt, x);
1320 : }
1321 :
1322 207127 : if (tf->may_throw)
1323 : {
1324 : /* We don't need to copy the EH path of EH_ELSE,
1325 : since it is only emitted once. */
1326 177817 : if (eh_else)
1327 0 : seq = gimple_eh_else_e_body (eh_else);
1328 : else
1329 177817 : seq = lower_try_finally_dup_block (finally, state, tf_loc);
1330 177817 : lower_eh_constructs_1 (state, &seq);
1331 :
1332 177817 : emit_post_landing_pad (&eh_seq, tf->region);
1333 177817 : gimple_seq_add_seq (&eh_seq, seq);
1334 177817 : emit_resx (&eh_seq, tf->region);
1335 : }
1336 :
1337 207127 : if (tf->goto_queue)
1338 : {
1339 150708 : struct goto_queue_node *q, *qe;
1340 150708 : int return_index, index;
1341 150708 : struct labels_s
1342 : {
1343 : struct goto_queue_node *q;
1344 : tree label;
1345 : } *labels;
1346 :
1347 150708 : return_index = tf->dest_array.length ();
1348 150708 : labels = XCNEWVEC (struct labels_s, return_index + 1);
1349 :
1350 150708 : q = tf->goto_queue;
1351 150708 : qe = q + tf->goto_queue_active;
1352 406563 : for (; q < qe; q++)
1353 : {
1354 255855 : index = q->index < 0 ? return_index : q->index;
1355 :
1356 255855 : if (!labels[index].q)
1357 154694 : labels[index].q = q;
1358 : }
1359 :
1360 456110 : for (index = 0; index < return_index + 1; index++)
1361 : {
1362 305402 : tree lab;
1363 :
1364 305402 : q = labels[index].q;
1365 305402 : if (! q)
1366 150708 : continue;
1367 :
1368 309388 : lab = labels[index].label
1369 154694 : = create_artificial_label (tf_loc);
1370 :
1371 154694 : if (index == return_index)
1372 0 : do_return_redirection (q, lab, NULL);
1373 : else
1374 154694 : do_goto_redirection (q, lab, NULL, tf);
1375 :
1376 154694 : x = gimple_build_label (lab);
1377 154694 : gimple_seq_add_stmt (&new_stmt, x);
1378 :
1379 154694 : seq = lower_try_finally_dup_block (finally, state, q->location);
1380 154694 : lower_eh_constructs_1 (state, &seq);
1381 154694 : gimple_seq_add_seq (&new_stmt, seq);
1382 :
1383 154694 : gimple_seq_add_stmt (&new_stmt, q->cont_stmt);
1384 154694 : maybe_record_in_goto_queue (state, q->cont_stmt);
1385 : }
1386 :
1387 406563 : for (q = tf->goto_queue; q < qe; q++)
1388 : {
1389 255855 : tree lab;
1390 :
1391 255855 : index = q->index < 0 ? return_index : q->index;
1392 :
1393 255855 : if (labels[index].q == q)
1394 154694 : continue;
1395 :
1396 101161 : lab = labels[index].label;
1397 :
1398 101161 : if (index == return_index)
1399 0 : do_return_redirection (q, lab, NULL);
1400 : else
1401 101161 : do_goto_redirection (q, lab, NULL, tf);
1402 : }
1403 :
1404 150708 : replace_goto_queue (tf);
1405 150708 : free (labels);
1406 : }
1407 :
1408 : /* Need to link new stmts after running replace_goto_queue due
1409 : to not wanting to process the same goto stmts twice. */
1410 207127 : gimple_seq_add_seq (&tf->top_p_seq, new_stmt);
1411 207127 : }
1412 :
1413 : /* A subroutine of lower_try_finally. There are multiple edges incoming
1414 : and outgoing from the finally block. Implement this by instrumenting
1415 : each incoming edge and creating a switch statement at the end of the
1416 : finally block that branches to the appropriate destination. */
1417 :
1418 : static void
1419 3609 : lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
1420 : {
1421 3609 : struct goto_queue_node *q, *qe;
1422 3609 : tree finally_tmp, finally_label;
1423 3609 : int return_index, eh_index, fallthru_index;
1424 3609 : int nlabels, ndests, j, last_case_index;
1425 3609 : tree last_case;
1426 3609 : auto_vec<tree> case_label_vec;
1427 3609 : gimple_seq switch_body = NULL;
1428 3609 : gimple *x;
1429 3609 : geh_else *eh_else;
1430 3609 : tree tmp;
1431 3609 : gimple *switch_stmt;
1432 3609 : gimple_seq finally;
1433 3609 : hash_map<tree, gimple *> *cont_map = NULL;
1434 : /* The location of the TRY_FINALLY stmt. */
1435 3609 : location_t tf_loc = gimple_location (tf->try_finally_expr);
1436 : /* The location of the finally block. */
1437 3609 : location_t finally_loc;
1438 :
1439 3609 : finally = gimple_try_cleanup (tf->top_p);
1440 3609 : eh_else = get_eh_else (finally);
1441 :
1442 : /* Mash the TRY block to the head of the chain. */
1443 3609 : tf->top_p_seq = gimple_try_eval (tf->top_p);
1444 :
1445 : /* The location of the finally is either the last stmt in the finally
1446 : block or the location of the TRY_FINALLY itself. */
1447 3609 : x = gimple_seq_last_stmt (finally);
1448 3609 : finally_loc = x ? gimple_location (x) : tf_loc;
1449 :
1450 : /* Prepare for switch statement generation. */
1451 3609 : nlabels = tf->dest_array.length ();
1452 3609 : return_index = nlabels;
1453 3609 : eh_index = return_index + tf->may_return;
1454 3609 : fallthru_index = eh_index + (tf->may_throw && !eh_else);
1455 3609 : ndests = fallthru_index + tf->may_fallthru;
1456 :
1457 3609 : finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
1458 3609 : finally_label = create_artificial_label (finally_loc);
1459 :
1460 : /* We use vec::quick_push on case_label_vec throughout this function,
1461 : since we know the size in advance and allocate precisely as muce
1462 : space as needed. */
1463 3609 : case_label_vec.create (ndests);
1464 3609 : last_case = NULL;
1465 3609 : last_case_index = 0;
1466 :
1467 : /* Begin inserting code for getting to the finally block. Things
1468 : are done in this order to correspond to the sequence the code is
1469 : laid out. */
1470 :
1471 3609 : if (tf->may_fallthru)
1472 : {
1473 3410 : x = gimple_build_assign (finally_tmp,
1474 : build_int_cst (integer_type_node,
1475 3410 : fallthru_index));
1476 3410 : gimple_set_location (x, finally_loc);
1477 3410 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1478 :
1479 3410 : tmp = build_int_cst (integer_type_node, fallthru_index);
1480 3410 : last_case = build_case_label (tmp, NULL,
1481 : create_artificial_label (finally_loc));
1482 3410 : case_label_vec.quick_push (last_case);
1483 3410 : last_case_index++;
1484 :
1485 3410 : x = gimple_build_label (CASE_LABEL (last_case));
1486 3410 : gimple_seq_add_stmt (&switch_body, x);
1487 :
1488 3410 : tmp = lower_try_finally_fallthru_label (tf);
1489 3410 : x = gimple_build_goto (tmp);
1490 3410 : gimple_set_location (x, finally_loc);
1491 3410 : gimple_seq_add_stmt (&switch_body, x);
1492 : }
1493 :
1494 : /* For EH_ELSE, emit the exception path (plus resx) now, then
1495 : subsequently we only need consider the normal path. */
1496 3609 : if (eh_else)
1497 : {
1498 10 : if (tf->may_throw)
1499 : {
1500 0 : finally = gimple_eh_else_e_body (eh_else);
1501 0 : lower_eh_constructs_1 (state, &finally);
1502 :
1503 0 : emit_post_landing_pad (&eh_seq, tf->region);
1504 0 : gimple_seq_add_seq (&eh_seq, finally);
1505 0 : emit_resx (&eh_seq, tf->region);
1506 : }
1507 :
1508 10 : finally = gimple_eh_else_n_body (eh_else);
1509 : }
1510 3599 : else if (tf->may_throw)
1511 : {
1512 2848 : emit_post_landing_pad (&eh_seq, tf->region);
1513 :
1514 2848 : x = gimple_build_assign (finally_tmp,
1515 2848 : build_int_cst (integer_type_node, eh_index));
1516 2848 : gimple_seq_add_stmt (&eh_seq, x);
1517 :
1518 2848 : x = gimple_build_goto (finally_label);
1519 2848 : gimple_set_location (x, tf_loc);
1520 2848 : gimple_seq_add_stmt (&eh_seq, x);
1521 :
1522 2848 : tmp = build_int_cst (integer_type_node, eh_index);
1523 2848 : last_case = build_case_label (tmp, NULL,
1524 : create_artificial_label (tf_loc));
1525 2848 : case_label_vec.quick_push (last_case);
1526 2848 : last_case_index++;
1527 :
1528 2848 : x = gimple_build_label (CASE_LABEL (last_case));
1529 2848 : gimple_seq_add_stmt (&eh_seq, x);
1530 2848 : emit_resx (&eh_seq, tf->region);
1531 : }
1532 :
1533 3609 : x = gimple_build_label (finally_label);
1534 3609 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1535 :
1536 3609 : lower_eh_constructs_1 (state, &finally);
1537 3609 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1538 :
1539 : /* Redirect each incoming goto edge. */
1540 3609 : q = tf->goto_queue;
1541 3609 : qe = q + tf->goto_queue_active;
1542 3609 : j = last_case_index + tf->may_return;
1543 : /* Prepare the assignments to finally_tmp that are executed upon the
1544 : entrance through a particular edge. */
1545 4931 : for (; q < qe; ++q)
1546 : {
1547 1322 : gimple_seq mod = NULL;
1548 1322 : int switch_id;
1549 1322 : unsigned int case_index;
1550 :
1551 1322 : if (q->index < 0)
1552 : {
1553 0 : x = gimple_build_assign (finally_tmp,
1554 : build_int_cst (integer_type_node,
1555 0 : return_index));
1556 0 : gimple_seq_add_stmt (&mod, x);
1557 0 : do_return_redirection (q, finally_label, mod);
1558 0 : switch_id = return_index;
1559 : }
1560 : else
1561 : {
1562 1322 : x = gimple_build_assign (finally_tmp,
1563 1322 : build_int_cst (integer_type_node, q->index));
1564 1322 : gimple_seq_add_stmt (&mod, x);
1565 1322 : do_goto_redirection (q, finally_label, mod, tf);
1566 1322 : switch_id = q->index;
1567 : }
1568 :
1569 1322 : case_index = j + q->index;
1570 1527 : if (case_label_vec.length () <= case_index || !case_label_vec[case_index])
1571 : {
1572 1117 : tree case_lab;
1573 1117 : tmp = build_int_cst (integer_type_node, switch_id);
1574 1117 : case_lab = build_case_label (tmp, NULL,
1575 : create_artificial_label (tf_loc));
1576 : /* We store the cont_stmt in the pointer map, so that we can recover
1577 : it in the loop below. */
1578 1117 : if (!cont_map)
1579 843 : cont_map = new hash_map<tree, gimple *>;
1580 1117 : cont_map->put (case_lab, q->cont_stmt);
1581 1117 : case_label_vec.quick_push (case_lab);
1582 : }
1583 : }
1584 4726 : for (j = last_case_index; j < last_case_index + nlabels; j++)
1585 : {
1586 1117 : gimple *cont_stmt;
1587 :
1588 1117 : last_case = case_label_vec[j];
1589 :
1590 1117 : gcc_assert (last_case);
1591 1117 : gcc_assert (cont_map);
1592 :
1593 1117 : cont_stmt = *cont_map->get (last_case);
1594 :
1595 1117 : x = gimple_build_label (CASE_LABEL (last_case));
1596 1117 : gimple_seq_add_stmt (&switch_body, x);
1597 1117 : gimple_seq_add_stmt (&switch_body, cont_stmt);
1598 1117 : maybe_record_in_goto_queue (state, cont_stmt);
1599 : }
1600 3609 : if (cont_map)
1601 843 : delete cont_map;
1602 :
1603 3609 : replace_goto_queue (tf);
1604 :
1605 : /* Make sure that the last case is the default label, as one is required.
1606 : Then sort the labels, which is also required in GIMPLE. */
1607 3609 : CASE_LOW (last_case) = NULL;
1608 3609 : tree tem = case_label_vec.pop ();
1609 3609 : gcc_assert (tem == last_case);
1610 3609 : sort_case_labels (case_label_vec);
1611 :
1612 : /* Build the switch statement, setting last_case to be the default
1613 : label. */
1614 3609 : switch_stmt = gimple_build_switch (finally_tmp, last_case,
1615 : case_label_vec);
1616 3609 : gimple_set_location (switch_stmt, finally_loc);
1617 :
1618 : /* Need to link SWITCH_STMT after running replace_goto_queue
1619 : due to not wanting to process the same goto stmts twice. */
1620 3609 : gimple_seq_add_stmt (&tf->top_p_seq, switch_stmt);
1621 3609 : gimple_seq_add_seq (&tf->top_p_seq, switch_body);
1622 3609 : }
1623 :
1624 : /* Decide whether or not we are going to duplicate the finally block.
1625 : There are several considerations.
1626 :
1627 : Second, we'd like to prevent egregious code growth. One way to
1628 : do this is to estimate the size of the finally block, multiply
1629 : that by the number of copies we'd need to make, and compare against
1630 : the estimate of the size of the switch machinery we'd have to add. */
1631 :
1632 : static bool
1633 210736 : decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
1634 : {
1635 210736 : int f_estimate, sw_estimate;
1636 210736 : geh_else *eh_else;
1637 :
1638 : /* If there's an EH_ELSE involved, the exception path is separate
1639 : and really doesn't come into play for this computation. */
1640 210736 : eh_else = get_eh_else (finally);
1641 210736 : if (eh_else)
1642 : {
1643 16 : ndests -= may_throw;
1644 16 : finally = gimple_eh_else_n_body (eh_else);
1645 : }
1646 :
1647 210736 : if (!optimize)
1648 : {
1649 17250 : gimple_stmt_iterator gsi;
1650 :
1651 17250 : if (ndests == 1)
1652 : return true;
1653 :
1654 44402 : for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
1655 : {
1656 : /* Duplicate __builtin_stack_restore in the hope of eliminating it
1657 : on the EH paths and, consequently, useless cleanups. */
1658 30740 : gimple *stmt = gsi_stmt (gsi);
1659 30740 : if (!is_gimple_debug (stmt)
1660 30740 : && !gimple_clobber_p (stmt)
1661 34445 : && !gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
1662 : return false;
1663 : }
1664 : return true;
1665 : }
1666 :
1667 : /* Finally estimate N times, plus N gotos. */
1668 193486 : f_estimate = estimate_num_insns_seq (finally, &eni_size_weights);
1669 193486 : f_estimate = (f_estimate + 1) * ndests;
1670 :
1671 : /* Switch statement (cost 10), N variable assignments, N gotos. */
1672 193486 : sw_estimate = 10 + 2 * ndests;
1673 :
1674 : /* Optimize for size clearly wants our best guess. */
1675 193486 : if (optimize_function_for_size_p (cfun))
1676 2415 : return f_estimate < sw_estimate;
1677 :
1678 : /* ??? These numbers are completely made up so far. */
1679 191071 : if (optimize > 1)
1680 187471 : return f_estimate < 100 || f_estimate < sw_estimate * 2;
1681 : else
1682 3600 : return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
1683 : }
1684 :
1685 : /* REG is current region of a LEH state.
1686 : is the enclosing region for a possible cleanup region, or the region
1687 : itself. Returns TRUE if such a region would be unreachable.
1688 :
1689 : Cleanup regions within a must-not-throw region aren't actually reachable
1690 : even if there are throwing stmts within them, because the personality
1691 : routine will call terminate before unwinding. */
1692 :
1693 : static bool
1694 1507193 : cleanup_is_dead_in (leh_state *state)
1695 : {
1696 1507193 : if (flag_checking)
1697 : {
1698 1507181 : eh_region reg = state->cur_region;
1699 27293816 : while (reg && reg->type == ERT_CLEANUP)
1700 25786635 : reg = reg->outer;
1701 :
1702 1507181 : gcc_assert (reg == state->outer_non_cleanup);
1703 : }
1704 :
1705 1507193 : eh_region reg = state->outer_non_cleanup;
1706 1507193 : return (reg && reg->type == ERT_MUST_NOT_THROW);
1707 : }
1708 :
1709 : /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY_FINALLY nodes
1710 : to a sequence of labels and blocks, plus the exception region trees
1711 : that record all the magic. This is complicated by the need to
1712 : arrange for the FINALLY block to be executed on all exits. */
1713 :
1714 : static gimple_seq
1715 1739717 : lower_try_finally (struct leh_state *state, gtry *tp)
1716 : {
1717 1739717 : struct leh_tf_state this_tf;
1718 1739717 : struct leh_state this_state;
1719 1739717 : int ndests;
1720 1739717 : gimple_seq old_eh_seq;
1721 :
1722 : /* Process the try block. */
1723 :
1724 1739717 : memset (&this_tf, 0, sizeof (this_tf));
1725 1739717 : this_tf.try_finally_expr = tp;
1726 1739717 : this_tf.top_p = tp;
1727 1739717 : this_tf.outer = state;
1728 1739717 : if (using_eh_for_cleanups_p () && !cleanup_is_dead_in (state))
1729 : {
1730 1187817 : this_tf.region = gen_eh_region_cleanup (state->cur_region);
1731 1187817 : this_state.cur_region = this_tf.region;
1732 : }
1733 : else
1734 : {
1735 551900 : this_tf.region = NULL;
1736 551900 : this_state.cur_region = state->cur_region;
1737 : }
1738 :
1739 1739717 : this_state.outer_non_cleanup = state->outer_non_cleanup;
1740 1739717 : this_state.ehp_region = state->ehp_region;
1741 1739717 : this_state.tf = &this_tf;
1742 :
1743 1739717 : old_eh_seq = eh_seq;
1744 1739717 : eh_seq = NULL;
1745 :
1746 1739717 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1747 :
1748 : /* Determine if the try block is escaped through the bottom. */
1749 1739717 : this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
1750 :
1751 : /* Determine if any exceptions are possible within the try block. */
1752 1739717 : if (this_tf.region)
1753 1187817 : this_tf.may_throw = eh_region_may_contain_throw (this_tf.region);
1754 1739717 : if (this_tf.may_throw)
1755 845924 : honor_protect_cleanup_actions (state, &this_state, &this_tf);
1756 :
1757 : /* Determine how many edges (still) reach the finally block. Or rather,
1758 : how many destinations are reached by the finally block. Use this to
1759 : determine how we process the finally block itself. */
1760 :
1761 1739717 : ndests = this_tf.dest_array.length ();
1762 1739717 : ndests += this_tf.may_fallthru;
1763 1739717 : ndests += this_tf.may_return;
1764 1739717 : ndests += this_tf.may_throw;
1765 :
1766 : /* If the FINALLY block is not reachable, dike it out. */
1767 1739717 : if (ndests == 0)
1768 : {
1769 18462 : gimple_seq_add_seq (&this_tf.top_p_seq, gimple_try_eval (tp));
1770 18462 : gimple_try_set_cleanup (tp, NULL);
1771 : }
1772 : /* If the finally block doesn't fall through, then any destination
1773 : we might try to impose there isn't reached either. There may be
1774 : some minor amount of cleanup and redirection still needed. */
1775 1721255 : else if (!gimple_seq_may_fallthru (gimple_try_cleanup (tp)))
1776 2 : lower_try_finally_nofallthru (state, &this_tf);
1777 :
1778 : /* We can easily special-case redirection to a single destination. */
1779 1721253 : else if (ndests == 1)
1780 1510517 : lower_try_finally_onedest (state, &this_tf);
1781 210736 : else if (decide_copy_try_finally (ndests, this_tf.may_throw,
1782 : gimple_try_cleanup (tp)))
1783 207127 : lower_try_finally_copy (state, &this_tf);
1784 : else
1785 3609 : lower_try_finally_switch (state, &this_tf);
1786 :
1787 : /* If someone requested we add a label at the end of the transformed
1788 : block, do so. */
1789 1739717 : if (this_tf.fallthru_label)
1790 : {
1791 : /* This must be reached only if ndests == 0. */
1792 115590 : gimple *x = gimple_build_label (this_tf.fallthru_label);
1793 115590 : gimple_seq_add_stmt (&this_tf.top_p_seq, x);
1794 : }
1795 :
1796 1739717 : this_tf.dest_array.release ();
1797 1739717 : free (this_tf.goto_queue);
1798 1739717 : if (this_tf.goto_queue_map)
1799 609 : delete this_tf.goto_queue_map;
1800 :
1801 : /* If there was an old (aka outer) eh_seq, append the current eh_seq.
1802 : If there was no old eh_seq, then the append is trivially already done. */
1803 1739717 : if (old_eh_seq)
1804 : {
1805 155571 : if (eh_seq == NULL)
1806 12649 : eh_seq = old_eh_seq;
1807 : else
1808 : {
1809 142922 : gimple_seq new_eh_seq = eh_seq;
1810 142922 : eh_seq = old_eh_seq;
1811 142922 : gimple_seq_add_seq (&eh_seq, new_eh_seq);
1812 : }
1813 : }
1814 :
1815 1739717 : return this_tf.top_p_seq;
1816 : }
1817 :
1818 : /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY_CATCH with a
1819 : list of GIMPLE_CATCH to a sequence of labels and blocks, plus the
1820 : exception region trees that records all the magic. */
1821 :
1822 : static gimple_seq
1823 47050 : lower_catch (struct leh_state *state, gtry *tp)
1824 : {
1825 47050 : eh_region try_region = NULL;
1826 47050 : struct leh_state this_state = *state;
1827 47050 : gimple_stmt_iterator gsi;
1828 47050 : tree out_label;
1829 47050 : gimple_seq new_seq, cleanup;
1830 47050 : gimple *x;
1831 47050 : geh_dispatch *eh_dispatch;
1832 47050 : location_t try_catch_loc = gimple_location (tp);
1833 47050 : location_t catch_loc = UNKNOWN_LOCATION;
1834 :
1835 47050 : if (flag_exceptions)
1836 : {
1837 47044 : try_region = gen_eh_region_try (state->cur_region);
1838 47044 : this_state.cur_region = try_region;
1839 47044 : this_state.outer_non_cleanup = this_state.cur_region;
1840 : }
1841 :
1842 47050 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1843 :
1844 47050 : if (!eh_region_may_contain_throw (try_region))
1845 4830 : return gimple_try_eval (tp);
1846 :
1847 42220 : new_seq = NULL;
1848 42220 : eh_dispatch = gimple_build_eh_dispatch (try_region->index);
1849 42220 : gimple_seq_add_stmt (&new_seq, eh_dispatch);
1850 42220 : emit_resx (&new_seq, try_region);
1851 :
1852 42220 : this_state.cur_region = state->cur_region;
1853 42220 : this_state.outer_non_cleanup = state->outer_non_cleanup;
1854 42220 : this_state.ehp_region = try_region;
1855 :
1856 : /* Add eh_seq from lowering EH in the cleanup sequence after the cleanup
1857 : itself, so that e.g. for coverage purposes the nested cleanups don't
1858 : appear before the cleanup body. See PR64634 for details. */
1859 42220 : gimple_seq old_eh_seq = eh_seq;
1860 42220 : eh_seq = NULL;
1861 :
1862 42220 : out_label = NULL;
1863 42220 : cleanup = gimple_try_cleanup (tp);
1864 42220 : for (gsi = gsi_start (cleanup);
1865 48737 : !gsi_end_p (gsi);
1866 6517 : gsi_next (&gsi))
1867 : {
1868 45222 : eh_catch c;
1869 45222 : gcatch *catch_stmt;
1870 45222 : gimple_seq handler;
1871 :
1872 45222 : catch_stmt = as_a <gcatch *> (gsi_stmt (gsi));
1873 45222 : if (catch_loc == UNKNOWN_LOCATION)
1874 42220 : catch_loc = gimple_location (catch_stmt);
1875 45222 : c = gen_eh_region_catch (try_region, gimple_catch_types (catch_stmt));
1876 :
1877 45222 : handler = gimple_catch_handler (catch_stmt);
1878 45222 : lower_eh_constructs_1 (&this_state, &handler);
1879 :
1880 45222 : c->label = create_artificial_label (UNKNOWN_LOCATION);
1881 45222 : x = gimple_build_label (c->label);
1882 45222 : gimple_seq_add_stmt (&new_seq, x);
1883 :
1884 45222 : gimple_seq_add_seq (&new_seq, handler);
1885 :
1886 45222 : if (gimple_seq_may_fallthru (new_seq))
1887 : {
1888 14621 : if (!out_label)
1889 14053 : out_label = create_artificial_label (try_catch_loc);
1890 :
1891 14621 : x = gimple_build_goto (out_label);
1892 14621 : gimple_seq_add_stmt (&new_seq, x);
1893 : }
1894 45222 : if (!c->type_list)
1895 : break;
1896 : }
1897 :
1898 : /* Try to set a location on the dispatching construct to avoid inheriting
1899 : the location of the previous statement. */
1900 42220 : gimple_set_location (eh_dispatch, catch_loc);
1901 :
1902 42220 : gimple_try_set_cleanup (tp, new_seq);
1903 :
1904 42220 : gimple_seq new_eh_seq = eh_seq;
1905 42220 : eh_seq = old_eh_seq;
1906 42220 : gimple_seq ret_seq = frob_into_branch_around (tp, try_region, out_label);
1907 42220 : gimple_seq_add_seq (&eh_seq, new_eh_seq);
1908 42220 : return ret_seq;
1909 : }
1910 :
1911 : /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY with a
1912 : GIMPLE_EH_FILTER to a sequence of labels and blocks, plus the exception
1913 : region trees that record all the magic. */
1914 :
1915 : static gimple_seq
1916 5841 : lower_eh_filter (struct leh_state *state, gtry *tp)
1917 : {
1918 5841 : struct leh_state this_state = *state;
1919 5841 : eh_region this_region = NULL;
1920 5841 : gimple *inner, *x;
1921 5841 : gimple_seq new_seq;
1922 :
1923 5841 : inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
1924 :
1925 5841 : if (flag_exceptions)
1926 : {
1927 5841 : this_region = gen_eh_region_allowed (state->cur_region,
1928 : gimple_eh_filter_types (inner));
1929 5841 : this_state.cur_region = this_region;
1930 5841 : this_state.outer_non_cleanup = this_state.cur_region;
1931 : }
1932 :
1933 5841 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1934 :
1935 5841 : if (!eh_region_may_contain_throw (this_region))
1936 5276 : return gimple_try_eval (tp);
1937 :
1938 565 : this_state.cur_region = state->cur_region;
1939 565 : this_state.ehp_region = this_region;
1940 :
1941 565 : new_seq = NULL;
1942 565 : x = gimple_build_eh_dispatch (this_region->index);
1943 565 : gimple_set_location (x, gimple_location (tp));
1944 565 : gimple_seq_add_stmt (&new_seq, x);
1945 565 : emit_resx (&new_seq, this_region);
1946 :
1947 565 : this_region->u.allowed.label = create_artificial_label (UNKNOWN_LOCATION);
1948 565 : x = gimple_build_label (this_region->u.allowed.label);
1949 565 : gimple_seq_add_stmt (&new_seq, x);
1950 :
1951 565 : lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure_ptr (inner));
1952 565 : gimple_seq_add_seq (&new_seq, gimple_eh_filter_failure (inner));
1953 :
1954 565 : gimple_try_set_cleanup (tp, new_seq);
1955 :
1956 565 : return frob_into_branch_around (tp, this_region, NULL);
1957 : }
1958 :
1959 : /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY with
1960 : an GIMPLE_EH_MUST_NOT_THROW to a sequence of labels and blocks,
1961 : plus the exception region trees that record all the magic. */
1962 :
1963 : static gimple_seq
1964 1358711 : lower_eh_must_not_throw (struct leh_state *state, gtry *tp)
1965 : {
1966 1358711 : struct leh_state this_state = *state;
1967 :
1968 1358711 : if (flag_exceptions)
1969 : {
1970 1358711 : gimple *inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
1971 1358711 : eh_region this_region;
1972 :
1973 1358711 : this_region = gen_eh_region_must_not_throw (state->cur_region);
1974 1358711 : this_region->u.must_not_throw.failure_decl
1975 1358711 : = gimple_eh_must_not_throw_fndecl (
1976 1358711 : as_a <geh_mnt *> (inner));
1977 1358711 : this_region->u.must_not_throw.failure_loc
1978 1358711 : = LOCATION_LOCUS (gimple_location (tp));
1979 :
1980 : /* In order to get mangling applied to this decl, we must mark it
1981 : used now. Otherwise, pass_ipa_free_lang_data won't think it
1982 : needs to happen. */
1983 1358711 : TREE_USED (this_region->u.must_not_throw.failure_decl) = 1;
1984 :
1985 1358711 : this_state.cur_region = this_region;
1986 1358711 : this_state.outer_non_cleanup = this_state.cur_region;
1987 : }
1988 :
1989 1358711 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1990 :
1991 1358711 : return gimple_try_eval (tp);
1992 : }
1993 :
1994 : /* Implement a cleanup expression. This is similar to try-finally,
1995 : except that we only execute the cleanup block for exception edges. */
1996 :
1997 : static gimple_seq
1998 145930 : lower_cleanup (struct leh_state *state, gtry *tp)
1999 : {
2000 145930 : struct leh_state this_state = *state;
2001 145930 : eh_region this_region = NULL;
2002 145930 : struct leh_tf_state fake_tf;
2003 145930 : gimple_seq result;
2004 145930 : bool cleanup_dead = cleanup_is_dead_in (state);
2005 :
2006 145930 : if (flag_exceptions && !cleanup_dead)
2007 : {
2008 122937 : this_region = gen_eh_region_cleanup (state->cur_region);
2009 122937 : this_state.cur_region = this_region;
2010 122937 : this_state.outer_non_cleanup = state->outer_non_cleanup;
2011 : }
2012 :
2013 145930 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
2014 :
2015 145930 : if (cleanup_dead || !eh_region_may_contain_throw (this_region))
2016 86106 : return gimple_try_eval (tp);
2017 :
2018 : /* Build enough of a try-finally state so that we can reuse
2019 : honor_protect_cleanup_actions. */
2020 59824 : memset (&fake_tf, 0, sizeof (fake_tf));
2021 59824 : fake_tf.top_p = fake_tf.try_finally_expr = tp;
2022 59824 : fake_tf.outer = state;
2023 59824 : fake_tf.region = this_region;
2024 59824 : fake_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
2025 59824 : fake_tf.may_throw = true;
2026 :
2027 59824 : honor_protect_cleanup_actions (state, NULL, &fake_tf);
2028 :
2029 59824 : if (fake_tf.may_throw)
2030 : {
2031 : /* In this case honor_protect_cleanup_actions had nothing to do,
2032 : and we should process this normally. */
2033 0 : lower_eh_constructs_1 (state, gimple_try_cleanup_ptr (tp));
2034 0 : result = frob_into_branch_around (tp, this_region,
2035 : fake_tf.fallthru_label);
2036 : }
2037 : else
2038 : {
2039 : /* In this case honor_protect_cleanup_actions did nearly all of
2040 : the work. All we have left is to append the fallthru_label. */
2041 :
2042 59824 : result = gimple_try_eval (tp);
2043 59824 : if (fake_tf.fallthru_label)
2044 : {
2045 0 : gimple *x = gimple_build_label (fake_tf.fallthru_label);
2046 0 : gimple_seq_add_stmt (&result, x);
2047 : }
2048 : }
2049 59824 : return result;
2050 : }
2051 :
2052 : /* Main loop for lowering eh constructs. Also moves gsi to the next
2053 : statement. */
2054 :
2055 : static void
2056 92221566 : lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
2057 : {
2058 92221566 : gimple_seq replace;
2059 92221566 : gimple *x;
2060 92221566 : gimple *stmt = gsi_stmt (*gsi);
2061 :
2062 92221566 : switch (gimple_code (stmt))
2063 : {
2064 11407498 : case GIMPLE_CALL:
2065 11407498 : {
2066 11407498 : tree fndecl = gimple_call_fndecl (stmt);
2067 11407498 : tree rhs, lhs;
2068 :
2069 11407498 : if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
2070 2239525 : switch (DECL_FUNCTION_CODE (fndecl))
2071 : {
2072 20395 : case BUILT_IN_EH_POINTER:
2073 : /* The front end may have generated a call to
2074 : __builtin_eh_pointer (0) within a catch region. Replace
2075 : this zero argument with the current catch region number. */
2076 20395 : if (state->ehp_region)
2077 : {
2078 40780 : tree nr = build_int_cst (integer_type_node,
2079 20390 : state->ehp_region->index);
2080 20390 : gimple_call_set_arg (stmt, 0, nr);
2081 : }
2082 : else
2083 : {
2084 : /* The user has dome something silly. Remove it. */
2085 5 : rhs = null_pointer_node;
2086 5 : goto do_replace;
2087 : }
2088 20390 : break;
2089 :
2090 0 : case BUILT_IN_EH_FILTER:
2091 : /* ??? This should never appear, but since it's a builtin it
2092 : is accessible to abuse by users. Just remove it and
2093 : replace the use with the arbitrary value zero. */
2094 0 : rhs = build_int_cst (TREE_TYPE (TREE_TYPE (fndecl)), 0);
2095 5 : do_replace:
2096 5 : lhs = gimple_call_lhs (stmt);
2097 5 : x = gimple_build_assign (lhs, rhs);
2098 5 : gsi_insert_before (gsi, x, GSI_SAME_STMT);
2099 : /* FALLTHRU */
2100 :
2101 5 : case BUILT_IN_EH_COPY_VALUES:
2102 : /* Likewise this should not appear. Remove it. */
2103 5 : gsi_remove (gsi, true);
2104 2573617 : return;
2105 :
2106 : default:
2107 : break;
2108 : }
2109 : }
2110 : /* FALLTHRU */
2111 :
2112 55287822 : case GIMPLE_ASSIGN:
2113 : /* If the stmt can throw, use a new temporary for the assignment
2114 : to a LHS. This makes sure the old value of the LHS is
2115 : available on the EH edge. Only do so for statements that
2116 : potentially fall through (no noreturn calls e.g.), otherwise
2117 : this new assignment might create fake fallthru regions. */
2118 55287822 : if (stmt_could_throw_p (cfun, stmt)
2119 3652801 : && gimple_has_lhs (stmt)
2120 2624784 : && gimple_stmt_may_fallthru (stmt)
2121 2624781 : && !lhs_could_trap_p (gimple_get_lhs (stmt))
2122 57693685 : && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt))))
2123 : {
2124 1769172 : tree lhs = gimple_get_lhs (stmt);
2125 1769172 : tree tmp = create_tmp_var (TREE_TYPE (lhs));
2126 1769172 : gimple *s = gimple_build_assign (lhs, tmp);
2127 1769172 : gimple_set_location (s, gimple_location (stmt));
2128 1769172 : gimple_set_block (s, gimple_block (stmt));
2129 1769172 : gimple_set_lhs (stmt, tmp);
2130 1769172 : gsi_insert_after (gsi, s, GSI_SAME_STMT);
2131 : }
2132 : /* Look for things that can throw exceptions, and record them. */
2133 55287822 : if (state->cur_region && stmt_could_throw_p (cfun, stmt))
2134 : {
2135 2760251 : record_stmt_eh_region (state->cur_region, stmt);
2136 2760251 : note_eh_region_may_contain_throw (state->cur_region);
2137 : }
2138 : break;
2139 :
2140 14248354 : case GIMPLE_COND:
2141 14248354 : case GIMPLE_GOTO:
2142 14248354 : case GIMPLE_RETURN:
2143 14248354 : case GIMPLE_ASM:
2144 14248354 : maybe_record_in_goto_queue (state, stmt);
2145 14248354 : break;
2146 :
2147 50176 : case GIMPLE_SWITCH:
2148 50176 : verify_norecord_switch_expr (state, as_a <gswitch *> (stmt));
2149 50176 : break;
2150 :
2151 2573607 : case GIMPLE_TRY:
2152 2573607 : {
2153 2573607 : gtry *try_stmt = as_a <gtry *> (stmt);
2154 2573607 : if (gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
2155 1739717 : replace = lower_try_finally (state, try_stmt);
2156 : else
2157 : {
2158 833890 : x = gimple_seq_first_stmt (gimple_try_cleanup (try_stmt));
2159 833890 : if (!x)
2160 : {
2161 0 : replace = gimple_try_eval (try_stmt);
2162 0 : lower_eh_constructs_1 (state, &replace);
2163 : }
2164 : else
2165 833890 : switch (gimple_code (x))
2166 : {
2167 47050 : case GIMPLE_CATCH:
2168 47050 : replace = lower_catch (state, try_stmt);
2169 47050 : break;
2170 5841 : case GIMPLE_EH_FILTER:
2171 5841 : replace = lower_eh_filter (state, try_stmt);
2172 5841 : break;
2173 635069 : case GIMPLE_EH_MUST_NOT_THROW:
2174 635069 : replace = lower_eh_must_not_throw (state, try_stmt);
2175 635069 : break;
2176 0 : case GIMPLE_EH_ELSE:
2177 : /* This code is only valid with GIMPLE_TRY_FINALLY. */
2178 0 : gcc_unreachable ();
2179 145930 : default:
2180 145930 : replace = lower_cleanup (state, try_stmt);
2181 145930 : break;
2182 : }
2183 : }
2184 : }
2185 :
2186 : /* Remove the old stmt and insert the transformed sequence
2187 : instead. */
2188 2573607 : gsi_insert_seq_before (gsi, replace, GSI_SAME_STMT);
2189 2573607 : gsi_remove (gsi, true);
2190 :
2191 : /* Return since we don't want gsi_next () */
2192 2573607 : return;
2193 :
2194 0 : case GIMPLE_EH_ELSE:
2195 : /* We should be eliminating this in lower_try_finally et al. */
2196 0 : gcc_unreachable ();
2197 :
2198 : default:
2199 : /* A type, a decl, or some kind of statement that we're not
2200 : interested in. Don't walk them. */
2201 : break;
2202 : }
2203 :
2204 89647954 : gsi_next (gsi);
2205 : }
2206 :
2207 : /* A helper to unwrap a gimple_seq and feed stmts to lower_eh_constructs_2. */
2208 :
2209 : static void
2210 8326882 : lower_eh_constructs_1 (struct leh_state *state, gimple_seq *pseq)
2211 : {
2212 8326882 : gimple_stmt_iterator gsi;
2213 108750192 : for (gsi = gsi_start (*pseq); !gsi_end_p (gsi);)
2214 92221566 : lower_eh_constructs_2 (state, &gsi);
2215 8326882 : }
2216 :
2217 : namespace {
2218 :
2219 : const pass_data pass_data_lower_eh =
2220 : {
2221 : GIMPLE_PASS, /* type */
2222 : "eh", /* name */
2223 : OPTGROUP_NONE, /* optinfo_flags */
2224 : TV_TREE_EH, /* tv_id */
2225 : PROP_gimple_lcf, /* properties_required */
2226 : PROP_gimple_leh, /* properties_provided */
2227 : 0, /* properties_destroyed */
2228 : 0, /* todo_flags_start */
2229 : 0, /* todo_flags_finish */
2230 : };
2231 :
2232 : class pass_lower_eh : public gimple_opt_pass
2233 : {
2234 : public:
2235 294587 : pass_lower_eh (gcc::context *ctxt)
2236 589174 : : gimple_opt_pass (pass_data_lower_eh, ctxt)
2237 : {}
2238 :
2239 : /* opt_pass methods: */
2240 : unsigned int execute (function *) final override;
2241 :
2242 : }; // class pass_lower_eh
2243 :
2244 : unsigned int
2245 3024716 : pass_lower_eh::execute (function *fun)
2246 : {
2247 3024716 : struct leh_state null_state;
2248 3024716 : gimple_seq bodyp;
2249 :
2250 3024716 : bodyp = gimple_body (current_function_decl);
2251 3024716 : if (bodyp == NULL)
2252 : return 0;
2253 :
2254 3024716 : finally_tree = new hash_table<finally_tree_hasher> (31);
2255 3024716 : eh_region_may_contain_throw_map = BITMAP_ALLOC (NULL);
2256 3024716 : memset (&null_state, 0, sizeof (null_state));
2257 :
2258 3024716 : collect_finally_tree_1 (bodyp, NULL);
2259 3024716 : lower_eh_constructs_1 (&null_state, &bodyp);
2260 3024716 : gimple_set_body (current_function_decl, bodyp);
2261 :
2262 : /* We assume there's a return statement, or something, at the end of
2263 : the function, and thus ploping the EH sequence afterward won't
2264 : change anything. */
2265 3024716 : gcc_assert (!gimple_seq_may_fallthru (bodyp));
2266 3024716 : gimple_seq_add_seq (&bodyp, eh_seq);
2267 :
2268 : /* We assume that since BODYP already existed, adding EH_SEQ to it
2269 : didn't change its value, and we don't have to re-set the function. */
2270 3024716 : gcc_assert (bodyp == gimple_body (current_function_decl));
2271 :
2272 3024716 : delete finally_tree;
2273 3024716 : finally_tree = NULL;
2274 3024716 : BITMAP_FREE (eh_region_may_contain_throw_map);
2275 3024716 : eh_seq = NULL;
2276 :
2277 : /* If this function needs a language specific EH personality routine
2278 : and the frontend didn't already set one do so now. */
2279 3024716 : if (function_needs_eh_personality (fun) == eh_personality_lang
2280 3024716 : && !DECL_FUNCTION_PERSONALITY (current_function_decl))
2281 832543 : DECL_FUNCTION_PERSONALITY (current_function_decl)
2282 1665086 : = lang_hooks.eh_personality ();
2283 :
2284 : return 0;
2285 : }
2286 :
2287 : } // anon namespace
2288 :
2289 : gimple_opt_pass *
2290 294587 : make_pass_lower_eh (gcc::context *ctxt)
2291 : {
2292 294587 : return new pass_lower_eh (ctxt);
2293 : }
2294 :
2295 : /* Create the multiple edges from an EH_DISPATCH statement to all of
2296 : the possible handlers for its EH region. Return true if there's
2297 : no fallthru edge; false if there is. */
2298 :
2299 : bool
2300 53031 : make_eh_dispatch_edges (geh_dispatch *stmt)
2301 : {
2302 53031 : eh_region r;
2303 53031 : eh_catch c;
2304 53031 : basic_block src, dst;
2305 :
2306 53031 : r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
2307 53031 : src = gimple_bb (stmt);
2308 :
2309 53031 : switch (r->type)
2310 : {
2311 52314 : case ERT_TRY:
2312 59901 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
2313 : {
2314 55738 : dst = label_to_block (cfun, c->label);
2315 55738 : make_edge (src, dst, 0);
2316 :
2317 : /* A catch-all handler doesn't have a fallthru. */
2318 55738 : if (c->type_list == NULL)
2319 : return false;
2320 : }
2321 : break;
2322 :
2323 717 : case ERT_ALLOWED_EXCEPTIONS:
2324 717 : dst = label_to_block (cfun, r->u.allowed.label);
2325 717 : make_edge (src, dst, 0);
2326 717 : break;
2327 :
2328 0 : default:
2329 0 : gcc_unreachable ();
2330 : }
2331 :
2332 : return true;
2333 : }
2334 :
2335 : /* Create the single EH edge from STMT to its nearest landing pad,
2336 : if there is such a landing pad within the current function. */
2337 :
2338 : edge
2339 6253250 : make_eh_edge (gimple *stmt)
2340 : {
2341 6253250 : basic_block src, dst;
2342 6253250 : eh_landing_pad lp;
2343 6253250 : int lp_nr;
2344 :
2345 6253250 : lp_nr = lookup_stmt_eh_lp (stmt);
2346 6253250 : if (lp_nr <= 0)
2347 : return NULL;
2348 :
2349 3983261 : lp = get_eh_landing_pad_from_number (lp_nr);
2350 3983261 : gcc_assert (lp != NULL);
2351 :
2352 3983261 : src = gimple_bb (stmt);
2353 3983261 : dst = label_to_block (cfun, lp->post_landing_pad);
2354 3983261 : return make_edge (src, dst, EDGE_EH);
2355 : }
2356 :
2357 : /* Do the work in redirecting EDGE_IN to NEW_BB within the EH region tree;
2358 : do not actually perform the final edge redirection.
2359 :
2360 : CHANGE_REGION is true when we're being called from cleanup_empty_eh and
2361 : we intend to change the destination EH region as well; this means
2362 : EH_LANDING_PAD_NR must already be set on the destination block label.
2363 : If false, we're being called from generic cfg manipulation code and we
2364 : should preserve our place within the region tree. */
2365 :
2366 : static void
2367 2749617 : redirect_eh_edge_1 (edge edge_in, basic_block new_bb, bool change_region)
2368 : {
2369 2749617 : eh_landing_pad old_lp, new_lp;
2370 2749617 : basic_block old_bb;
2371 2749617 : gimple *throw_stmt;
2372 2749617 : int old_lp_nr, new_lp_nr;
2373 2749617 : tree old_label, new_label;
2374 2749617 : edge_iterator ei;
2375 2749617 : edge e;
2376 :
2377 2749617 : old_bb = edge_in->dest;
2378 2749617 : old_label = gimple_block_label (old_bb);
2379 2749617 : old_lp_nr = EH_LANDING_PAD_NR (old_label);
2380 2749617 : gcc_assert (old_lp_nr > 0);
2381 2749617 : old_lp = get_eh_landing_pad_from_number (old_lp_nr);
2382 :
2383 2749617 : throw_stmt = *gsi_last_bb (edge_in->src);
2384 2749617 : gcc_checking_assert (lookup_stmt_eh_lp (throw_stmt) == old_lp_nr);
2385 :
2386 2749617 : new_label = gimple_block_label (new_bb);
2387 :
2388 : /* Look for an existing region that might be using NEW_BB already. */
2389 2749617 : new_lp_nr = EH_LANDING_PAD_NR (new_label);
2390 2749617 : if (new_lp_nr)
2391 : {
2392 1701660 : new_lp = get_eh_landing_pad_from_number (new_lp_nr);
2393 1701660 : gcc_assert (new_lp);
2394 :
2395 : /* Unless CHANGE_REGION is true, the new and old landing pad
2396 : had better be associated with the same EH region. */
2397 1701660 : gcc_assert (change_region || new_lp->region == old_lp->region);
2398 : }
2399 : else
2400 : {
2401 1047957 : new_lp = NULL;
2402 1047957 : gcc_assert (!change_region);
2403 : }
2404 :
2405 : /* Notice when we redirect the last EH edge away from OLD_BB. */
2406 10632925 : FOR_EACH_EDGE (e, ei, old_bb->preds)
2407 9356909 : if (e != edge_in && (e->flags & EDGE_EH))
2408 : break;
2409 :
2410 2749617 : if (new_lp)
2411 : {
2412 : /* NEW_LP already exists. If there are still edges into OLD_LP,
2413 : there's nothing to do with the EH tree. If there are no more
2414 : edges into OLD_LP, then we want to remove OLD_LP as it is unused.
2415 : If CHANGE_REGION is true, then our caller is expecting to remove
2416 : the landing pad. */
2417 1701660 : if (e == NULL && !change_region)
2418 786074 : remove_eh_landing_pad (old_lp);
2419 : }
2420 : else
2421 : {
2422 : /* No correct landing pad exists. If there are no more edges
2423 : into OLD_LP, then we can simply re-use the existing landing pad.
2424 : Otherwise, we have to create a new landing pad. */
2425 1047957 : if (e == NULL)
2426 : {
2427 239780 : EH_LANDING_PAD_NR (old_lp->post_landing_pad) = 0;
2428 239780 : new_lp = old_lp;
2429 : }
2430 : else
2431 808177 : new_lp = gen_eh_landing_pad (old_lp->region);
2432 1047957 : new_lp->post_landing_pad = new_label;
2433 1047957 : EH_LANDING_PAD_NR (new_label) = new_lp->index;
2434 : }
2435 :
2436 : /* Maybe move the throwing statement to the new region. */
2437 2749617 : if (old_lp != new_lp)
2438 : {
2439 2509837 : remove_stmt_from_eh_lp (throw_stmt);
2440 2509837 : add_stmt_to_eh_lp (throw_stmt, new_lp->index);
2441 : }
2442 2749617 : }
2443 :
2444 : /* Redirect EH edge E to NEW_BB. */
2445 :
2446 : edge
2447 998548 : redirect_eh_edge (edge edge_in, basic_block new_bb)
2448 : {
2449 998548 : redirect_eh_edge_1 (edge_in, new_bb, false);
2450 998548 : return ssa_redirect_edge (edge_in, new_bb);
2451 : }
2452 :
2453 : /* This is a subroutine of gimple_redirect_edge_and_branch. Update the
2454 : labels for redirecting a non-fallthru EH_DISPATCH edge E to NEW_BB.
2455 : The actual edge update will happen in the caller. */
2456 :
2457 : void
2458 0 : redirect_eh_dispatch_edge (geh_dispatch *stmt, edge e, basic_block new_bb)
2459 : {
2460 0 : tree new_lab = gimple_block_label (new_bb);
2461 0 : bool any_changed = false;
2462 0 : basic_block old_bb;
2463 0 : eh_region r;
2464 0 : eh_catch c;
2465 :
2466 0 : r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
2467 0 : switch (r->type)
2468 : {
2469 0 : case ERT_TRY:
2470 0 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
2471 : {
2472 0 : old_bb = label_to_block (cfun, c->label);
2473 0 : if (old_bb == e->dest)
2474 : {
2475 0 : c->label = new_lab;
2476 0 : any_changed = true;
2477 : }
2478 : }
2479 : break;
2480 :
2481 0 : case ERT_ALLOWED_EXCEPTIONS:
2482 0 : old_bb = label_to_block (cfun, r->u.allowed.label);
2483 0 : gcc_assert (old_bb == e->dest);
2484 0 : r->u.allowed.label = new_lab;
2485 0 : any_changed = true;
2486 0 : break;
2487 :
2488 0 : default:
2489 0 : gcc_unreachable ();
2490 : }
2491 :
2492 0 : gcc_assert (any_changed);
2493 0 : }
2494 :
2495 : /* Helper function for operation_could_trap_p and stmt_could_throw_p. */
2496 :
2497 : bool
2498 1852365200 : operation_could_trap_helper_p (enum tree_code op,
2499 : bool fp_operation,
2500 : bool honor_trapv,
2501 : bool honor_nans,
2502 : bool honor_snans,
2503 : tree divisor,
2504 : bool *handled)
2505 : {
2506 1852365200 : *handled = true;
2507 1852365200 : switch (op)
2508 : {
2509 2166725 : case TRUNC_DIV_EXPR:
2510 2166725 : case CEIL_DIV_EXPR:
2511 2166725 : case FLOOR_DIV_EXPR:
2512 2166725 : case ROUND_DIV_EXPR:
2513 2166725 : case EXACT_DIV_EXPR:
2514 2166725 : case CEIL_MOD_EXPR:
2515 2166725 : case FLOOR_MOD_EXPR:
2516 2166725 : case ROUND_MOD_EXPR:
2517 2166725 : case TRUNC_MOD_EXPR:
2518 2166725 : if (!TREE_CONSTANT (divisor) || integer_zerop (divisor))
2519 : return true;
2520 1424128 : if (TREE_CODE (divisor) == VECTOR_CST)
2521 : {
2522 : /* Inspired by initializer_each_zero_or_onep. */
2523 454 : unsigned HOST_WIDE_INT nelts = vector_cst_encoded_nelts (divisor);
2524 454 : if (VECTOR_CST_STEPPED_P (divisor)
2525 454 : && !TYPE_VECTOR_SUBPARTS (TREE_TYPE (divisor))
2526 0 : .is_constant (&nelts))
2527 1852365200 : return true;
2528 1540 : for (unsigned int i = 0; i < nelts; ++i)
2529 : {
2530 1119 : tree elt = vector_cst_elt (divisor, i);
2531 1119 : if (integer_zerop (elt))
2532 : return true;
2533 : }
2534 : }
2535 : return false;
2536 :
2537 422892 : case RDIV_EXPR:
2538 422892 : if (fp_operation)
2539 : {
2540 422892 : if (honor_snans)
2541 : return true;
2542 415168 : return flag_trapping_math;
2543 : }
2544 : /* Fixed point operations also use RDIV_EXPR. */
2545 0 : if (!TREE_CONSTANT (divisor) || fixed_zerop (divisor))
2546 : return true;
2547 : return false;
2548 :
2549 : case LT_EXPR:
2550 : case LE_EXPR:
2551 : case GT_EXPR:
2552 : case GE_EXPR:
2553 : case LTGT_EXPR:
2554 : /* MIN/MAX similar as LT/LE/GT/GE. */
2555 : case MIN_EXPR:
2556 : case MAX_EXPR:
2557 : /* Some floating point comparisons may trap. */
2558 : return honor_nans;
2559 :
2560 209147258 : case EQ_EXPR:
2561 209147258 : case NE_EXPR:
2562 209147258 : case UNORDERED_EXPR:
2563 209147258 : case ORDERED_EXPR:
2564 209147258 : case UNLT_EXPR:
2565 209147258 : case UNLE_EXPR:
2566 209147258 : case UNGT_EXPR:
2567 209147258 : case UNGE_EXPR:
2568 209147258 : case UNEQ_EXPR:
2569 209147258 : return honor_snans;
2570 :
2571 1343402 : case NEGATE_EXPR:
2572 1343402 : case ABS_EXPR:
2573 1343402 : case CONJ_EXPR:
2574 : /* These operations don't trap with floating point. */
2575 1343402 : if (honor_trapv)
2576 : return true;
2577 : return false;
2578 :
2579 : case ABSU_EXPR:
2580 : /* ABSU_EXPR never traps. */
2581 : return false;
2582 :
2583 92017796 : case PLUS_EXPR:
2584 92017796 : case MINUS_EXPR:
2585 92017796 : case MULT_EXPR:
2586 : /* Any floating arithmetic may trap. */
2587 92017796 : if (fp_operation && flag_trapping_math)
2588 : return true;
2589 90239226 : if (honor_trapv)
2590 : return true;
2591 : return false;
2592 :
2593 : case COMPLEX_EXPR:
2594 : case CONSTRUCTOR:
2595 : case VEC_DUPLICATE_EXPR:
2596 : case PAREN_EXPR:
2597 : /* Constructing an object cannot trap. */
2598 : return false;
2599 :
2600 228817 : case FIX_TRUNC_EXPR:
2601 228817 : case VEC_PACK_FIX_TRUNC_EXPR:
2602 228817 : case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
2603 228817 : case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
2604 : /* The FIX_TRUNC family are always potentially trapping. */
2605 228817 : return flag_trapping_math;
2606 :
2607 82167 : case COND_EXPR:
2608 82167 : case VEC_COND_EXPR:
2609 : /* Whether *COND_EXPR can trap depends on whether the
2610 : first argument can trap, so signal it as not handled.
2611 : Whether lhs is floating or not doesn't matter. */
2612 82167 : *handled = false;
2613 82167 : return false;
2614 :
2615 1466444637 : default:
2616 : /* Any floating arithmetic may trap. */
2617 1466444637 : if (fp_operation && flag_trapping_math)
2618 : return true;
2619 :
2620 1464134384 : *handled = false;
2621 1464134384 : return false;
2622 : }
2623 : }
2624 :
2625 : /* Return true if operation OP may trap. FP_OPERATION is true if OP is applied
2626 : on floating-point values. HONOR_TRAPV is true if OP is applied on integer
2627 : type operands that may trap. If OP is a division operator, DIVISOR contains
2628 : the value of the divisor. */
2629 :
2630 : bool
2631 4109304127 : operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
2632 : tree divisor)
2633 : {
2634 46441459 : bool honor_nans = (fp_operation && flag_trapping_math
2635 4143583249 : && !flag_finite_math_only);
2636 46441459 : bool honor_snans = fp_operation && flag_signaling_nans != 0;
2637 4109304127 : bool handled;
2638 :
2639 : /* This function cannot tell whether or not COND_EXPR could trap,
2640 : because that depends on its condition op. */
2641 4109304127 : gcc_assert (op != COND_EXPR);
2642 :
2643 4109304127 : if (TREE_CODE_CLASS (op) != tcc_comparison
2644 : && TREE_CODE_CLASS (op) != tcc_unary
2645 4109304127 : && TREE_CODE_CLASS (op) != tcc_binary)
2646 : return false;
2647 :
2648 285128628 : return operation_could_trap_helper_p (op, fp_operation, honor_trapv,
2649 : honor_nans, honor_snans, divisor,
2650 285128628 : &handled);
2651 : }
2652 :
2653 :
2654 : /* Returns true if it is possible to prove that the index of
2655 : an array access REF (an ARRAY_REF expression) falls into the
2656 : array bounds. */
2657 :
2658 : static bool
2659 251602631 : in_array_bounds_p (tree ref)
2660 : {
2661 251602631 : tree idx = TREE_OPERAND (ref, 1);
2662 251602631 : tree min, max;
2663 :
2664 251602631 : if (TREE_CODE (idx) != INTEGER_CST)
2665 : return false;
2666 :
2667 248133503 : min = array_ref_low_bound (ref);
2668 248133503 : max = array_ref_up_bound (ref);
2669 248133503 : if (!min
2670 248133503 : || !max
2671 248115273 : || TREE_CODE (min) != INTEGER_CST
2672 248115273 : || TREE_CODE (max) != INTEGER_CST)
2673 : return false;
2674 :
2675 248110188 : if (tree_int_cst_lt (idx, min)
2676 248110188 : || tree_int_cst_lt (max, idx))
2677 58381 : return false;
2678 :
2679 : return true;
2680 : }
2681 :
2682 : /* Returns true if it is possible to prove that the range of
2683 : an array access REF (an ARRAY_RANGE_REF expression) falls
2684 : into the array bounds. */
2685 :
2686 : static bool
2687 1962 : range_in_array_bounds_p (tree ref)
2688 : {
2689 1962 : tree domain_type = TYPE_DOMAIN (TREE_TYPE (ref));
2690 1962 : tree range_min, range_max, min, max;
2691 :
2692 1962 : range_min = TYPE_MIN_VALUE (domain_type);
2693 1962 : range_max = TYPE_MAX_VALUE (domain_type);
2694 1962 : if (!range_min
2695 1962 : || !range_max
2696 1962 : || TREE_CODE (range_min) != INTEGER_CST
2697 1962 : || TREE_CODE (range_max) != INTEGER_CST)
2698 : return false;
2699 :
2700 1962 : min = array_ref_low_bound (ref);
2701 1962 : max = array_ref_up_bound (ref);
2702 1962 : if (!min
2703 1962 : || !max
2704 1962 : || TREE_CODE (min) != INTEGER_CST
2705 1962 : || TREE_CODE (max) != INTEGER_CST)
2706 : return false;
2707 :
2708 1962 : if (tree_int_cst_lt (range_min, min)
2709 1962 : || tree_int_cst_lt (max, range_max))
2710 40 : return false;
2711 :
2712 : return true;
2713 : }
2714 :
2715 : /* Return true iff a BIT_FIELD_REF <(TYPE)???, SIZE, OFFSET> would access a bit
2716 : range that is known to be in bounds for TYPE. */
2717 :
2718 : bool
2719 1224514 : access_in_bounds_of_type_p (tree type, poly_uint64 size, poly_uint64 offset)
2720 : {
2721 1224514 : tree type_size_tree;
2722 1224514 : poly_uint64 type_size_max, min = offset, wid = size, max;
2723 :
2724 1224514 : type_size_tree = TYPE_SIZE (type);
2725 1224514 : if (!type_size_tree || !poly_int_tree_p (type_size_tree, &type_size_max))
2726 : return false;
2727 :
2728 1224491 : max = min + wid;
2729 1224491 : if (maybe_lt (max, min)
2730 1224491 : || maybe_lt (type_size_max, max))
2731 21 : return false;
2732 :
2733 : return true;
2734 : }
2735 :
2736 : /* Return whether an access at [off, refsz[ to an object spanning [0, size[
2737 : accesses storage outside of the object. */
2738 :
2739 : static bool
2740 244256676 : ref_outside_object_p (tree size, poly_offset_int off, tree refsz)
2741 : {
2742 244256676 : if (size == NULL_TREE
2743 244256676 : || refsz == NULL_TREE
2744 244242982 : || !poly_int_tree_p (size)
2745 244241767 : || !poly_int_tree_p (refsz)
2746 244221951 : || maybe_le (wi::to_poly_offset (size), off)
2747 488499658 : || maybe_gt (off + wi::to_poly_offset (refsz),
2748 : wi::to_poly_offset (size)))
2749 : return true;
2750 : /* Now we are sure the whole base of the access is inside
2751 : the object. */
2752 : return false;
2753 : }
2754 :
2755 : /* If PTR is a PARM_DECL or its default SSA definition, return the
2756 : PARM_DECL. Otherwise return NULL_TREE. */
2757 :
2758 : static tree
2759 221330396 : parm_decl_from_ptr (tree ptr)
2760 : {
2761 221330396 : if (TREE_CODE (ptr) == SSA_NAME)
2762 : {
2763 214779743 : if (!SSA_NAME_IS_DEFAULT_DEF (ptr))
2764 : return NULL_TREE;
2765 84472255 : ptr = SSA_NAME_VAR (ptr);
2766 : }
2767 :
2768 91022908 : return ptr && TREE_CODE (ptr) == PARM_DECL ? ptr : NULL_TREE;
2769 : }
2770 :
2771 : /* If PTR is a parameter of the current function, or the default definition
2772 : of one, that is known to designate a whole object, return the size of that
2773 : object in bytes. Otherwise return NULL_TREE.
2774 :
2775 : Two kinds of parameter qualify. The this pointer of a method points to
2776 : an object of the method base type. A parameter whose reference type
2777 : refers to an object type is bound to an object of the referenced type.
2778 : In both cases the pointed-to object is at least as large as that type. */
2779 :
2780 : static tree
2781 221433555 : whole_object_param_size (tree ptr)
2782 : {
2783 221433555 : tree type;
2784 :
2785 221433555 : if (!cfun)
2786 : return NULL_TREE;
2787 :
2788 221330396 : ptr = parm_decl_from_ptr (ptr);
2789 221330396 : if (!ptr)
2790 : return NULL_TREE;
2791 :
2792 87922230 : if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE)
2793 927596 : type = TREE_TYPE (TREE_TYPE (ptr));
2794 86994634 : else if (TREE_CODE (TREE_TYPE (cfun->decl)) == METHOD_TYPE
2795 86994634 : && ptr == DECL_ARGUMENTS (cfun->decl))
2796 1164091 : type = TYPE_METHOD_BASETYPE (TREE_TYPE (cfun->decl));
2797 : else
2798 : return NULL_TREE;
2799 :
2800 2091687 : return nonnull_arg_p (ptr) ? TYPE_SIZE_UNIT (type) : NULL_TREE;
2801 : }
2802 :
2803 : /* Return true if EXPR can trap, as in dereferencing an invalid pointer
2804 : location or evaluating floating-point arithmetic. See may_trap_p for the
2805 : RTL counterpart. This routine expects only GIMPLE lhs or rhs input. LHS
2806 : is true when EXPR is the lhs of a store. */
2807 :
2808 : static bool
2809 3819473745 : tree_could_trap_1 (tree expr, bool lhs)
2810 : {
2811 3819473745 : enum tree_code code;
2812 3819473745 : bool fp_operation = false;
2813 3819473745 : bool honor_trapv = false;
2814 3819473745 : tree t, base, div = NULL_TREE;
2815 :
2816 3819473745 : if (!expr)
2817 : return false;
2818 :
2819 : /* In COND_EXPR and VEC_COND_EXPR only the condition may trap, but
2820 : they won't appear as operands in GIMPLE form, so this is just for the
2821 : GENERIC uses where it needs to recurse on the operands and so
2822 : *COND_EXPR itself doesn't trap. */
2823 3816051352 : if (TREE_CODE (expr) == COND_EXPR || TREE_CODE (expr) == VEC_COND_EXPR)
2824 : return false;
2825 :
2826 3816049988 : code = TREE_CODE (expr);
2827 3816049988 : t = TREE_TYPE (expr);
2828 :
2829 3816049988 : if (t)
2830 : {
2831 3816038456 : if (COMPARISON_CLASS_P (expr))
2832 6606760 : fp_operation = FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
2833 : else
2834 3809431696 : fp_operation = FLOAT_TYPE_P (t);
2835 3816038456 : honor_trapv = INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t);
2836 : }
2837 :
2838 3816049988 : if (TREE_CODE_CLASS (code) == tcc_binary)
2839 500412 : div = TREE_OPERAND (expr, 1);
2840 3816049988 : if (operation_could_trap_p (code, fp_operation, honor_trapv, div))
2841 : return true;
2842 :
2843 3814664803 : restart:
2844 4748801852 : switch (code)
2845 : {
2846 1449329 : case BIT_FIELD_REF:
2847 1449329 : if (DECL_P (TREE_OPERAND (expr, 0))
2848 1449329 : && !access_in_bounds_of_type_p (TREE_TYPE (TREE_OPERAND (expr, 0)),
2849 : bit_field_size (expr),
2850 : bit_field_offset (expr)))
2851 : return true;
2852 : /* Fall through. */
2853 :
2854 934137049 : case COMPONENT_REF:
2855 934137049 : case REALPART_EXPR:
2856 934137049 : case IMAGPART_EXPR:
2857 934137049 : case VIEW_CONVERT_EXPR:
2858 934137049 : case WITH_SIZE_EXPR:
2859 934137049 : expr = TREE_OPERAND (expr, 0);
2860 934137049 : code = TREE_CODE (expr);
2861 934137049 : goto restart;
2862 :
2863 2111 : case ARRAY_RANGE_REF:
2864 2111 : base = TREE_OPERAND (expr, 0);
2865 2111 : if (tree_could_trap_1 (base, lhs))
2866 : return true;
2867 1962 : if (TREE_THIS_NOTRAP (expr))
2868 : return false;
2869 1962 : return !range_in_array_bounds_p (expr);
2870 :
2871 262304298 : case ARRAY_REF:
2872 262304298 : base = TREE_OPERAND (expr, 0);
2873 262304298 : if (tree_could_trap_1 (base, lhs))
2874 : return true;
2875 251652477 : if (TREE_THIS_NOTRAP (expr))
2876 : return false;
2877 251602631 : return !in_array_bounds_p (expr);
2878 :
2879 636804036 : case TARGET_MEM_REF:
2880 636804036 : case MEM_REF:
2881 636804036 : if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
2882 636804036 : && tree_could_trap_1 (TREE_OPERAND (TREE_OPERAND (expr, 0), 0), lhs))
2883 : return true;
2884 636750527 : if (TREE_THIS_NOTRAP (expr))
2885 : return false;
2886 : /* We cannot prove that the access is in-bounds when we have
2887 : variable-index TARGET_MEM_REFs. */
2888 546411505 : if (code == TARGET_MEM_REF
2889 554791945 : && (TMR_INDEX (expr) || TMR_INDEX2 (expr)))
2890 : return true;
2891 538941005 : if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
2892 : {
2893 242328772 : tree base = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
2894 242328772 : poly_offset_int off = mem_ref_offset (expr);
2895 242328772 : if (maybe_lt (off, 0))
2896 : return true;
2897 242325672 : if (TREE_CODE (base) == STRING_CST)
2898 159888 : return maybe_le (TREE_STRING_LENGTH (base), off);
2899 242165784 : tree size = DECL_SIZE_UNIT (base);
2900 242165784 : tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
2901 242165784 : return ref_outside_object_p (size, off, refsz);
2902 : }
2903 296612233 : if (!lhs)
2904 : {
2905 221433555 : if (tree size = whole_object_param_size (TREE_OPERAND (expr, 0)))
2906 : {
2907 2091132 : poly_offset_int off = mem_ref_offset (expr);
2908 2091132 : if (maybe_lt (off, 0))
2909 : return true;
2910 2090892 : tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
2911 2090892 : return ref_outside_object_p (size, off, refsz);
2912 : }
2913 : }
2914 : return true;
2915 :
2916 761245 : case INDIRECT_REF:
2917 761245 : return !TREE_THIS_NOTRAP (expr);
2918 :
2919 0 : case ASM_EXPR:
2920 0 : return TREE_THIS_VOLATILE (expr);
2921 :
2922 489954 : case CALL_EXPR:
2923 : /* Internal function calls do not trap. */
2924 489954 : if (CALL_EXPR_FN (expr) == NULL_TREE)
2925 : return false;
2926 489830 : t = get_callee_fndecl (expr);
2927 : /* Assume that indirect and calls to weak functions may trap. */
2928 489830 : if (!t || !DECL_P (t))
2929 : return true;
2930 489830 : if (DECL_WEAK (t))
2931 : return tree_could_trap_1 (t, lhs);
2932 : return false;
2933 :
2934 1247750 : case FUNCTION_DECL:
2935 : /* Functions will cause a trap if on the lhs. */
2936 1247750 : if (lhs)
2937 : return true;
2938 : /* Assume that accesses to weak functions may trap, unless we know
2939 : they are certainly defined in current TU or in some other
2940 : LTO partition. */
2941 3211 : if (DECL_WEAK (expr) && !DECL_COMDAT (expr) && DECL_EXTERNAL (expr))
2942 : {
2943 13 : cgraph_node *node = cgraph_node::get (expr);
2944 13 : if (node)
2945 13 : node = node->function_symbol ();
2946 13 : return !(node && node->in_other_partition);
2947 : }
2948 : return false;
2949 :
2950 1061557037 : case VAR_DECL:
2951 : /* Readonly non-local decls can cause a trap on the lhs. */
2952 1061557037 : if (lhs && !auto_var_p (expr) && TREE_READONLY (expr))
2953 : return true;
2954 : /* Assume that accesses to weak vars may trap, unless we know
2955 : they are certainly defined in current TU or in some other
2956 : LTO partition. */
2957 1056389187 : if (DECL_WEAK (expr) && !DECL_COMDAT (expr) && DECL_EXTERNAL (expr))
2958 : {
2959 18605 : varpool_node *node = varpool_node::get (expr);
2960 18605 : if (node)
2961 18523 : node = node->ultimate_alias_target ();
2962 18523 : return !(node && node->in_other_partition);
2963 : }
2964 : return false;
2965 : /* Strings, const and labels will cause a trap if on the lhs. */
2966 : case LABEL_DECL:
2967 : case CONST_DECL:
2968 : case STRING_CST:
2969 : return lhs;
2970 : /* Result and arguments will never cause a trap. */
2971 : case RESULT_DECL:
2972 : case PARM_DECL:
2973 : return false;
2974 : default:
2975 : return false;
2976 : }
2977 : }
2978 :
2979 : /* Return true if EXPR can trap when evaluated as an rvalue. See may_trap_p
2980 : for the RTL counterpart. */
2981 :
2982 : bool
2983 1636557951 : tree_could_trap_p (tree expr)
2984 : {
2985 1636557951 : return tree_could_trap_1 (expr, false);
2986 : }
2987 :
2988 : /* Return true if LHS can trap as a store. */
2989 : bool
2990 46308796 : lhs_could_trap_p (tree lhs)
2991 : {
2992 46308796 : return tree_could_trap_1 (lhs, true);
2993 : }
2994 :
2995 : /* Return non-NULL if there is an integer operation with trapping overflow
2996 : we can rewrite into non-trapping. Called via walk_tree from
2997 : rewrite_to_non_trapping_overflow. */
2998 :
2999 : static tree
3000 270 : find_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
3001 : {
3002 270 : if (EXPR_P (*tp)
3003 159 : && ANY_INTEGRAL_TYPE_P (TREE_TYPE (*tp))
3004 407 : && !operation_no_trapping_overflow (TREE_TYPE (*tp), TREE_CODE (*tp)))
3005 9 : return *tp;
3006 261 : if (IS_TYPE_OR_DECL_P (*tp)
3007 258 : || (TREE_CODE (*tp) == SAVE_EXPR && data == NULL))
3008 3 : *walk_subtrees = 0;
3009 : return NULL_TREE;
3010 : }
3011 :
3012 : /* Rewrite selected operations into unsigned arithmetics, so that they
3013 : don't trap on overflow. */
3014 :
3015 : static tree
3016 74 : replace_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
3017 : {
3018 74 : if (find_trapping_overflow (tp, walk_subtrees, data))
3019 : {
3020 6 : tree type = TREE_TYPE (*tp);
3021 6 : tree utype = unsigned_type_for (type);
3022 6 : *walk_subtrees = 0;
3023 6 : int len = TREE_OPERAND_LENGTH (*tp);
3024 24 : for (int i = 0; i < len; ++i)
3025 12 : walk_tree (&TREE_OPERAND (*tp, i), replace_trapping_overflow,
3026 : data, (hash_set<tree> *) data);
3027 :
3028 6 : if (TREE_CODE (*tp) == ABS_EXPR)
3029 : {
3030 0 : TREE_SET_CODE (*tp, ABSU_EXPR);
3031 0 : TREE_TYPE (*tp) = utype;
3032 0 : *tp = fold_convert (type, *tp);
3033 : }
3034 : else
3035 : {
3036 6 : TREE_TYPE (*tp) = utype;
3037 6 : len = TREE_OPERAND_LENGTH (*tp);
3038 24 : for (int i = 0; i < len; ++i)
3039 12 : TREE_OPERAND (*tp, i)
3040 24 : = fold_convert (utype, TREE_OPERAND (*tp, i));
3041 6 : *tp = fold_convert (type, *tp);
3042 : }
3043 : }
3044 74 : return NULL_TREE;
3045 : }
3046 :
3047 : /* If any subexpression of EXPR can trap due to -ftrapv, rewrite it
3048 : using unsigned arithmetics to avoid traps in it. */
3049 :
3050 : tree
3051 49948 : rewrite_to_non_trapping_overflow (tree expr)
3052 : {
3053 49948 : if (!flag_trapv)
3054 49911 : return expr;
3055 37 : hash_set<tree> pset;
3056 37 : if (!walk_tree (&expr, find_trapping_overflow, &pset, &pset))
3057 34 : return expr;
3058 3 : expr = unshare_expr (expr);
3059 3 : pset.empty ();
3060 3 : walk_tree (&expr, replace_trapping_overflow, &pset, &pset);
3061 3 : return expr;
3062 37 : }
3063 :
3064 : /* Helper for stmt_could_throw_p. Return true if STMT (assumed to be a
3065 : an assignment or a conditional) may throw. */
3066 :
3067 : static bool
3068 1630749096 : stmt_could_throw_1_p (gassign *stmt)
3069 : {
3070 1630749096 : enum tree_code code = gimple_assign_rhs_code (stmt);
3071 1630749096 : bool honor_nans = false;
3072 1630749096 : bool honor_snans = false;
3073 1630749096 : bool fp_operation = false;
3074 1630749096 : bool honor_trapv = false;
3075 1630749096 : tree t;
3076 1630749096 : size_t i;
3077 1630749096 : bool handled, ret;
3078 :
3079 1630749096 : if (TREE_CODE_CLASS (code) == tcc_comparison
3080 : || TREE_CODE_CLASS (code) == tcc_unary
3081 1630749096 : || TREE_CODE_CLASS (code) == tcc_binary)
3082 : {
3083 233927686 : if (TREE_CODE_CLASS (code) == tcc_comparison)
3084 29687473 : t = TREE_TYPE (gimple_assign_rhs1 (stmt));
3085 : else
3086 204240213 : t = TREE_TYPE (gimple_assign_lhs (stmt));
3087 233927686 : fp_operation = FLOAT_TYPE_P (t);
3088 226574225 : if (fp_operation)
3089 : {
3090 7353461 : honor_nans = flag_trapping_math && !flag_finite_math_only;
3091 7353461 : honor_snans = flag_signaling_nans != 0;
3092 : }
3093 226574225 : else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
3094 : honor_trapv = true;
3095 : }
3096 :
3097 : /* First check the LHS. */
3098 1630749096 : if (tree_could_trap_1 (gimple_assign_lhs (stmt), true))
3099 : return true;
3100 :
3101 : /* Check if the main expression may trap. */
3102 1708902597 : ret = operation_could_trap_helper_p (code, fp_operation, honor_trapv,
3103 : honor_nans, honor_snans,
3104 : gimple_assign_rhs2 (stmt),
3105 : &handled);
3106 1561512432 : if (handled)
3107 : return ret;
3108 :
3109 : /* If the expression does not trap, see if any of the individual operands may
3110 : trap. */
3111 2726350913 : for (i = 1; i < gimple_num_ops (stmt); i++)
3112 1497116628 : if (tree_could_trap_p (gimple_op (stmt, i)))
3113 : return true;
3114 :
3115 : return false;
3116 : }
3117 :
3118 :
3119 : /* Return true if statement STMT within FUN could throw an exception. */
3120 :
3121 : bool
3122 17888766689 : stmt_could_throw_p (function *fun, gimple *stmt)
3123 : {
3124 17888766689 : if (!flag_exceptions)
3125 : return false;
3126 :
3127 : /* The only statements that can throw an exception are assignments,
3128 : conditionals, calls, resx, and asms. */
3129 13539665080 : switch (gimple_code (stmt))
3130 : {
3131 : case GIMPLE_RESX:
3132 : return true;
3133 :
3134 1079348874 : case GIMPLE_CALL:
3135 1079348874 : {
3136 1079348874 : gcall *call = as_a <gcall *> (stmt);
3137 1079348874 : if (!gimple_call_nothrow_p (call))
3138 : return true;
3139 : /* Return slot optimization can fall back to a temporary and a
3140 : caller-side copy. */
3141 314778638 : if ((fun && !fun->can_throw_non_call_exceptions)
3142 325191674 : || !gimple_store_p (call))
3143 : return false;
3144 154664 : return lhs_could_trap_p (gimple_call_lhs (call));
3145 : }
3146 :
3147 201266607 : case GIMPLE_COND:
3148 201266607 : {
3149 201266607 : if (fun && !fun->can_throw_non_call_exceptions)
3150 : return false;
3151 68124432 : gcond *cond = as_a <gcond *> (stmt);
3152 68124432 : tree lhs = gimple_cond_lhs (cond);
3153 135794715 : return operation_could_trap_p (gimple_cond_code (cond),
3154 135794715 : FLOAT_TYPE_P (TREE_TYPE (lhs)),
3155 68124432 : false, NULL_TREE);
3156 : }
3157 :
3158 3998943544 : case GIMPLE_ASSIGN:
3159 3998943544 : if ((fun && !fun->can_throw_non_call_exceptions)
3160 5678042765 : || gimple_clobber_p (stmt))
3161 : return false;
3162 1630749096 : return stmt_could_throw_1_p (as_a <gassign *> (stmt));
3163 :
3164 1034382 : case GIMPLE_ASM:
3165 1034382 : if (fun && !fun->can_throw_non_call_exceptions)
3166 : return false;
3167 60756 : return gimple_asm_volatile_p (as_a <gasm *> (stmt));
3168 :
3169 : default:
3170 : return false;
3171 : }
3172 : }
3173 :
3174 : /* Return true if STMT in function FUN must be assumed necessary because of
3175 : non-call exceptions. */
3176 :
3177 : bool
3178 26900417 : stmt_unremovable_because_of_non_call_eh_p (function *fun, gimple *stmt)
3179 : {
3180 26900417 : return (fun->can_throw_non_call_exceptions
3181 5968956 : && !fun->can_delete_dead_exceptions
3182 32847349 : && stmt_could_throw_p (fun, stmt));
3183 : }
3184 :
3185 : /* Return true if expression T could throw an exception. */
3186 :
3187 : bool
3188 40069037 : tree_could_throw_p (tree t)
3189 : {
3190 40069037 : if (!flag_exceptions)
3191 : return false;
3192 33413567 : if (TREE_CODE (t) == MODIFY_EXPR)
3193 : {
3194 0 : if (cfun->can_throw_non_call_exceptions
3195 0 : && tree_could_trap_1 (TREE_OPERAND (t, 0), true))
3196 : return true;
3197 0 : t = TREE_OPERAND (t, 1);
3198 : }
3199 :
3200 33413567 : if (TREE_CODE (t) == WITH_SIZE_EXPR)
3201 0 : t = TREE_OPERAND (t, 0);
3202 33413567 : if (TREE_CODE (t) == CALL_EXPR)
3203 422043 : return (call_expr_flags (t) & ECF_NOTHROW) == 0;
3204 32991524 : if (cfun->can_throw_non_call_exceptions)
3205 20385547 : return tree_could_trap_p (t);
3206 : return false;
3207 : }
3208 :
3209 : /* Return true if STMT can throw an exception that is not caught within its
3210 : function FUN. FUN can be NULL but the function is extra conservative
3211 : then. */
3212 :
3213 : bool
3214 917394543 : stmt_can_throw_external (function *fun, gimple *stmt)
3215 : {
3216 917394543 : int lp_nr;
3217 :
3218 917394543 : if (!stmt_could_throw_p (fun, stmt))
3219 : return false;
3220 46388868 : if (!fun)
3221 : return true;
3222 :
3223 46383949 : lp_nr = lookup_stmt_eh_lp_fn (fun, stmt);
3224 46383949 : return lp_nr == 0;
3225 : }
3226 :
3227 : /* Return true if STMT can throw an exception that is caught within its
3228 : function FUN. */
3229 :
3230 : bool
3231 15464088061 : stmt_can_throw_internal (function *fun, gimple *stmt)
3232 : {
3233 15464088061 : int lp_nr;
3234 :
3235 15464088061 : gcc_checking_assert (fun);
3236 15464088061 : if (!stmt_could_throw_p (fun, stmt))
3237 : return false;
3238 :
3239 625700693 : lp_nr = lookup_stmt_eh_lp_fn (fun, stmt);
3240 625700693 : return lp_nr > 0;
3241 : }
3242 :
3243 : /* Given a statement STMT in IFUN, if STMT can no longer throw, then
3244 : remove any entry it might have from the EH table. Return true if
3245 : any change was made. */
3246 :
3247 : bool
3248 197219939 : maybe_clean_eh_stmt_fn (struct function *ifun, gimple *stmt)
3249 : {
3250 197219939 : if (stmt_could_throw_p (ifun, stmt))
3251 : return false;
3252 180035770 : return remove_stmt_from_eh_lp_fn (ifun, stmt);
3253 : }
3254 :
3255 : /* Likewise, but always use the current function. */
3256 :
3257 : bool
3258 197219939 : maybe_clean_eh_stmt (gimple *stmt)
3259 : {
3260 197219939 : return maybe_clean_eh_stmt_fn (cfun, stmt);
3261 : }
3262 :
3263 : /* Given a statement OLD_STMT and a new statement NEW_STMT that has replaced
3264 : OLD_STMT in the function, remove OLD_STMT from the EH table and put NEW_STMT
3265 : in the table if it should be in there. Return TRUE if a replacement was
3266 : done that my require an EH edge purge. */
3267 :
3268 : bool
3269 49613010 : maybe_clean_or_replace_eh_stmt (gimple *old_stmt, gimple *new_stmt)
3270 : {
3271 49613010 : int lp_nr = lookup_stmt_eh_lp (old_stmt);
3272 :
3273 49613010 : if (lp_nr != 0)
3274 : {
3275 1610301 : bool new_stmt_could_throw = stmt_could_throw_p (cfun, new_stmt);
3276 :
3277 1610301 : if (new_stmt == old_stmt && new_stmt_could_throw)
3278 : return false;
3279 :
3280 319827 : remove_stmt_from_eh_lp (old_stmt);
3281 319827 : if (new_stmt_could_throw)
3282 : {
3283 317 : add_stmt_to_eh_lp (new_stmt, lp_nr);
3284 317 : return false;
3285 : }
3286 : else
3287 : return true;
3288 : }
3289 :
3290 : return false;
3291 : }
3292 :
3293 : /* Given a statement OLD_STMT in OLD_FUN and a duplicate statement NEW_STMT
3294 : in NEW_FUN, copy the EH table data from OLD_STMT to NEW_STMT. The MAP
3295 : operand is the return value of duplicate_eh_regions. */
3296 :
3297 : bool
3298 98777636 : maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple *new_stmt,
3299 : struct function *old_fun, gimple *old_stmt,
3300 : hash_map<void *, void *> *map,
3301 : int default_lp_nr)
3302 : {
3303 98777636 : int old_lp_nr, new_lp_nr;
3304 :
3305 98777636 : if (!stmt_could_throw_p (new_fun, new_stmt))
3306 : return false;
3307 :
3308 1920301 : old_lp_nr = lookup_stmt_eh_lp_fn (old_fun, old_stmt);
3309 1920301 : if (old_lp_nr == 0)
3310 : {
3311 1736264 : if (default_lp_nr == 0)
3312 : return false;
3313 : new_lp_nr = default_lp_nr;
3314 : }
3315 184037 : else if (old_lp_nr > 0)
3316 : {
3317 129292 : eh_landing_pad old_lp, new_lp;
3318 :
3319 129292 : old_lp = (*old_fun->eh->lp_array)[old_lp_nr];
3320 129292 : new_lp = static_cast<eh_landing_pad> (*map->get (old_lp));
3321 129292 : new_lp_nr = new_lp->index;
3322 : }
3323 : else
3324 : {
3325 54745 : eh_region old_r, new_r;
3326 :
3327 54745 : old_r = (*old_fun->eh->region_array)[-old_lp_nr];
3328 54745 : new_r = static_cast<eh_region> (*map->get (old_r));
3329 54745 : new_lp_nr = -new_r->index;
3330 : }
3331 :
3332 836165 : add_stmt_to_eh_lp_fn (new_fun, new_stmt, new_lp_nr);
3333 836165 : return true;
3334 : }
3335 :
3336 : /* Similar, but both OLD_STMT and NEW_STMT are within the current function,
3337 : and thus no remapping is required. */
3338 :
3339 : bool
3340 24728071 : maybe_duplicate_eh_stmt (gimple *new_stmt, gimple *old_stmt)
3341 : {
3342 24728071 : int lp_nr;
3343 :
3344 24728071 : if (!stmt_could_throw_p (cfun, new_stmt))
3345 : return false;
3346 :
3347 70913 : lp_nr = lookup_stmt_eh_lp (old_stmt);
3348 70913 : if (lp_nr == 0)
3349 : return false;
3350 :
3351 7519 : add_stmt_to_eh_lp (new_stmt, lp_nr);
3352 7519 : return true;
3353 : }
3354 :
3355 : /* Returns TRUE if oneh and twoh are exception handlers (gimple_try_cleanup of
3356 : GIMPLE_TRY) that are similar enough to be considered the same. Currently
3357 : this only handles handlers consisting of a single call, as that's the
3358 : important case for C++: a destructor call for a particular object showing
3359 : up in multiple handlers. */
3360 :
3361 : static bool
3362 1 : same_handler_p (gimple_seq oneh, gimple_seq twoh)
3363 : {
3364 1 : gimple_stmt_iterator gsi;
3365 1 : gimple *ones, *twos;
3366 1 : unsigned int ai;
3367 :
3368 1 : gsi = gsi_start (oneh);
3369 1 : if (!gsi_one_before_end_p (gsi))
3370 : return false;
3371 1 : ones = gsi_stmt (gsi);
3372 :
3373 1 : gsi = gsi_start (twoh);
3374 1 : if (!gsi_one_before_end_p (gsi))
3375 : return false;
3376 1 : twos = gsi_stmt (gsi);
3377 :
3378 1 : if (!is_gimple_call (ones)
3379 1 : || !is_gimple_call (twos)
3380 1 : || gimple_call_lhs (ones)
3381 1 : || gimple_call_lhs (twos)
3382 1 : || gimple_call_chain (ones)
3383 1 : || gimple_call_chain (twos)
3384 1 : || !gimple_call_same_target_p (ones, twos)
3385 2 : || gimple_call_num_args (ones) != gimple_call_num_args (twos))
3386 : return false;
3387 :
3388 2 : for (ai = 0; ai < gimple_call_num_args (ones); ++ai)
3389 1 : if (!operand_equal_p (gimple_call_arg (ones, ai),
3390 1 : gimple_call_arg (twos, ai), 0))
3391 : return false;
3392 :
3393 : return true;
3394 : }
3395 :
3396 : /* Optimize
3397 : try { A() } finally { try { ~B() } catch { ~A() } }
3398 : try { ... } finally { ~A() }
3399 : into
3400 : try { A() } catch { ~B() }
3401 : try { ~B() ... } finally { ~A() }
3402 :
3403 : This occurs frequently in C++, where A is a local variable and B is a
3404 : temporary used in the initializer for A. */
3405 :
3406 : static void
3407 58121 : optimize_double_finally (gtry *one, gtry *two)
3408 : {
3409 58121 : gimple *oneh;
3410 58121 : gimple_stmt_iterator gsi;
3411 58121 : gimple_seq cleanup;
3412 :
3413 58121 : cleanup = gimple_try_cleanup (one);
3414 58121 : gsi = gsi_start (cleanup);
3415 58121 : if (!gsi_one_before_end_p (gsi))
3416 58121 : return;
3417 :
3418 56726 : oneh = gsi_stmt (gsi);
3419 56726 : if (gimple_code (oneh) != GIMPLE_TRY
3420 56726 : || gimple_try_kind (oneh) != GIMPLE_TRY_CATCH)
3421 : return;
3422 :
3423 1 : if (same_handler_p (gimple_try_cleanup (oneh), gimple_try_cleanup (two)))
3424 : {
3425 1 : gimple_seq seq = gimple_try_eval (oneh);
3426 :
3427 1 : gimple_try_set_cleanup (one, seq);
3428 1 : gimple_try_set_kind (one, GIMPLE_TRY_CATCH);
3429 1 : seq = copy_gimple_seq_and_replace_locals (seq);
3430 1 : gimple_seq_add_seq (&seq, gimple_try_eval (two));
3431 1 : gimple_try_set_eval (two, seq);
3432 : }
3433 : }
3434 :
3435 : /* Perform EH refactoring optimizations that are simpler to do when code
3436 : flow has been lowered but EH structures haven't. */
3437 :
3438 : static void
3439 6688638 : refactor_eh_r (gimple_seq seq)
3440 : {
3441 6688638 : gimple_stmt_iterator gsi;
3442 6688638 : gimple *one, *two;
3443 :
3444 6688638 : one = NULL;
3445 6688638 : two = NULL;
3446 6688638 : gsi = gsi_start (seq);
3447 109778530 : while (1)
3448 : {
3449 58233584 : one = two;
3450 58233584 : if (gsi_end_p (gsi))
3451 : two = NULL;
3452 : else
3453 : two = gsi_stmt (gsi);
3454 58233584 : if (one && two)
3455 44980044 : if (gtry *try_one = dyn_cast <gtry *> (one))
3456 1478196 : if (gtry *try_two = dyn_cast <gtry *> (two))
3457 73239 : if (gimple_try_kind (try_one) == GIMPLE_TRY_FINALLY
3458 73239 : && gimple_try_kind (try_two) == GIMPLE_TRY_FINALLY)
3459 58121 : optimize_double_finally (try_one, try_two);
3460 58233584 : if (one)
3461 51544946 : switch (gimple_code (one))
3462 : {
3463 2184621 : case GIMPLE_TRY:
3464 2184621 : refactor_eh_r (gimple_try_eval (one));
3465 2184621 : refactor_eh_r (gimple_try_cleanup (one));
3466 2184621 : break;
3467 41042 : case GIMPLE_CATCH:
3468 41042 : refactor_eh_r (gimple_catch_handler (as_a <gcatch *> (one)));
3469 41042 : break;
3470 5841 : case GIMPLE_EH_FILTER:
3471 5841 : refactor_eh_r (gimple_eh_filter_failure (one));
3472 5841 : break;
3473 826 : case GIMPLE_EH_ELSE:
3474 826 : {
3475 826 : geh_else *eh_else_stmt = as_a <geh_else *> (one);
3476 826 : refactor_eh_r (gimple_eh_else_n_body (eh_else_stmt));
3477 826 : refactor_eh_r (gimple_eh_else_e_body (eh_else_stmt));
3478 : }
3479 826 : break;
3480 : default:
3481 : break;
3482 : }
3483 58233584 : if (two)
3484 51544946 : gsi_next (&gsi);
3485 : else
3486 : break;
3487 51544946 : }
3488 6688638 : }
3489 :
3490 : namespace {
3491 :
3492 : const pass_data pass_data_refactor_eh =
3493 : {
3494 : GIMPLE_PASS, /* type */
3495 : "ehopt", /* name */
3496 : OPTGROUP_NONE, /* optinfo_flags */
3497 : TV_TREE_EH, /* tv_id */
3498 : PROP_gimple_lcf, /* properties_required */
3499 : 0, /* properties_provided */
3500 : 0, /* properties_destroyed */
3501 : 0, /* todo_flags_start */
3502 : 0, /* todo_flags_finish */
3503 : };
3504 :
3505 : class pass_refactor_eh : public gimple_opt_pass
3506 : {
3507 : public:
3508 294587 : pass_refactor_eh (gcc::context *ctxt)
3509 589174 : : gimple_opt_pass (pass_data_refactor_eh, ctxt)
3510 : {}
3511 :
3512 : /* opt_pass methods: */
3513 3024721 : bool gate (function *) final override { return flag_exceptions != 0; }
3514 2270861 : unsigned int execute (function *) final override
3515 : {
3516 2270861 : refactor_eh_r (gimple_body (current_function_decl));
3517 2270861 : return 0;
3518 : }
3519 :
3520 : }; // class pass_refactor_eh
3521 :
3522 : } // anon namespace
3523 :
3524 : gimple_opt_pass *
3525 294587 : make_pass_refactor_eh (gcc::context *ctxt)
3526 : {
3527 294587 : return new pass_refactor_eh (ctxt);
3528 : }
3529 :
3530 : /* At the end of gimple optimization, we can lower RESX. */
3531 :
3532 : static bool
3533 182751 : lower_resx (basic_block bb, gresx *stmt,
3534 : hash_map<eh_region, tree> *mnt_map)
3535 : {
3536 182751 : int lp_nr;
3537 182751 : eh_region src_r, dst_r;
3538 182751 : gimple_stmt_iterator gsi;
3539 182751 : gcall *x;
3540 182751 : tree fn, src_nr;
3541 182751 : bool ret = false;
3542 :
3543 182751 : lp_nr = lookup_stmt_eh_lp (stmt);
3544 182751 : if (lp_nr != 0)
3545 100773 : dst_r = get_eh_region_from_lp_number (lp_nr);
3546 : else
3547 : dst_r = NULL;
3548 :
3549 182751 : src_r = get_eh_region_from_number (gimple_resx_region (stmt));
3550 182751 : gsi = gsi_last_bb (bb);
3551 :
3552 182751 : if (src_r == NULL)
3553 : {
3554 : /* We can wind up with no source region when pass_cleanup_eh shows
3555 : that there are no entries into an eh region and deletes it, but
3556 : then the block that contains the resx isn't removed. This can
3557 : happen without optimization when the switch statement created by
3558 : lower_try_finally_switch isn't simplified to remove the eh case.
3559 :
3560 : Resolve this by expanding the resx node to an abort. */
3561 :
3562 0 : fn = builtin_decl_implicit (BUILT_IN_TRAP);
3563 0 : x = gimple_build_call (fn, 0);
3564 0 : gimple_call_set_ctrl_altering (x, true);
3565 0 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3566 :
3567 0 : while (EDGE_COUNT (bb->succs) > 0)
3568 0 : remove_edge (EDGE_SUCC (bb, 0));
3569 : }
3570 182751 : else if (dst_r)
3571 : {
3572 : /* When we have a destination region, we resolve this by copying
3573 : the excptr and filter values into place, and changing the edge
3574 : to immediately after the landing pad. */
3575 100773 : edge e;
3576 :
3577 100773 : if (lp_nr < 0)
3578 : {
3579 476 : basic_block new_bb;
3580 476 : tree lab;
3581 :
3582 : /* We are resuming into a MUST_NOT_CALL region. Expand a call to
3583 : the failure decl into a new block, if needed. */
3584 476 : gcc_assert (dst_r->type == ERT_MUST_NOT_THROW);
3585 :
3586 476 : tree *slot = mnt_map->get (dst_r);
3587 476 : if (slot == NULL)
3588 : {
3589 356 : gimple_stmt_iterator gsi2;
3590 :
3591 356 : new_bb = create_empty_bb (bb);
3592 356 : new_bb->count = bb->count;
3593 356 : add_bb_to_loop (new_bb, bb->loop_father);
3594 356 : lab = gimple_block_label (new_bb);
3595 356 : gsi2 = gsi_start_bb (new_bb);
3596 :
3597 : /* Handle failure fns that expect either no arguments or the
3598 : exception pointer. */
3599 356 : fn = dst_r->u.must_not_throw.failure_decl;
3600 356 : if (TYPE_ARG_TYPES (TREE_TYPE (fn)) != void_list_node)
3601 : {
3602 356 : tree epfn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
3603 356 : src_nr = build_int_cst (integer_type_node, src_r->index);
3604 356 : x = gimple_build_call (epfn, 1, src_nr);
3605 356 : tree var = create_tmp_var (ptr_type_node);
3606 356 : var = make_ssa_name (var, x);
3607 356 : gimple_call_set_lhs (x, var);
3608 356 : gsi_insert_after (&gsi2, x, GSI_CONTINUE_LINKING);
3609 356 : x = gimple_build_call (fn, 1, var);
3610 : }
3611 : else
3612 0 : x = gimple_build_call (fn, 0);
3613 356 : gimple_set_location (x, dst_r->u.must_not_throw.failure_loc);
3614 356 : gsi_insert_after (&gsi2, x, GSI_CONTINUE_LINKING);
3615 :
3616 356 : mnt_map->put (dst_r, lab);
3617 : }
3618 : else
3619 : {
3620 120 : lab = *slot;
3621 120 : new_bb = label_to_block (cfun, lab);
3622 : }
3623 :
3624 476 : gcc_assert (EDGE_COUNT (bb->succs) == 0);
3625 476 : e = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
3626 : }
3627 : else
3628 : {
3629 100297 : edge_iterator ei;
3630 100297 : tree dst_nr = build_int_cst (integer_type_node, dst_r->index);
3631 :
3632 100297 : fn = builtin_decl_implicit (BUILT_IN_EH_COPY_VALUES);
3633 100297 : src_nr = build_int_cst (integer_type_node, src_r->index);
3634 100297 : x = gimple_build_call (fn, 2, dst_nr, src_nr);
3635 100297 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3636 :
3637 : /* Update the flags for the outgoing edge. */
3638 100297 : e = single_succ_edge (bb);
3639 100297 : gcc_assert (e->flags & EDGE_EH);
3640 100297 : e->flags = (e->flags & ~EDGE_EH) | EDGE_FALLTHRU;
3641 100297 : e->probability = profile_probability::always ();
3642 :
3643 : /* If there are no more EH users of the landing pad, delete it. */
3644 152616 : FOR_EACH_EDGE (e, ei, e->dest->preds)
3645 131414 : if (e->flags & EDGE_EH)
3646 : break;
3647 100297 : if (e == NULL)
3648 : {
3649 21202 : eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr);
3650 21202 : remove_eh_landing_pad (lp);
3651 : }
3652 : }
3653 :
3654 100773 : ret = true;
3655 : }
3656 : else
3657 : {
3658 81978 : tree var;
3659 :
3660 : /* When we don't have a destination region, this exception escapes
3661 : up the call chain. We resolve this by generating a call to the
3662 : _Unwind_Resume library function. */
3663 :
3664 : /* The ARM EABI redefines _Unwind_Resume as __cxa_end_cleanup
3665 : with no arguments for C++. Check for that. */
3666 81978 : if (src_r->use_cxa_end_cleanup)
3667 : {
3668 0 : fn = builtin_decl_implicit (BUILT_IN_CXA_END_CLEANUP);
3669 0 : x = gimple_build_call (fn, 0);
3670 0 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3671 : }
3672 : else
3673 : {
3674 81978 : fn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
3675 81978 : src_nr = build_int_cst (integer_type_node, src_r->index);
3676 81978 : x = gimple_build_call (fn, 1, src_nr);
3677 81978 : var = create_tmp_var (ptr_type_node);
3678 81978 : var = make_ssa_name (var, x);
3679 81978 : gimple_call_set_lhs (x, var);
3680 81978 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3681 :
3682 : /* When exception handling is delegated to a caller function, we
3683 : have to guarantee that shadow memory variables living on stack
3684 : will be cleaner before control is given to a parent function. */
3685 81978 : if (sanitize_flags_p (SANITIZE_ADDRESS))
3686 : {
3687 271 : tree decl
3688 271 : = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
3689 271 : gimple *g = gimple_build_call (decl, 0);
3690 271 : gimple_set_location (g, gimple_location (stmt));
3691 271 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
3692 : }
3693 :
3694 81978 : fn = builtin_decl_implicit (BUILT_IN_UNWIND_RESUME);
3695 81978 : x = gimple_build_call (fn, 1, var);
3696 81978 : gimple_call_set_ctrl_altering (x, true);
3697 81978 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3698 : }
3699 :
3700 81978 : gcc_assert (EDGE_COUNT (bb->succs) == 0);
3701 : }
3702 :
3703 182751 : gsi_remove (&gsi, true);
3704 :
3705 182751 : return ret;
3706 : }
3707 :
3708 : namespace {
3709 :
3710 : const pass_data pass_data_lower_resx =
3711 : {
3712 : GIMPLE_PASS, /* type */
3713 : "resx", /* name */
3714 : OPTGROUP_NONE, /* optinfo_flags */
3715 : TV_TREE_EH, /* tv_id */
3716 : PROP_gimple_lcf, /* properties_required */
3717 : 0, /* properties_provided */
3718 : 0, /* properties_destroyed */
3719 : 0, /* todo_flags_start */
3720 : 0, /* todo_flags_finish */
3721 : };
3722 :
3723 : class pass_lower_resx : public gimple_opt_pass
3724 : {
3725 : public:
3726 294587 : pass_lower_resx (gcc::context *ctxt)
3727 589174 : : gimple_opt_pass (pass_data_lower_resx, ctxt)
3728 : {}
3729 :
3730 : /* opt_pass methods: */
3731 1512174 : bool gate (function *) final override { return flag_exceptions != 0; }
3732 : unsigned int execute (function *) final override;
3733 :
3734 : }; // class pass_lower_resx
3735 :
3736 : unsigned
3737 823897 : pass_lower_resx::execute (function *fun)
3738 : {
3739 823897 : basic_block bb;
3740 823897 : bool dominance_invalidated = false;
3741 823897 : bool any_rewritten = false;
3742 :
3743 823897 : hash_map<eh_region, tree> mnt_map;
3744 :
3745 9884729 : FOR_EACH_BB_FN (bb, fun)
3746 : {
3747 25724491 : if (gresx *last = safe_dyn_cast <gresx *> (*gsi_last_bb (bb)))
3748 : {
3749 182751 : dominance_invalidated |= lower_resx (bb, last, &mnt_map);
3750 182751 : any_rewritten = true;
3751 : }
3752 : }
3753 :
3754 823897 : if (dominance_invalidated)
3755 : {
3756 22202 : free_dominance_info (CDI_DOMINATORS);
3757 22202 : free_dominance_info (CDI_POST_DOMINATORS);
3758 : }
3759 :
3760 823897 : return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
3761 823897 : }
3762 :
3763 : } // anon namespace
3764 :
3765 : gimple_opt_pass *
3766 294587 : make_pass_lower_resx (gcc::context *ctxt)
3767 : {
3768 294587 : return new pass_lower_resx (ctxt);
3769 : }
3770 :
3771 : /* Try to optimize var = {v} {CLOBBER} stmts followed just by
3772 : external throw. */
3773 :
3774 : static void
3775 663487 : optimize_clobbers (basic_block bb)
3776 : {
3777 663487 : gimple_stmt_iterator gsi = gsi_last_bb (bb);
3778 663487 : bool any_clobbers = false;
3779 663487 : bool seen_stack_restore = false;
3780 663487 : edge_iterator ei;
3781 663487 : edge e;
3782 :
3783 : /* Only optimize anything if the bb contains at least one clobber,
3784 : ends with resx (checked by caller), optionally contains some
3785 : debug stmts or labels, or at most one __builtin_stack_restore
3786 : call, and has an incoming EH edge. */
3787 2624250 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3788 : {
3789 2591476 : gimple *stmt = gsi_stmt (gsi);
3790 2591476 : if (is_gimple_debug (stmt))
3791 1419214 : continue;
3792 1172262 : if (gimple_clobber_p (stmt))
3793 : {
3794 524746 : any_clobbers = true;
3795 524746 : continue;
3796 : }
3797 647932 : if (!seen_stack_restore
3798 647516 : && gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
3799 : {
3800 416 : seen_stack_restore = true;
3801 416 : continue;
3802 : }
3803 647100 : if (gimple_code (stmt) == GIMPLE_LABEL)
3804 : break;
3805 455711 : return;
3806 : }
3807 378291 : if (!any_clobbers)
3808 : return;
3809 228912 : FOR_EACH_EDGE (e, ei, bb->preds)
3810 221548 : if (e->flags & EDGE_EH)
3811 : break;
3812 215140 : if (e == NULL)
3813 : return;
3814 207776 : gsi = gsi_last_bb (bb);
3815 1169208 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3816 : {
3817 753656 : gimple *stmt = gsi_stmt (gsi);
3818 753656 : if (!gimple_clobber_p (stmt))
3819 379083 : continue;
3820 374573 : unlink_stmt_vdef (stmt);
3821 374573 : gsi_remove (&gsi, true);
3822 374573 : release_defs (stmt);
3823 : }
3824 : }
3825 :
3826 : /* Try to sink var = {v} {CLOBBER} stmts followed just by
3827 : internal throw to successor BB.
3828 : SUNK, if not NULL, is an array of sequences indexed by basic-block
3829 : index to sink to and to pick up sinking opportunities from.
3830 : If FOUND_OPPORTUNITY is not NULL then do not perform the optimization
3831 : but set *FOUND_OPPORTUNITY to true. */
3832 :
3833 : static int
3834 702826 : sink_clobbers (basic_block bb,
3835 : gimple_seq *sunk = NULL, bool *found_opportunity = NULL)
3836 : {
3837 702826 : edge e;
3838 702826 : edge_iterator ei;
3839 702826 : gimple_stmt_iterator gsi, dgsi;
3840 702826 : basic_block succbb;
3841 702826 : bool any_clobbers = false;
3842 702826 : unsigned todo = 0;
3843 :
3844 : /* Only optimize if BB has a single EH successor and
3845 : all predecessor edges are EH too. */
3846 702826 : if (!single_succ_p (bb)
3847 702351 : || (single_succ_edge (bb)->flags & EDGE_EH) == 0)
3848 : return 0;
3849 :
3850 2900706 : FOR_EACH_EDGE (e, ei, bb->preds)
3851 : {
3852 2217871 : if ((e->flags & EDGE_EH) == 0)
3853 : return 0;
3854 : }
3855 :
3856 : /* And BB contains only CLOBBER stmts before the final
3857 : RESX. */
3858 682835 : gsi = gsi_last_bb (bb);
3859 2865035 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3860 : {
3861 2865035 : gimple *stmt = gsi_stmt (gsi);
3862 2865035 : if (is_gimple_debug (stmt))
3863 1752841 : continue;
3864 1112194 : if (gimple_code (stmt) == GIMPLE_LABEL)
3865 : break;
3866 840971 : if (!gimple_clobber_p (stmt))
3867 : return 0;
3868 : any_clobbers = true;
3869 : }
3870 271223 : if (!any_clobbers && (!sunk || gimple_seq_empty_p (sunk[bb->index])))
3871 : return 0;
3872 :
3873 : /* If this was a dry run, tell it we found clobbers to sink. */
3874 182574 : if (found_opportunity)
3875 : {
3876 3467 : *found_opportunity = true;
3877 3467 : return 0;
3878 : }
3879 :
3880 179107 : edge succe = single_succ_edge (bb);
3881 179107 : succbb = succe->dest;
3882 :
3883 : /* See if there is a virtual PHI node to take an updated virtual
3884 : operand from. */
3885 179107 : gphi *vphi = NULL;
3886 179107 : for (gphi_iterator gpi = gsi_start_phis (succbb);
3887 179620 : !gsi_end_p (gpi); gsi_next (&gpi))
3888 : {
3889 143960 : tree res = gimple_phi_result (gpi.phi ());
3890 287920 : if (virtual_operand_p (res))
3891 : {
3892 : vphi = gpi.phi ();
3893 : break;
3894 : }
3895 : }
3896 :
3897 179107 : gimple *first_sunk = NULL;
3898 179107 : gimple *last_sunk = NULL;
3899 179107 : if (sunk && !(succbb->flags & BB_VISITED))
3900 9730 : dgsi = gsi_start (sunk[succbb->index]);
3901 : else
3902 171157 : dgsi = gsi_after_labels (succbb);
3903 179107 : gsi = gsi_last_bb (bb);
3904 453263 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3905 : {
3906 453263 : gimple *stmt = gsi_stmt (gsi);
3907 453263 : tree lhs;
3908 453263 : if (is_gimple_debug (stmt))
3909 64494 : continue;
3910 388769 : if (gimple_code (stmt) == GIMPLE_LABEL)
3911 : break;
3912 209662 : lhs = gimple_assign_lhs (stmt);
3913 : /* Unfortunately we don't have dominance info updated at this
3914 : point, so checking if
3915 : dominated_by_p (CDI_DOMINATORS, succbb,
3916 : gimple_bb (SSA_NAME_DEF_STMT (TREE_OPERAND (lhs, 0)))
3917 : would be too costly. Thus, avoid sinking any clobbers that
3918 : refer to non-(D) SSA_NAMEs. */
3919 209669 : if (TREE_CODE (lhs) == MEM_REF
3920 92 : && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME
3921 209714 : && !SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (lhs, 0)))
3922 : {
3923 7 : unlink_stmt_vdef (stmt);
3924 7 : gsi_remove (&gsi, true);
3925 7 : release_defs (stmt);
3926 7 : continue;
3927 : }
3928 :
3929 : /* As we do not change stmt order when sinking across a
3930 : forwarder edge we can keep virtual operands in place. */
3931 209655 : gsi_remove (&gsi, false);
3932 209655 : gsi_insert_before (&dgsi, stmt, GSI_NEW_STMT);
3933 209655 : if (!first_sunk)
3934 179084 : first_sunk = stmt;
3935 : last_sunk = stmt;
3936 : }
3937 179107 : if (sunk && !gimple_seq_empty_p (sunk[bb->index]))
3938 : {
3939 1807 : if (!first_sunk)
3940 16 : first_sunk = gsi_stmt (gsi_last (sunk[bb->index]));
3941 1807 : last_sunk = gsi_stmt (gsi_start (sunk[bb->index]));
3942 1807 : gsi_insert_seq_before_without_update (&dgsi,
3943 : sunk[bb->index], GSI_NEW_STMT);
3944 1807 : sunk[bb->index] = NULL;
3945 : }
3946 179107 : if (first_sunk)
3947 : {
3948 : /* If there isn't a single predecessor but no virtual PHI node
3949 : create one and arrange for virtual operands to be renamed as
3950 : we cannot be sure all incoming edges will updated from sinking
3951 : something. */
3952 214753 : if (!vphi && !single_pred_p (succbb))
3953 : {
3954 10851 : vphi = create_phi_node (gimple_vop (cfun), succbb);
3955 103115 : FOR_EACH_EDGE (e, ei, succbb->preds)
3956 92264 : add_phi_arg (vphi, gimple_vop (cfun), e, UNKNOWN_LOCATION);
3957 10851 : mark_virtual_operands_for_renaming (cfun);
3958 10851 : todo |= TODO_update_ssa_only_virtuals;
3959 : }
3960 : /* Adjust virtual operands if we sunk across a virtual PHI. */
3961 179100 : if (vphi)
3962 : {
3963 154298 : imm_use_iterator iter;
3964 154298 : use_operand_p use_p;
3965 154298 : gimple *use_stmt;
3966 154298 : tree phi_def = gimple_phi_result (vphi);
3967 298908 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, phi_def)
3968 289434 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
3969 289434 : SET_USE (use_p, gimple_vdef (first_sunk));
3970 154298 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (phi_def))
3971 : {
3972 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_vdef (first_sunk)) = 1;
3973 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (phi_def) = 0;
3974 : }
3975 308596 : SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (vphi, succe),
3976 : gimple_vuse (last_sunk));
3977 154298 : SET_USE (gimple_vuse_op (last_sunk), phi_def);
3978 : }
3979 : }
3980 :
3981 179107 : return todo;
3982 : }
3983 :
3984 : /* At the end of inlining, we can lower EH_DISPATCH. Return true when
3985 : we have found some duplicate labels and removed some edges. */
3986 :
3987 : static bool
3988 43382 : lower_eh_dispatch (basic_block src, geh_dispatch *stmt)
3989 : {
3990 43382 : gimple_stmt_iterator gsi;
3991 43382 : int region_nr;
3992 43382 : eh_region r;
3993 43382 : tree filter, fn;
3994 43382 : gimple *x;
3995 43382 : bool redirected = false;
3996 :
3997 43382 : region_nr = gimple_eh_dispatch_region (stmt);
3998 43382 : r = get_eh_region_from_number (region_nr);
3999 :
4000 43382 : gsi = gsi_last_bb (src);
4001 :
4002 43382 : switch (r->type)
4003 : {
4004 43096 : case ERT_TRY:
4005 43096 : {
4006 43096 : auto_vec<tree> labels;
4007 43096 : tree default_label = NULL;
4008 43096 : eh_catch c;
4009 43096 : edge_iterator ei;
4010 43096 : edge e;
4011 43096 : hash_set<tree> seen_values;
4012 :
4013 : /* Collect the labels for a switch. Zero the post_landing_pad
4014 : field because we'll no longer have anything keeping these labels
4015 : in existence and the optimizer will be free to merge these
4016 : blocks at will. */
4017 49565 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
4018 : {
4019 46026 : tree tp_node, flt_node, lab = c->label;
4020 46026 : bool have_label = false;
4021 :
4022 46026 : c->label = NULL;
4023 46026 : tp_node = c->type_list;
4024 46026 : flt_node = c->filter_list;
4025 :
4026 46026 : if (tp_node == NULL)
4027 : {
4028 : default_label = lab;
4029 : break;
4030 : }
4031 6469 : do
4032 : {
4033 : /* Filter out duplicate labels that arise when this handler
4034 : is shadowed by an earlier one. When no labels are
4035 : attached to the handler anymore, we remove
4036 : the corresponding edge and then we delete unreachable
4037 : blocks at the end of this pass. */
4038 6469 : if (! seen_values.contains (TREE_VALUE (flt_node)))
4039 : {
4040 6448 : tree t = build_case_label (TREE_VALUE (flt_node),
4041 6448 : NULL, lab);
4042 6448 : labels.safe_push (t);
4043 6448 : seen_values.add (TREE_VALUE (flt_node));
4044 6448 : have_label = true;
4045 : }
4046 :
4047 6469 : tp_node = TREE_CHAIN (tp_node);
4048 6469 : flt_node = TREE_CHAIN (flt_node);
4049 : }
4050 6469 : while (tp_node);
4051 6469 : if (! have_label)
4052 : {
4053 21 : remove_edge (find_edge (src, label_to_block (cfun, lab)));
4054 21 : redirected = true;
4055 : }
4056 : }
4057 :
4058 : /* Clean up the edge flags. */
4059 92640 : FOR_EACH_EDGE (e, ei, src->succs)
4060 : {
4061 49544 : if (e->flags & EDGE_FALLTHRU)
4062 : {
4063 : /* If there was no catch-all, use the fallthru edge. */
4064 3539 : if (default_label == NULL)
4065 3539 : default_label = gimple_block_label (e->dest);
4066 3539 : e->flags &= ~EDGE_FALLTHRU;
4067 : }
4068 : }
4069 43096 : gcc_assert (default_label != NULL);
4070 :
4071 : /* Don't generate a switch if there's only a default case.
4072 : This is common in the form of try { A; } catch (...) { B; }. */
4073 43096 : if (!labels.exists ())
4074 : {
4075 37671 : e = single_succ_edge (src);
4076 37671 : e->flags |= EDGE_FALLTHRU;
4077 : }
4078 : else
4079 : {
4080 5425 : fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
4081 5425 : x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
4082 5425 : region_nr));
4083 5425 : filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)));
4084 5425 : filter = make_ssa_name (filter, x);
4085 5425 : gimple_call_set_lhs (x, filter);
4086 5425 : gimple_set_location (x, gimple_location (stmt));
4087 5425 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4088 :
4089 : /* Turn the default label into a default case. */
4090 5425 : default_label = build_case_label (NULL, NULL, default_label);
4091 5425 : sort_case_labels (labels);
4092 :
4093 5425 : x = gimple_build_switch (filter, default_label, labels);
4094 5425 : gimple_set_location (x, gimple_location (stmt));
4095 5425 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4096 : }
4097 43096 : }
4098 43096 : break;
4099 :
4100 286 : case ERT_ALLOWED_EXCEPTIONS:
4101 286 : {
4102 286 : edge b_e = BRANCH_EDGE (src);
4103 286 : edge f_e = FALLTHRU_EDGE (src);
4104 :
4105 286 : fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
4106 286 : x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
4107 286 : region_nr));
4108 286 : filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)));
4109 286 : filter = make_ssa_name (filter, x);
4110 286 : gimple_call_set_lhs (x, filter);
4111 286 : gimple_set_location (x, gimple_location (stmt));
4112 286 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4113 :
4114 286 : r->u.allowed.label = NULL;
4115 286 : x = gimple_build_cond (EQ_EXPR, filter,
4116 286 : build_int_cst (TREE_TYPE (filter),
4117 286 : r->u.allowed.filter),
4118 : NULL_TREE, NULL_TREE);
4119 286 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4120 :
4121 286 : b_e->flags = b_e->flags | EDGE_TRUE_VALUE;
4122 286 : f_e->flags = (f_e->flags & ~EDGE_FALLTHRU) | EDGE_FALSE_VALUE;
4123 : }
4124 286 : break;
4125 :
4126 0 : default:
4127 0 : gcc_unreachable ();
4128 : }
4129 :
4130 : /* Replace the EH_DISPATCH with the SWITCH or COND generated above. */
4131 43382 : gsi_remove (&gsi, true);
4132 43382 : return redirected;
4133 : }
4134 :
4135 : namespace {
4136 :
4137 : const pass_data pass_data_lower_eh_dispatch =
4138 : {
4139 : GIMPLE_PASS, /* type */
4140 : "ehdisp", /* name */
4141 : OPTGROUP_NONE, /* optinfo_flags */
4142 : TV_TREE_EH, /* tv_id */
4143 : PROP_gimple_lcf, /* properties_required */
4144 : 0, /* properties_provided */
4145 : 0, /* properties_destroyed */
4146 : 0, /* todo_flags_start */
4147 : 0, /* todo_flags_finish */
4148 : };
4149 :
4150 : class pass_lower_eh_dispatch : public gimple_opt_pass
4151 : {
4152 : public:
4153 294587 : pass_lower_eh_dispatch (gcc::context *ctxt)
4154 589174 : : gimple_opt_pass (pass_data_lower_eh_dispatch, ctxt)
4155 : {}
4156 :
4157 : /* opt_pass methods: */
4158 1512346 : bool gate (function *fun) final override
4159 : {
4160 1512346 : return fun->eh->region_tree != NULL;
4161 : }
4162 : unsigned int execute (function *) final override;
4163 :
4164 : }; // class pass_lower_eh_dispatch
4165 :
4166 : unsigned
4167 147305 : pass_lower_eh_dispatch::execute (function *fun)
4168 : {
4169 147305 : basic_block bb;
4170 147305 : int flags = 0;
4171 147305 : bool redirected = false;
4172 147305 : bool any_resx_to_process = false;
4173 :
4174 147305 : assign_filter_values ();
4175 :
4176 5461012 : FOR_EACH_BB_FN (bb, fun)
4177 : {
4178 5313707 : gimple *last = *gsi_last_bb (bb);
4179 5313707 : if (last == NULL)
4180 77346 : continue;
4181 5236361 : if (gimple_code (last) == GIMPLE_EH_DISPATCH)
4182 : {
4183 43382 : redirected |= lower_eh_dispatch (bb,
4184 : as_a <geh_dispatch *> (last));
4185 43382 : flags |= TODO_update_ssa_only_virtuals;
4186 : }
4187 5192979 : else if (gimple_code (last) == GIMPLE_RESX)
4188 : {
4189 219483 : if (stmt_can_throw_external (fun, last))
4190 104625 : optimize_clobbers (bb);
4191 114858 : else if (!any_resx_to_process)
4192 107328 : sink_clobbers (bb, NULL, &any_resx_to_process);
4193 : }
4194 5236361 : bb->flags &= ~BB_VISITED;
4195 : }
4196 147305 : if (redirected)
4197 : {
4198 12 : free_dominance_info (CDI_DOMINATORS);
4199 12 : delete_unreachable_blocks ();
4200 : }
4201 :
4202 147305 : if (any_resx_to_process)
4203 : {
4204 : /* Make sure to catch all secondary sinking opportunities by processing
4205 : blocks in RPO order and after all CFG modifications from lowering
4206 : and unreachable block removal. */
4207 3467 : int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
4208 3467 : int rpo_n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, false);
4209 3467 : gimple_seq *sunk = XCNEWVEC (gimple_seq, last_basic_block_for_fn (fun));
4210 132793 : for (int i = 0; i < rpo_n; ++i)
4211 : {
4212 125859 : bb = BASIC_BLOCK_FOR_FN (fun, rpo[i]);
4213 125859 : gimple *last = *gsi_last_bb (bb);
4214 125859 : if (last
4215 123607 : && gimple_code (last) == GIMPLE_RESX
4216 141839 : && !stmt_can_throw_external (fun, last))
4217 12056 : flags |= sink_clobbers (bb, sunk);
4218 : /* If there were any clobbers sunk into this BB, insert them now. */
4219 125859 : if (!gimple_seq_empty_p (sunk[bb->index]))
4220 : {
4221 4363 : gimple_stmt_iterator gsi = gsi_after_labels (bb);
4222 4363 : gsi_insert_seq_before (&gsi, sunk[bb->index], GSI_NEW_STMT);
4223 4363 : sunk[bb->index] = NULL;
4224 : }
4225 125859 : bb->flags |= BB_VISITED;
4226 : }
4227 3467 : free (rpo);
4228 3467 : free (sunk);
4229 : }
4230 :
4231 147305 : return flags;
4232 : }
4233 :
4234 : } // anon namespace
4235 :
4236 : gimple_opt_pass *
4237 294587 : make_pass_lower_eh_dispatch (gcc::context *ctxt)
4238 : {
4239 294587 : return new pass_lower_eh_dispatch (ctxt);
4240 : }
4241 :
4242 : /* Walk statements, see what regions and, optionally, landing pads
4243 : are really referenced.
4244 :
4245 : Returns in R_REACHABLEP an sbitmap with bits set for reachable regions,
4246 : and in LP_REACHABLE an sbitmap with bits set for reachable landing pads.
4247 :
4248 : Passing NULL for LP_REACHABLE is valid, in this case only reachable
4249 : regions are marked.
4250 :
4251 : The caller is responsible for freeing the returned sbitmaps. */
4252 :
4253 : static void
4254 1471606 : mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep)
4255 : {
4256 1471606 : sbitmap r_reachable, lp_reachable;
4257 1471606 : basic_block bb;
4258 1471606 : bool mark_landing_pads = (lp_reachablep != NULL);
4259 1471606 : gcc_checking_assert (r_reachablep != NULL);
4260 :
4261 1471606 : r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
4262 1471606 : bitmap_clear (r_reachable);
4263 1471606 : *r_reachablep = r_reachable;
4264 :
4265 1471606 : if (mark_landing_pads)
4266 : {
4267 1175519 : lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
4268 1175519 : bitmap_clear (lp_reachable);
4269 1175519 : *lp_reachablep = lp_reachable;
4270 : }
4271 : else
4272 : lp_reachable = NULL;
4273 :
4274 21335765 : FOR_EACH_BB_FN (bb, cfun)
4275 : {
4276 19864159 : gimple_stmt_iterator gsi;
4277 :
4278 190627849 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4279 : {
4280 150899531 : gimple *stmt = gsi_stmt (gsi);
4281 :
4282 150899531 : if (mark_landing_pads)
4283 : {
4284 90289233 : int lp_nr = lookup_stmt_eh_lp (stmt);
4285 :
4286 : /* Negative LP numbers are MUST_NOT_THROW regions which
4287 : are not considered BB enders. */
4288 90289233 : if (lp_nr < 0)
4289 92999 : bitmap_set_bit (r_reachable, -lp_nr);
4290 :
4291 : /* Positive LP numbers are real landing pads, and BB enders. */
4292 90196234 : else if (lp_nr > 0)
4293 : {
4294 3422559 : gcc_assert (gsi_one_before_end_p (gsi));
4295 3422559 : eh_region region = get_eh_region_from_lp_number (lp_nr);
4296 3422559 : bitmap_set_bit (r_reachable, region->index);
4297 3422559 : bitmap_set_bit (lp_reachable, lp_nr);
4298 : }
4299 : }
4300 :
4301 : /* Avoid removing regions referenced from RESX/EH_DISPATCH. */
4302 150899531 : switch (gimple_code (stmt))
4303 : {
4304 1176250 : case GIMPLE_RESX:
4305 2352500 : bitmap_set_bit (r_reachable,
4306 1176250 : gimple_resx_region (as_a <gresx *> (stmt)));
4307 1176250 : break;
4308 66536 : case GIMPLE_EH_DISPATCH:
4309 133072 : bitmap_set_bit (r_reachable,
4310 : gimple_eh_dispatch_region (
4311 66536 : as_a <geh_dispatch *> (stmt)));
4312 66536 : break;
4313 8025616 : case GIMPLE_CALL:
4314 8025616 : if (gimple_call_builtin_p (stmt, BUILT_IN_EH_COPY_VALUES))
4315 3999 : for (int i = 0; i < 2; ++i)
4316 : {
4317 2666 : tree rt = gimple_call_arg (stmt, i);
4318 2666 : HOST_WIDE_INT ri = tree_to_shwi (rt);
4319 :
4320 2666 : gcc_assert (ri == (int)ri);
4321 2666 : bitmap_set_bit (r_reachable, ri);
4322 : }
4323 : break;
4324 : default:
4325 : break;
4326 : }
4327 : }
4328 : }
4329 1471606 : }
4330 :
4331 : /* Remove unreachable handlers and unreachable landing pads. */
4332 :
4333 : static void
4334 1175519 : remove_unreachable_handlers (void)
4335 : {
4336 1175519 : sbitmap r_reachable, lp_reachable;
4337 1175519 : eh_region region;
4338 1175519 : eh_landing_pad lp;
4339 1175519 : unsigned i;
4340 :
4341 1175519 : mark_reachable_handlers (&r_reachable, &lp_reachable);
4342 :
4343 1175519 : if (dump_file)
4344 : {
4345 3 : fprintf (dump_file, "Before removal of unreachable regions:\n");
4346 3 : dump_eh_tree (dump_file, cfun);
4347 3 : fprintf (dump_file, "Reachable regions: ");
4348 3 : dump_bitmap_file (dump_file, r_reachable);
4349 3 : fprintf (dump_file, "Reachable landing pads: ");
4350 3 : dump_bitmap_file (dump_file, lp_reachable);
4351 : }
4352 :
4353 1175519 : if (dump_file)
4354 : {
4355 18 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
4356 15 : if (region && !bitmap_bit_p (r_reachable, region->index))
4357 6 : fprintf (dump_file,
4358 : "Removing unreachable region %d\n",
4359 : region->index);
4360 : }
4361 :
4362 1175519 : remove_unreachable_eh_regions (r_reachable);
4363 :
4364 5895551 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
4365 3544513 : if (lp && !bitmap_bit_p (lp_reachable, lp->index))
4366 : {
4367 10493 : if (dump_file)
4368 0 : fprintf (dump_file,
4369 : "Removing unreachable landing pad %d\n",
4370 : lp->index);
4371 10493 : remove_eh_landing_pad (lp);
4372 : }
4373 :
4374 1175519 : if (dump_file)
4375 : {
4376 3 : fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
4377 3 : dump_eh_tree (dump_file, cfun);
4378 3 : fprintf (dump_file, "\n\n");
4379 : }
4380 :
4381 1175519 : sbitmap_free (r_reachable);
4382 1175519 : sbitmap_free (lp_reachable);
4383 :
4384 1175519 : if (flag_checking)
4385 1175504 : verify_eh_tree (cfun);
4386 1175519 : }
4387 :
4388 : /* Remove unreachable handlers if any landing pads have been removed after
4389 : last ehcleanup pass (due to gimple_purge_dead_eh_edges). */
4390 :
4391 : void
4392 1753214 : maybe_remove_unreachable_handlers (void)
4393 : {
4394 1753214 : eh_landing_pad lp;
4395 1753214 : unsigned i;
4396 :
4397 1753214 : if (cfun->eh == NULL)
4398 : return;
4399 :
4400 5277625 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
4401 3528205 : if (lp
4402 3528205 : && (lp->post_landing_pad == NULL_TREE
4403 361955 : || label_to_block (cfun, lp->post_landing_pad) == NULL))
4404 : {
4405 3794 : remove_unreachable_handlers ();
4406 3794 : return;
4407 : }
4408 : }
4409 :
4410 : /* Remove regions that do not have landing pads. This assumes
4411 : that remove_unreachable_handlers has already been run, and
4412 : that we've just manipulated the landing pads since then.
4413 :
4414 : Preserve regions with landing pads and regions that prevent
4415 : exceptions from propagating further, even if these regions
4416 : are not reachable. */
4417 :
4418 : static void
4419 296087 : remove_unreachable_handlers_no_lp (void)
4420 : {
4421 296087 : eh_region region;
4422 296087 : sbitmap r_reachable;
4423 296087 : unsigned i;
4424 :
4425 296087 : mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL);
4426 :
4427 3180720 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
4428 : {
4429 2588546 : if (! region)
4430 1644402 : continue;
4431 :
4432 944144 : if (region->landing_pads != NULL
4433 623911 : || region->type == ERT_MUST_NOT_THROW)
4434 354817 : bitmap_set_bit (r_reachable, region->index);
4435 :
4436 944144 : if (dump_file
4437 944144 : && !bitmap_bit_p (r_reachable, region->index))
4438 6 : fprintf (dump_file,
4439 : "Removing unreachable region %d\n",
4440 : region->index);
4441 : }
4442 :
4443 296087 : remove_unreachable_eh_regions (r_reachable);
4444 :
4445 296087 : sbitmap_free (r_reachable);
4446 296087 : }
4447 :
4448 : /* Undo critical edge splitting on an EH landing pad. Earlier, we
4449 : optimisticaly split all sorts of edges, including EH edges. The
4450 : optimization passes in between may not have needed them; if not,
4451 : we should undo the split.
4452 :
4453 : Recognize this case by having one EH edge incoming to the BB and
4454 : one normal edge outgoing; BB should be empty apart from the
4455 : post_landing_pad label.
4456 :
4457 : Note that this is slightly different from the empty handler case
4458 : handled by cleanup_empty_eh, in that the actual handler may yet
4459 : have actual code but the landing pad has been separated from the
4460 : handler. As such, cleanup_empty_eh relies on this transformation
4461 : having been done first. */
4462 :
4463 : static bool
4464 1755842 : unsplit_eh (eh_landing_pad lp)
4465 : {
4466 1755842 : basic_block bb = label_to_block (cfun, lp->post_landing_pad);
4467 1755842 : gimple_stmt_iterator gsi;
4468 1755842 : edge e_in, e_out;
4469 :
4470 : /* Quickly check the edge counts on BB for singularity. */
4471 3082122 : if (!single_pred_p (bb) || !single_succ_p (bb))
4472 : return false;
4473 1282051 : e_in = single_pred_edge (bb);
4474 1282051 : e_out = single_succ_edge (bb);
4475 :
4476 : /* Input edge must be EH and output edge must be normal. */
4477 1282051 : if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0)
4478 : return false;
4479 :
4480 : /* The block must be empty except for the labels and debug insns. */
4481 971756 : gsi = gsi_after_labels (bb);
4482 971756 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4483 3629 : gsi_next_nondebug (&gsi);
4484 971756 : if (!gsi_end_p (gsi))
4485 : return false;
4486 :
4487 : /* The destination block must not already have a landing pad
4488 : for a different region. */
4489 2693035 : for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
4490 : {
4491 1776336 : glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
4492 896031 : tree lab;
4493 896031 : int lp_nr;
4494 :
4495 896031 : if (!label_stmt)
4496 : break;
4497 896031 : lab = gimple_label_label (label_stmt);
4498 896031 : lp_nr = EH_LANDING_PAD_NR (lab);
4499 896031 : if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
4500 : return false;
4501 : }
4502 :
4503 : /* The new destination block must not already be a destination of
4504 : the source block, lest we merge fallthru and eh edges and get
4505 : all sorts of confused. */
4506 898502 : if (find_edge (e_in->src, e_out->dest))
4507 : return false;
4508 :
4509 : /* ??? We can get degenerate phis due to cfg cleanups. I would have
4510 : thought this should have been cleaned up by a phicprop pass, but
4511 : that doesn't appear to handle virtuals. Propagate by hand. */
4512 898498 : if (!gimple_seq_empty_p (phi_nodes (bb)))
4513 : {
4514 0 : for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi); )
4515 : {
4516 0 : gimple *use_stmt;
4517 0 : gphi *phi = gpi.phi ();
4518 0 : tree lhs = gimple_phi_result (phi);
4519 0 : tree rhs = gimple_phi_arg_def (phi, 0);
4520 0 : use_operand_p use_p;
4521 0 : imm_use_iterator iter;
4522 :
4523 0 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
4524 : {
4525 0 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
4526 0 : SET_USE (use_p, rhs);
4527 0 : }
4528 :
4529 0 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
4530 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs) = 1;
4531 :
4532 0 : remove_phi_node (&gpi, true);
4533 : }
4534 : }
4535 :
4536 898498 : if (dump_file && (dump_flags & TDF_DETAILS))
4537 0 : fprintf (dump_file, "Unsplit EH landing pad %d to block %i.\n",
4538 0 : lp->index, e_out->dest->index);
4539 :
4540 : /* Redirect the edge. Since redirect_eh_edge_1 expects to be moving
4541 : a successor edge, humor it. But do the real CFG change with the
4542 : predecessor of E_OUT in order to preserve the ordering of arguments
4543 : to the PHI nodes in E_OUT->DEST. */
4544 898498 : redirect_eh_edge_1 (e_in, e_out->dest, false);
4545 898498 : redirect_edge_pred (e_out, e_in->src);
4546 898498 : e_out->flags = e_in->flags;
4547 898498 : e_out->probability = e_in->probability;
4548 898498 : remove_edge (e_in);
4549 :
4550 898498 : return true;
4551 : }
4552 :
4553 : /* Examine each landing pad block and see if it matches unsplit_eh. */
4554 :
4555 : static bool
4556 567907 : unsplit_all_eh (void)
4557 : {
4558 567907 : bool changed = false;
4559 567907 : eh_landing_pad lp;
4560 567907 : int i;
4561 :
4562 3036630 : for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
4563 2468723 : if (lp)
4564 1755842 : changed |= unsplit_eh (lp);
4565 :
4566 567907 : return changed;
4567 : }
4568 :
4569 : /* Wrapper around unsplit_all_eh that makes it usable everywhere. */
4570 :
4571 : void
4572 241058 : unsplit_eh_edges (void)
4573 : {
4574 241058 : bool changed;
4575 :
4576 : /* unsplit_all_eh can die looking up unreachable landing pads. */
4577 241058 : maybe_remove_unreachable_handlers ();
4578 :
4579 241058 : changed = unsplit_all_eh ();
4580 :
4581 : /* If EH edges have been unsplit, delete unreachable forwarder blocks. */
4582 241058 : if (changed)
4583 : {
4584 9442 : free_dominance_info (CDI_DOMINATORS);
4585 9442 : free_dominance_info (CDI_POST_DOMINATORS);
4586 9442 : delete_unreachable_blocks ();
4587 : }
4588 241058 : }
4589 :
4590 : /* A subroutine of cleanup_empty_eh. Redirect all EH edges incoming
4591 : to OLD_BB to NEW_BB; return true on success, false on failure.
4592 :
4593 : OLD_BB_OUT is the edge into NEW_BB from OLD_BB, so if we miss any
4594 : PHI variables from OLD_BB we can pick them up from OLD_BB_OUT.
4595 : Virtual PHIs may be deleted and marked for renaming. */
4596 :
4597 : static bool
4598 275956 : cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
4599 : edge old_bb_out, bool change_region)
4600 : {
4601 275956 : gphi_iterator ngsi, ogsi;
4602 275956 : edge_iterator ei;
4603 275956 : edge e;
4604 275956 : bitmap ophi_handled;
4605 :
4606 : /* The destination block must not be a regular successor for any
4607 : of the preds of the landing pad. Thus, avoid turning
4608 : <..>
4609 : | \ EH
4610 : | <..>
4611 : | /
4612 : <..>
4613 : into
4614 : <..>
4615 : | | EH
4616 : <..>
4617 : which CFG verification would choke on. See PR45172 and PR51089. */
4618 275956 : if (!single_pred_p (new_bb))
4619 1086419 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4620 848587 : if (find_edge (e->src, new_bb))
4621 : return false;
4622 :
4623 1472275 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4624 1196329 : redirect_edge_var_map_clear (e);
4625 :
4626 275946 : ophi_handled = BITMAP_ALLOC (NULL);
4627 :
4628 : /* First, iterate through the PHIs on NEW_BB and set up the edge_var_map
4629 : for the edges we're going to move. */
4630 518509 : for (ngsi = gsi_start_phis (new_bb); !gsi_end_p (ngsi); gsi_next (&ngsi))
4631 : {
4632 242563 : gphi *ophi, *nphi = ngsi.phi ();
4633 242563 : tree nresult, nop;
4634 :
4635 242563 : nresult = gimple_phi_result (nphi);
4636 242563 : nop = gimple_phi_arg_def (nphi, old_bb_out->dest_idx);
4637 :
4638 : /* Find the corresponding PHI in OLD_BB so we can forward-propagate
4639 : the source ssa_name. */
4640 242563 : ophi = NULL;
4641 259871 : for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
4642 : {
4643 96671 : ophi = ogsi.phi ();
4644 96671 : if (gimple_phi_result (ophi) == nop)
4645 : break;
4646 17308 : ophi = NULL;
4647 : }
4648 :
4649 : /* If we did find the corresponding PHI, copy those inputs. */
4650 242563 : if (ophi)
4651 : {
4652 : /* If NOP is used somewhere else beyond phis in new_bb, give up. */
4653 79363 : if (!has_single_use (nop))
4654 : {
4655 16638 : imm_use_iterator imm_iter;
4656 16638 : use_operand_p use_p;
4657 :
4658 49987 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, nop)
4659 : {
4660 33349 : if (!gimple_debug_bind_p (USE_STMT (use_p))
4661 33349 : && (gimple_code (USE_STMT (use_p)) != GIMPLE_PHI
4662 33349 : || gimple_bb (USE_STMT (use_p)) != new_bb))
4663 0 : goto fail;
4664 16638 : }
4665 : }
4666 79363 : bitmap_set_bit (ophi_handled, SSA_NAME_VERSION (nop));
4667 747843 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4668 : {
4669 668480 : location_t oloc;
4670 668480 : tree oop;
4671 :
4672 668480 : if ((e->flags & EDGE_EH) == 0)
4673 2781 : continue;
4674 665699 : oop = gimple_phi_arg_def (ophi, e->dest_idx);
4675 665699 : oloc = gimple_phi_arg_location (ophi, e->dest_idx);
4676 665699 : redirect_edge_var_map_add (e, nresult, oop, oloc);
4677 : }
4678 : }
4679 : /* If we didn't find the PHI, if it's a real variable or a VOP, we know
4680 : from the fact that OLD_BB is tree_empty_eh_handler_p that the
4681 : variable is unchanged from input to the block and we can simply
4682 : re-use the input to NEW_BB from the OLD_BB_OUT edge. */
4683 : else
4684 : {
4685 163200 : location_t nloc
4686 163200 : = gimple_phi_arg_location (nphi, old_bb_out->dest_idx);
4687 426262 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4688 263062 : redirect_edge_var_map_add (e, nresult, nop, nloc);
4689 : }
4690 : }
4691 :
4692 : /* Second, verify that all PHIs from OLD_BB have been handled. If not,
4693 : we don't know what values from the other edges into NEW_BB to use. */
4694 355003 : for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
4695 : {
4696 100501 : gphi *ophi = ogsi.phi ();
4697 100501 : tree oresult = gimple_phi_result (ophi);
4698 100501 : if (!bitmap_bit_p (ophi_handled, SSA_NAME_VERSION (oresult)))
4699 21444 : goto fail;
4700 : }
4701 :
4702 : /* Finally, move the edges and update the PHIs. */
4703 1108203 : for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); )
4704 853701 : if (e->flags & EDGE_EH)
4705 : {
4706 : /* ??? CFG manipluation routines do not try to update loop
4707 : form on edge redirection. Do so manually here for now. */
4708 : /* If we redirect a loop entry or latch edge that will either create
4709 : a multiple entry loop or rotate the loop. If the loops merge
4710 : we may have created a loop with multiple latches.
4711 : All of this isn't easily fixed thus cancel the affected loop
4712 : and mark the other loop as possibly having multiple latches. */
4713 852571 : if (e->dest == e->dest->loop_father->header)
4714 : {
4715 0 : mark_loop_for_removal (e->dest->loop_father);
4716 0 : new_bb->loop_father->latch = NULL;
4717 0 : loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
4718 : }
4719 852571 : redirect_eh_edge_1 (e, new_bb, change_region);
4720 852571 : redirect_edge_succ (e, new_bb);
4721 852571 : flush_pending_stmts (e);
4722 : }
4723 : else
4724 1130 : ei_next (&ei);
4725 :
4726 254502 : BITMAP_FREE (ophi_handled);
4727 254502 : return true;
4728 :
4729 21444 : fail:
4730 364072 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4731 342628 : redirect_edge_var_map_clear (e);
4732 21444 : BITMAP_FREE (ophi_handled);
4733 21444 : return false;
4734 : }
4735 :
4736 : /* A subroutine of cleanup_empty_eh. Move a landing pad LP from its
4737 : old region to NEW_REGION at BB. */
4738 :
4739 : static void
4740 10380 : cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
4741 : eh_landing_pad lp, eh_region new_region)
4742 : {
4743 10380 : gimple_stmt_iterator gsi;
4744 10380 : eh_landing_pad *pp;
4745 :
4746 10380 : for (pp = &lp->region->landing_pads; *pp != lp; pp = &(*pp)->next_lp)
4747 0 : continue;
4748 10380 : *pp = lp->next_lp;
4749 :
4750 10380 : lp->region = new_region;
4751 10380 : lp->next_lp = new_region->landing_pads;
4752 10380 : new_region->landing_pads = lp;
4753 :
4754 : /* Delete the RESX that was matched within the empty handler block. */
4755 10380 : gsi = gsi_last_bb (bb);
4756 10380 : unlink_stmt_vdef (gsi_stmt (gsi));
4757 10380 : gsi_remove (&gsi, true);
4758 :
4759 : /* Clean up E_OUT for the fallthru. */
4760 10380 : e_out->flags = (e_out->flags & ~EDGE_EH) | EDGE_FALLTHRU;
4761 10380 : e_out->probability = profile_probability::always ();
4762 0 : }
4763 :
4764 : /* A subroutine of cleanup_empty_eh. Handle more complex cases of
4765 : unsplitting than unsplit_eh was prepared to handle, e.g. when
4766 : multiple incoming edges and phis are involved. */
4767 :
4768 : static bool
4769 14565 : cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
4770 : {
4771 14565 : gimple_stmt_iterator gsi;
4772 14565 : tree lab;
4773 :
4774 : /* We really ought not have totally lost everything following
4775 : a landing pad label. Given that BB is empty, there had better
4776 : be a successor. */
4777 14565 : gcc_assert (e_out != NULL);
4778 :
4779 : /* The destination block must not already have a landing pad
4780 : for a different region. */
4781 14565 : lab = NULL;
4782 42731 : for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
4783 : {
4784 28166 : glabel *stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
4785 13601 : int lp_nr;
4786 :
4787 13601 : if (!stmt)
4788 : break;
4789 13601 : lab = gimple_label_label (stmt);
4790 13601 : lp_nr = EH_LANDING_PAD_NR (lab);
4791 13601 : if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
4792 : return false;
4793 : }
4794 :
4795 : /* Attempt to move the PHIs into the successor block. */
4796 14565 : if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, false))
4797 : {
4798 4318 : if (dump_file && (dump_flags & TDF_DETAILS))
4799 0 : fprintf (dump_file,
4800 : "Unsplit EH landing pad %d to block %i "
4801 : "(via cleanup_empty_eh).\n",
4802 0 : lp->index, e_out->dest->index);
4803 : return true;
4804 : }
4805 :
4806 : return false;
4807 : }
4808 :
4809 : /* Return true if edge E_FIRST is part of an empty infinite loop
4810 : or leads to such a loop through a series of single successor
4811 : empty bbs. */
4812 :
4813 : static bool
4814 14615 : infinite_empty_loop_p (edge e_first)
4815 : {
4816 14615 : bool inf_loop = false;
4817 14615 : edge e;
4818 :
4819 14615 : if (e_first->dest == e_first->src)
4820 : return true;
4821 :
4822 14613 : e_first->src->aux = (void *) 1;
4823 14685 : for (e = e_first; single_succ_p (e->dest); e = single_succ_edge (e->dest))
4824 : {
4825 8195 : gimple_stmt_iterator gsi;
4826 8195 : if (e->dest->aux)
4827 : {
4828 : inf_loop = true;
4829 8123 : break;
4830 : }
4831 8147 : e->dest->aux = (void *) 1;
4832 8147 : gsi = gsi_after_labels (e->dest);
4833 8147 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4834 2904 : gsi_next_nondebug (&gsi);
4835 8147 : if (!gsi_end_p (gsi))
4836 : break;
4837 : }
4838 14613 : e_first->src->aux = NULL;
4839 22760 : for (e = e_first; e->dest->aux; e = single_succ_edge (e->dest))
4840 8147 : e->dest->aux = NULL;
4841 :
4842 : return inf_loop;
4843 : }
4844 :
4845 : /* Examine the block associated with LP to determine if it's an empty
4846 : handler for its EH region. If so, attempt to redirect EH edges to
4847 : an outer region. Return true the CFG was updated in any way. This
4848 : is similar to jump forwarding, just across EH edges. */
4849 :
4850 : static bool
4851 1417903 : cleanup_empty_eh (eh_landing_pad lp)
4852 : {
4853 1417903 : basic_block bb = label_to_block (cfun, lp->post_landing_pad);
4854 1417903 : gimple_stmt_iterator gsi;
4855 1417903 : gimple *resx;
4856 1417903 : eh_region new_region;
4857 1417903 : edge_iterator ei;
4858 1417903 : edge e, e_out;
4859 1417903 : bool has_non_eh_pred;
4860 1417903 : bool ret = false;
4861 1417903 : int new_lp_nr;
4862 :
4863 : /* There can be zero or one edges out of BB. This is the quickest test. */
4864 1417903 : switch (EDGE_COUNT (bb->succs))
4865 : {
4866 : case 0:
4867 : e_out = NULL;
4868 : break;
4869 736438 : case 1:
4870 736438 : e_out = single_succ_edge (bb);
4871 736438 : break;
4872 : default:
4873 : return false;
4874 : }
4875 :
4876 1296578 : gsi = gsi_last_nondebug_bb (bb);
4877 1296578 : resx = gsi_stmt (gsi);
4878 1296578 : if (resx && is_gimple_resx (resx))
4879 : {
4880 1142304 : if (stmt_can_throw_external (cfun, resx))
4881 558862 : optimize_clobbers (bb);
4882 583442 : else if (sink_clobbers (bb))
4883 1296578 : ret = true;
4884 : }
4885 :
4886 1296578 : gsi = gsi_after_labels (bb);
4887 :
4888 : /* Make sure to skip debug statements. */
4889 1296578 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4890 466933 : gsi_next_nondebug (&gsi);
4891 :
4892 : /* If the block is totally empty, look for more unsplitting cases. */
4893 1296578 : if (gsi_end_p (gsi))
4894 : {
4895 : /* For the degenerate case of an infinite loop bail out.
4896 : If bb has no successors and is totally empty, which can happen e.g.
4897 : because of incorrect noreturn attribute, bail out too. */
4898 14615 : if (e_out == NULL
4899 14615 : || infinite_empty_loop_p (e_out))
4900 : return ret;
4901 :
4902 14565 : return ret | cleanup_empty_eh_unsplit (bb, e_out, lp);
4903 : }
4904 :
4905 : /* The block should consist only of a single RESX statement, modulo a
4906 : preceding call to __builtin_stack_restore if there is no outgoing
4907 : edge, since the call can be eliminated in this case. */
4908 1281963 : resx = gsi_stmt (gsi);
4909 1281963 : if (!e_out && gimple_call_builtin_p (resx, BUILT_IN_STACK_RESTORE))
4910 : {
4911 318 : gsi_next_nondebug (&gsi);
4912 318 : resx = gsi_stmt (gsi);
4913 : }
4914 1281963 : if (!is_gimple_resx (resx))
4915 : return ret;
4916 592454 : gcc_assert (gsi_one_nondebug_before_end_p (gsi));
4917 :
4918 : /* Determine if there are non-EH edges, or resx edges into the handler. */
4919 592454 : has_non_eh_pred = false;
4920 3289500 : FOR_EACH_EDGE (e, ei, bb->preds)
4921 2697046 : if (!(e->flags & EDGE_EH))
4922 5677 : has_non_eh_pred = true;
4923 :
4924 : /* Find the handler that's outer of the empty handler by looking at
4925 : where the RESX instruction was vectored. */
4926 592454 : new_lp_nr = lookup_stmt_eh_lp (resx);
4927 592454 : new_region = get_eh_region_from_lp_number (new_lp_nr);
4928 :
4929 : /* If there's no destination region within the current function,
4930 : redirection is trivial via removing the throwing statements from
4931 : the EH region, removing the EH edges, and allowing the block
4932 : to go unreachable. */
4933 592454 : if (new_region == NULL)
4934 : {
4935 331058 : gcc_assert (e_out == NULL);
4936 2024731 : for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
4937 1693673 : if (e->flags & EDGE_EH)
4938 : {
4939 1691298 : gimple *stmt = *gsi_last_bb (e->src);
4940 1691298 : remove_stmt_from_eh_lp (stmt);
4941 1691298 : remove_edge (e);
4942 : }
4943 : else
4944 2375 : ei_next (&ei);
4945 331058 : goto succeed;
4946 : }
4947 :
4948 : /* If the destination region is a MUST_NOT_THROW, allow the runtime
4949 : to handle the abort and allow the blocks to go unreachable. */
4950 261396 : if (new_region->type == ERT_MUST_NOT_THROW)
4951 : {
4952 11 : for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
4953 6 : if (e->flags & EDGE_EH)
4954 : {
4955 6 : gimple *stmt = *gsi_last_bb (e->src);
4956 6 : remove_stmt_from_eh_lp (stmt);
4957 6 : add_stmt_to_eh_lp (stmt, new_lp_nr);
4958 6 : remove_edge (e);
4959 : }
4960 : else
4961 0 : ei_next (&ei);
4962 5 : goto succeed;
4963 : }
4964 :
4965 : /* Try to redirect the EH edges and merge the PHIs into the destination
4966 : landing pad block. If the merge succeeds, we'll already have redirected
4967 : all the EH edges. The handler itself will go unreachable if there were
4968 : no normal edges. */
4969 261391 : if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, true))
4970 250184 : goto succeed;
4971 :
4972 : /* Finally, if all input edges are EH edges, then we can (potentially)
4973 : reduce the number of transfers from the runtime by moving the landing
4974 : pad from the original region to the new region. This is a win when
4975 : we remove the last CLEANUP region along a particular exception
4976 : propagation path. Since nothing changes except for the region with
4977 : which the landing pad is associated, the PHI nodes do not need to be
4978 : adjusted at all. */
4979 11207 : if (!has_non_eh_pred)
4980 : {
4981 10380 : cleanup_empty_eh_move_lp (bb, e_out, lp, new_region);
4982 10380 : if (dump_file && (dump_flags & TDF_DETAILS))
4983 0 : fprintf (dump_file, "Empty EH handler %i moved to EH region %i.\n",
4984 : lp->index, new_region->index);
4985 :
4986 : /* ??? The CFG didn't change, but we may have rendered the
4987 : old EH region unreachable. Trigger a cleanup there. */
4988 : return true;
4989 : }
4990 :
4991 : return ret;
4992 :
4993 581247 : succeed:
4994 581247 : if (dump_file && (dump_flags & TDF_DETAILS))
4995 6 : fprintf (dump_file, "Empty EH handler %i removed.\n", lp->index);
4996 581247 : remove_eh_landing_pad (lp);
4997 581247 : return true;
4998 : }
4999 :
5000 : /* Do a post-order traversal of the EH region tree. Examine each
5001 : post_landing_pad block and see if we can eliminate it as empty. */
5002 :
5003 : static bool
5004 355720 : cleanup_all_empty_eh (void)
5005 : {
5006 355720 : bool changed = false;
5007 355720 : eh_landing_pad lp;
5008 355720 : int i;
5009 :
5010 : /* The post-order traversal may lead to quadraticness in the redirection
5011 : of incoming EH edges from inner LPs, so first try to walk the region
5012 : tree from inner to outer LPs in order to eliminate these edges. */
5013 2803145 : for (i = vec_safe_length (cfun->eh->lp_array) - 1; i >= 1; --i)
5014 : {
5015 2091705 : lp = (*cfun->eh->lp_array)[i];
5016 2091705 : if (lp)
5017 1001026 : changed |= cleanup_empty_eh (lp);
5018 : }
5019 :
5020 : /* Now do the post-order traversal to eliminate outer empty LPs. */
5021 2448045 : for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
5022 2092325 : if (lp)
5023 416877 : changed |= cleanup_empty_eh (lp);
5024 :
5025 355720 : return changed;
5026 : }
5027 :
5028 : /* Perform cleanups and lowering of exception handling
5029 : 1) cleanups regions with handlers doing nothing are optimized out
5030 : 2) MUST_NOT_THROW regions that became dead because of 1) are optimized out
5031 : 3) Info about regions that are containing instructions, and regions
5032 : reachable via local EH edges is collected
5033 : 4) Eh tree is pruned for regions no longer necessary.
5034 :
5035 : TODO: Push MUST_NOT_THROW regions to the root of the EH tree.
5036 : Unify those that have the same failure decl and locus.
5037 : */
5038 :
5039 : static unsigned int
5040 1171725 : execute_cleanup_eh_1 (void)
5041 : {
5042 : /* Do this first: unsplit_all_eh and cleanup_all_empty_eh can die
5043 : looking up unreachable landing pads. */
5044 1171725 : remove_unreachable_handlers ();
5045 :
5046 : /* Watch out for the region tree vanishing due to all unreachable. */
5047 1171725 : if (cfun->eh->region_tree)
5048 : {
5049 355720 : bool changed = false;
5050 :
5051 355720 : if (optimize)
5052 326849 : changed |= unsplit_all_eh ();
5053 355720 : changed |= cleanup_all_empty_eh ();
5054 :
5055 355720 : if (changed)
5056 : {
5057 296087 : free_dominance_info (CDI_DOMINATORS);
5058 296087 : free_dominance_info (CDI_POST_DOMINATORS);
5059 :
5060 : /* We delayed all basic block deletion, as we may have performed
5061 : cleanups on EH edges while non-EH edges were still present. */
5062 296087 : delete_unreachable_blocks ();
5063 :
5064 : /* We manipulated the landing pads. Remove any region that no
5065 : longer has a landing pad. */
5066 296087 : remove_unreachable_handlers_no_lp ();
5067 :
5068 296087 : return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
5069 : }
5070 : }
5071 :
5072 : return 0;
5073 : }
5074 :
5075 : namespace {
5076 :
5077 : const pass_data pass_data_cleanup_eh =
5078 : {
5079 : GIMPLE_PASS, /* type */
5080 : "ehcleanup", /* name */
5081 : OPTGROUP_NONE, /* optinfo_flags */
5082 : TV_TREE_EH, /* tv_id */
5083 : PROP_gimple_lcf, /* properties_required */
5084 : 0, /* properties_provided */
5085 : 0, /* properties_destroyed */
5086 : 0, /* todo_flags_start */
5087 : 0, /* todo_flags_finish */
5088 : };
5089 :
5090 : class pass_cleanup_eh : public gimple_opt_pass
5091 : {
5092 : public:
5093 589174 : pass_cleanup_eh (gcc::context *ctxt)
5094 1178348 : : gimple_opt_pass (pass_data_cleanup_eh, ctxt)
5095 : {}
5096 :
5097 : /* opt_pass methods: */
5098 294587 : opt_pass * clone () final override { return new pass_cleanup_eh (m_ctxt); }
5099 4057056 : bool gate (function *fun) final override
5100 : {
5101 4057056 : return fun->eh != NULL && fun->eh->region_tree != NULL;
5102 : }
5103 :
5104 : unsigned int execute (function *) final override;
5105 :
5106 : }; // class pass_cleanup_eh
5107 :
5108 : unsigned int
5109 1171725 : pass_cleanup_eh::execute (function *fun)
5110 : {
5111 1171725 : int ret = execute_cleanup_eh_1 ();
5112 :
5113 : /* If the function no longer needs an EH personality routine
5114 : clear it. This exposes cross-language inlining opportunities
5115 : and avoids references to a never defined personality routine. */
5116 1171725 : if (DECL_FUNCTION_PERSONALITY (current_function_decl)
5117 1171725 : && function_needs_eh_personality (fun) != eh_personality_lang)
5118 779436 : DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;
5119 :
5120 1171725 : return ret;
5121 : }
5122 :
5123 : } // anon namespace
5124 :
5125 : gimple_opt_pass *
5126 294587 : make_pass_cleanup_eh (gcc::context *ctxt)
5127 : {
5128 294587 : return new pass_cleanup_eh (ctxt);
5129 : }
5130 :
5131 : /* Disable warnings about missing quoting in GCC diagnostics for
5132 : the verification errors. Their format strings don't follow GCC
5133 : diagnostic conventions but are only used for debugging. */
5134 : #if __GNUC__ >= 10
5135 : # pragma GCC diagnostic push
5136 : # pragma GCC diagnostic ignored "-Wformat-diag"
5137 : #endif
5138 :
5139 : /* Verify that BB containing STMT as the last statement, has precisely the
5140 : edge that make_eh_edge would create. */
5141 :
5142 : DEBUG_FUNCTION bool
5143 1857332228 : verify_eh_edges (gimple *stmt)
5144 : {
5145 1857332228 : basic_block bb = gimple_bb (stmt);
5146 1857332228 : eh_landing_pad lp = NULL;
5147 1857332228 : int lp_nr;
5148 1857332228 : edge_iterator ei;
5149 1857332228 : edge e, eh_edge;
5150 :
5151 1857332228 : lp_nr = lookup_stmt_eh_lp (stmt);
5152 1857332228 : if (lp_nr > 0)
5153 199025520 : lp = get_eh_landing_pad_from_number (lp_nr);
5154 :
5155 1857332228 : eh_edge = NULL;
5156 4514808175 : FOR_EACH_EDGE (e, ei, bb->succs)
5157 : {
5158 2657475947 : if (e->flags & EDGE_EH)
5159 : {
5160 199025520 : if (eh_edge)
5161 : {
5162 0 : error ("BB %i has multiple EH edges", bb->index);
5163 0 : return true;
5164 : }
5165 : else
5166 : eh_edge = e;
5167 : }
5168 : }
5169 :
5170 1857332228 : if (lp == NULL)
5171 : {
5172 1658306708 : if (eh_edge)
5173 : {
5174 0 : error ("BB %i cannot throw but has an EH edge", bb->index);
5175 0 : return true;
5176 : }
5177 : return false;
5178 : }
5179 :
5180 199025520 : if (!stmt_could_throw_p (cfun, stmt))
5181 : {
5182 0 : error ("BB %i last statement has incorrectly set lp", bb->index);
5183 0 : return true;
5184 : }
5185 :
5186 199025520 : if (eh_edge == NULL)
5187 : {
5188 0 : error ("BB %i is missing an EH edge", bb->index);
5189 0 : return true;
5190 : }
5191 :
5192 199025520 : if (eh_edge->dest != label_to_block (cfun, lp->post_landing_pad))
5193 : {
5194 0 : error ("Incorrect EH edge %i->%i", bb->index, eh_edge->dest->index);
5195 0 : return true;
5196 : }
5197 :
5198 : return false;
5199 : }
5200 :
5201 : /* Similarly, but handle GIMPLE_EH_DISPATCH specifically. */
5202 :
5203 : DEBUG_FUNCTION bool
5204 1932358 : verify_eh_dispatch_edge (geh_dispatch *stmt)
5205 : {
5206 1932358 : eh_region r;
5207 1932358 : eh_catch c;
5208 1932358 : basic_block src, dst;
5209 1932358 : bool want_fallthru = true;
5210 1932358 : edge_iterator ei;
5211 1932358 : edge e, fall_edge;
5212 :
5213 1932358 : r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
5214 1932358 : src = gimple_bb (stmt);
5215 :
5216 4146215 : FOR_EACH_EDGE (e, ei, src->succs)
5217 2213857 : gcc_assert (e->aux == NULL);
5218 :
5219 1932358 : switch (r->type)
5220 : {
5221 1923268 : case ERT_TRY:
5222 2195677 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
5223 : {
5224 2039441 : dst = label_to_block (cfun, c->label);
5225 2039441 : e = find_edge (src, dst);
5226 2039441 : if (e == NULL)
5227 : {
5228 0 : error ("BB %i is missing an edge", src->index);
5229 0 : return true;
5230 : }
5231 2039441 : e->aux = (void *)e;
5232 :
5233 : /* A catch-all handler doesn't have a fallthru. */
5234 2039441 : if (c->type_list == NULL)
5235 : {
5236 : want_fallthru = false;
5237 : break;
5238 : }
5239 : }
5240 : break;
5241 :
5242 9090 : case ERT_ALLOWED_EXCEPTIONS:
5243 9090 : dst = label_to_block (cfun, r->u.allowed.label);
5244 9090 : e = find_edge (src, dst);
5245 9090 : if (e == NULL)
5246 : {
5247 0 : error ("BB %i is missing an edge", src->index);
5248 0 : return true;
5249 : }
5250 9090 : e->aux = (void *)e;
5251 9090 : break;
5252 :
5253 0 : default:
5254 0 : gcc_unreachable ();
5255 : }
5256 :
5257 1932358 : fall_edge = NULL;
5258 4146215 : FOR_EACH_EDGE (e, ei, src->succs)
5259 : {
5260 2213857 : if (e->flags & EDGE_FALLTHRU)
5261 : {
5262 165326 : if (fall_edge != NULL)
5263 : {
5264 0 : error ("BB %i too many fallthru edges", src->index);
5265 0 : return true;
5266 : }
5267 : fall_edge = e;
5268 : }
5269 2048531 : else if (e->aux)
5270 2048531 : e->aux = NULL;
5271 : else
5272 : {
5273 0 : error ("BB %i has incorrect edge", src->index);
5274 0 : return true;
5275 : }
5276 : }
5277 1932358 : if ((fall_edge != NULL) ^ want_fallthru)
5278 : {
5279 0 : error ("BB %i has incorrect fallthru edge", src->index);
5280 0 : return true;
5281 : }
5282 :
5283 : return false;
5284 : }
5285 :
5286 : #if __GNUC__ >= 10
5287 : # pragma GCC diagnostic pop
5288 : #endif
|