Branch data Line data Source code
1 : : /* Exception handling semantics and decomposition for trees.
2 : : Copyright (C) 2003-2025 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 : 6805971 : add_stmt_to_eh_lp_fn (struct function *ifun, gimple *t, int num)
73 : : {
74 : 6805971 : gcc_assert (num != 0);
75 : :
76 : 6805971 : if (!get_eh_throw_stmt_table (ifun))
77 : 401330 : set_eh_throw_stmt_table (ifun, hash_map<gimple *, int>::create_ggc (31));
78 : :
79 : 6805971 : bool existed = get_eh_throw_stmt_table (ifun)->put (t, num);
80 : 6805971 : gcc_assert (!existed);
81 : 6805971 : }
82 : :
83 : : /* Add statement T in the current function (cfun) to EH landing pad NUM. */
84 : :
85 : : void
86 : 2787862 : add_stmt_to_eh_lp (gimple *t, int num)
87 : : {
88 : 2787862 : add_stmt_to_eh_lp_fn (cfun, t, num);
89 : 2787862 : }
90 : :
91 : : /* Add statement T to the single EH landing pad in REGION. */
92 : :
93 : : static void
94 : 3234127 : record_stmt_eh_region (eh_region region, gimple *t)
95 : : {
96 : 3234127 : if (region == NULL)
97 : : return;
98 : 3234127 : if (region->type == ERT_MUST_NOT_THROW)
99 : 91383 : add_stmt_to_eh_lp_fn (cfun, t, -region->index);
100 : : else
101 : : {
102 : 3142744 : eh_landing_pad lp = region->landing_pads;
103 : 3142744 : if (lp == NULL)
104 : 889755 : lp = gen_eh_landing_pad (region);
105 : : else
106 : 2252989 : gcc_assert (lp->next_lp == NULL);
107 : 3142744 : 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 : 294696291 : remove_stmt_from_eh_lp_fn (struct function *ifun, gimple *t)
116 : : {
117 : 294696291 : if (!get_eh_throw_stmt_table (ifun))
118 : : return false;
119 : :
120 : 136024797 : if (!get_eh_throw_stmt_table (ifun)->get (t))
121 : : return false;
122 : :
123 : 5931961 : get_eh_throw_stmt_table (ifun)->remove (t);
124 : 5931961 : return true;
125 : : }
126 : :
127 : :
128 : : /* Remove statement T in the current function (cfun) from its
129 : : EH landing pad. */
130 : :
131 : : bool
132 : 120533834 : remove_stmt_from_eh_lp (gimple *t)
133 : : {
134 : 120533834 : 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 : 15474408073 : lookup_stmt_eh_lp_fn (struct function *ifun, const gimple *t)
144 : : {
145 : 15474408073 : if (ifun->eh->throw_stmt_table == NULL)
146 : : return 0;
147 : :
148 : 8437087644 : int *lp_nr = ifun->eh->throw_stmt_table->get (const_cast <gimple *> (t));
149 : 8437087644 : return lp_nr ? *lp_nr : 0;
150 : : }
151 : :
152 : : /* Likewise, but always use the current function. */
153 : :
154 : : int
155 : 14801443625 : 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 : 14801443625 : if (!cfun)
160 : : return 0;
161 : 14801443625 : 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 : 149213862 : finally_tree_hasher::hash (const finally_tree_node *v)
189 : : {
190 : 149213862 : return (intptr_t)v->child.t >> 4;
191 : : }
192 : :
193 : : inline bool
194 : 132868629 : finally_tree_hasher::equal (const finally_tree_node *v,
195 : : const finally_tree_node *c)
196 : : {
197 : 132868629 : 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 : 18195228 : record_in_finally_tree (treemple child, gtry *parent)
205 : : {
206 : 18195228 : struct finally_tree_node *n;
207 : 18195228 : finally_tree_node **slot;
208 : :
209 : 18195228 : n = XNEW (struct finally_tree_node);
210 : 18195228 : n->child = child;
211 : 18195228 : n->parent = parent;
212 : :
213 : 18195228 : slot = finally_tree->find_slot (n, INSERT);
214 : 18195228 : gcc_assert (!*slot);
215 : 18195228 : *slot = n;
216 : 18195228 : }
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 : 9157610 : collect_finally_tree_1 (gimple_seq seq, gtry *region)
226 : : {
227 : 9157610 : gimple_stmt_iterator gsi;
228 : :
229 : 99430703 : for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
230 : 90273093 : collect_finally_tree (gsi_stmt (gsi), region);
231 : 5143187 : }
232 : :
233 : : static void
234 : 90273093 : collect_finally_tree (gimple *stmt, gtry *region)
235 : : {
236 : 90273093 : treemple temp;
237 : :
238 : 90273093 : switch (gimple_code (stmt))
239 : : {
240 : 16465410 : case GIMPLE_LABEL:
241 : 16465410 : temp.t = gimple_label_label (as_a <glabel *> (stmt));
242 : 16465410 : record_in_finally_tree (temp, region);
243 : 16465410 : break;
244 : :
245 : 2540008 : case GIMPLE_TRY:
246 : 2540008 : if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
247 : : {
248 : 1673838 : temp.g = stmt;
249 : 1673838 : record_in_finally_tree (temp, region);
250 : 1673838 : collect_finally_tree_1 (gimple_try_eval (stmt),
251 : : as_a <gtry *> (stmt));
252 : 1673838 : collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
253 : : }
254 : 866170 : else if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
255 : : {
256 : 866170 : collect_finally_tree_1 (gimple_try_eval (stmt), region);
257 : 866170 : collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
258 : : }
259 : : break;
260 : :
261 : 57167 : case GIMPLE_CATCH:
262 : 114334 : collect_finally_tree_1 (gimple_catch_handler (
263 : 57167 : as_a <gcatch *> (stmt)),
264 : : region);
265 : 57167 : break;
266 : :
267 : 4732 : case GIMPLE_EH_FILTER:
268 : 4732 : collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
269 : 4732 : break;
270 : :
271 : 636 : case GIMPLE_EH_ELSE:
272 : 636 : {
273 : 636 : geh_else *eh_else_stmt = as_a <geh_else *> (stmt);
274 : 636 : collect_finally_tree_1 (gimple_eh_else_n_body (eh_else_stmt), region);
275 : 636 : collect_finally_tree_1 (gimple_eh_else_e_body (eh_else_stmt), region);
276 : : }
277 : 636 : 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 : 90273093 : }
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 : 8950310 : outside_finally_tree (treemple start, gimple *target)
292 : : {
293 : 9680809 : struct finally_tree_node n, *p;
294 : :
295 : 9680809 : do
296 : : {
297 : 9680809 : n.child = start;
298 : 9680809 : p = finally_tree->find (&n);
299 : 9680809 : if (!p)
300 : : return true;
301 : 8985640 : start.g = p->parent;
302 : : }
303 : 8985640 : 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 : 7143559 : find_goto_replacement (struct leh_tf_state *tf, treemple stmt)
423 : : {
424 : 7143559 : unsigned int i;
425 : :
426 : 7143559 : if (tf->goto_queue_active < LARGE_GOTO_QUEUE)
427 : : {
428 : 21329856 : for (i = 0; i < tf->goto_queue_active; i++)
429 : 14952861 : if ( tf->goto_queue[i].stmt.g == stmt.g)
430 : 686154 : 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 : 80410 : if (!tf->goto_queue_map)
438 : : {
439 : 329 : tf->goto_queue_map = new hash_map<gimple *, goto_queue_node *>;
440 : 9344 : for (i = 0; i < tf->goto_queue_active; i++)
441 : : {
442 : 18030 : bool existed = tf->goto_queue_map->put (tf->goto_queue[i].stmt.g,
443 : 9015 : &tf->goto_queue[i]);
444 : 9015 : gcc_assert (!existed);
445 : : }
446 : : }
447 : :
448 : 80410 : goto_queue_node **slot = tf->goto_queue_map->get (stmt.g);
449 : 80410 : if (slot != NULL)
450 : 9015 : 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 : 4520766 : replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
462 : : gimple_stmt_iterator *gsi)
463 : : {
464 : 4520766 : tree label;
465 : 4520766 : gimple_seq new_seq;
466 : 4520766 : treemple temp;
467 : 4520766 : location_t loc = gimple_location (gsi_stmt (*gsi));
468 : :
469 : 4520766 : temp.tp = tp;
470 : 4520766 : new_seq = find_goto_replacement (tf, temp);
471 : 4520766 : if (!new_seq)
472 : 4520691 : return;
473 : :
474 : 1853 : if (gimple_seq_singleton_p (new_seq)
475 : 1778 : && gimple_code (gimple_seq_first_stmt (new_seq)) == GIMPLE_GOTO)
476 : : {
477 : 1778 : *tp = gimple_goto_dest (gimple_seq_first_stmt (new_seq));
478 : 1778 : return;
479 : : }
480 : :
481 : 75 : label = create_artificial_label (loc);
482 : : /* Set the new label for the GIMPLE_COND */
483 : 75 : *tp = label;
484 : :
485 : 75 : gsi_insert_after (gsi, gimple_build_label (label), GSI_CONTINUE_LINKING);
486 : 75 : 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 : 35818552 : replace_goto_queue_1 (gimple *stmt, struct leh_tf_state *tf,
496 : : gimple_stmt_iterator *gsi)
497 : : {
498 : 35818552 : gimple_seq seq;
499 : 35818552 : treemple temp;
500 : 35818552 : temp.g = NULL;
501 : :
502 : 35818552 : switch (gimple_code (stmt))
503 : : {
504 : 2622658 : case GIMPLE_GOTO:
505 : 2622658 : case GIMPLE_RETURN:
506 : 2622658 : temp.g = stmt;
507 : 2622658 : seq = find_goto_replacement (tf, temp);
508 : 2622658 : if (seq)
509 : : {
510 : 693281 : gimple_stmt_iterator i;
511 : 693281 : seq = gimple_seq_copy (seq);
512 : 1387795 : for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
513 : 1232583 : gimple_set_location (gsi_stmt (i), gimple_location (stmt));
514 : 693281 : gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
515 : 693281 : gsi_remove (gsi, false);
516 : 693281 : return;
517 : : }
518 : : break;
519 : :
520 : 12866 : case GIMPLE_ASM:
521 : 12866 : if (int n = gimple_asm_nlabels (as_a <gasm *> (stmt)))
522 : : {
523 : 79 : temp.g = stmt;
524 : 79 : gasm *asm_stmt = as_a <gasm *> (stmt);
525 : 79 : location_t loc = gimple_location (stmt);
526 : 79 : tree bypass_label = NULL_TREE;
527 : 214 : for (int i = 0; i < n; ++i)
528 : : {
529 : 135 : tree elt = gimple_asm_label_op (asm_stmt, i);
530 : 135 : temp.tp = &TREE_VALUE (elt);
531 : 135 : seq = find_goto_replacement (tf, temp);
532 : 135 : if (!seq)
533 : 100 : 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 : 79 : if (bypass_label)
557 : 3 : gsi_insert_after (gsi, gimple_build_label (bypass_label),
558 : : GSI_CONTINUE_LINKING);
559 : : }
560 : : break;
561 : :
562 : 2260383 : case GIMPLE_COND:
563 : 2260383 : replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 2), tf, gsi);
564 : 2260383 : replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 3), tf, gsi);
565 : 2260383 : 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 : 35125271 : gsi_next (gsi);
595 : : }
596 : :
597 : : /* A subroutine of replace_goto_queue. Handles GIMPLE_SEQ. */
598 : :
599 : : static void
600 : 1046082 : replace_goto_queue_stmt_list (gimple_seq *seq, struct leh_tf_state *tf)
601 : : {
602 : 1046082 : gimple_stmt_iterator gsi = gsi_start (*seq);
603 : :
604 : 36864634 : while (!gsi_end_p (gsi))
605 : 35818552 : replace_goto_queue_1 (gsi_stmt (gsi), tf, &gsi);
606 : 1046082 : }
607 : :
608 : : /* Replace all goto queue members. */
609 : :
610 : : static void
611 : 525743 : replace_goto_queue (struct leh_tf_state *tf)
612 : : {
613 : 525743 : if (tf->goto_queue_active == 0)
614 : : return;
615 : 523041 : replace_goto_queue_stmt_list (&tf->top_p_seq, tf);
616 : 523041 : 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 : 695169 : 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 : 695169 : size_t active, size;
631 : 695169 : struct goto_queue_node *q;
632 : :
633 : 695169 : gcc_assert (!tf->goto_queue_map);
634 : :
635 : 695169 : active = tf->goto_queue_active;
636 : 695169 : size = tf->goto_queue_size;
637 : 695169 : if (active >= size)
638 : : {
639 : 523076 : size = (size ? size * 2 : 32);
640 : 523076 : tf->goto_queue_size = size;
641 : 523076 : tf->goto_queue
642 : 523076 : = XRESIZEVEC (struct goto_queue_node, tf->goto_queue, size);
643 : : }
644 : :
645 : 695169 : q = &tf->goto_queue[active];
646 : 695169 : tf->goto_queue_active = active + 1;
647 : :
648 : 695169 : memset (q, 0, sizeof (*q));
649 : 695169 : q->stmt = new_stmt;
650 : 695169 : q->index = index;
651 : 695169 : q->location = location;
652 : 695169 : q->is_label = is_label;
653 : 695169 : }
654 : :
655 : : /* Record the LABEL label in the goto queue contained in TF.
656 : : TF is not null. */
657 : :
658 : : static void
659 : 8721839 : record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label,
660 : : location_t location)
661 : : {
662 : 8721839 : int index;
663 : 8721839 : treemple temp, new_stmt;
664 : :
665 : 8721839 : if (!label)
666 : 8026670 : 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 : 8721839 : if (TREE_CODE (label) != LABEL_DECL)
672 : : return;
673 : :
674 : : /* No need to record gotos that don't leave the try block. */
675 : 8721607 : temp.t = label;
676 : 8721607 : if (!outside_finally_tree (temp, tf->try_finally_expr))
677 : : return;
678 : :
679 : 695169 : if (! tf->dest_array.exists ())
680 : : {
681 : 523041 : tf->dest_array.create (10);
682 : 523041 : tf->dest_array.quick_push (label);
683 : 523041 : index = 0;
684 : : }
685 : : else
686 : : {
687 : 172128 : int n = tf->dest_array.length ();
688 : 189343 : for (index = 0; index < n; ++index)
689 : 185075 : if (tf->dest_array[index] == label)
690 : : break;
691 : 172128 : if (index == n)
692 : 4268 : 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 : 695169 : new_stmt = stmt;
699 : 695169 : 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 : 14587859 : maybe_record_in_goto_queue (struct leh_state *state, gimple *stmt)
708 : : {
709 : 14587859 : struct leh_tf_state *tf = state->tf;
710 : 14587859 : treemple new_stmt;
711 : :
712 : 14587859 : if (!tf)
713 : 14587859 : return;
714 : :
715 : 5731108 : switch (gimple_code (stmt))
716 : : {
717 : 3006539 : case GIMPLE_COND:
718 : 3006539 : {
719 : 3006539 : gcond *cond_stmt = as_a <gcond *> (stmt);
720 : 3006539 : new_stmt.tp = gimple_op_ptr (cond_stmt, 2);
721 : 3006539 : record_in_goto_queue_label (tf, new_stmt,
722 : : gimple_cond_true_label (cond_stmt),
723 : 3006539 : EXPR_LOCATION (*new_stmt.tp));
724 : 3006539 : 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 : 3006539 : EXPR_LOCATION (*new_stmt.tp));
728 : : }
729 : 3006539 : break;
730 : :
731 : 2708707 : case GIMPLE_GOTO:
732 : 2708707 : new_stmt.g = stmt;
733 : 2708707 : record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt),
734 : : gimple_location (stmt));
735 : 2708707 : break;
736 : :
737 : 15862 : case GIMPLE_ASM:
738 : 15862 : if (int n = gimple_asm_nlabels (as_a <gasm *> (stmt)))
739 : : {
740 : 94 : new_stmt.g = stmt;
741 : : gasm *asm_stmt = as_a <gasm *> (stmt);
742 : 94 : for (int i = 0; i < n; ++i)
743 : : {
744 : 54 : tree elt = gimple_asm_label_op (asm_stmt, i);
745 : 54 : new_stmt.tp = &TREE_VALUE (elt);
746 : 54 : 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 : 52211 : verify_norecord_switch_expr (struct leh_state *state,
771 : : gswitch *switch_expr)
772 : : {
773 : 52211 : struct leh_tf_state *tf = state->tf;
774 : 52211 : size_t i, n;
775 : :
776 : 52211 : if (!tf)
777 : : return;
778 : :
779 : 30513 : n = gimple_switch_num_labels (switch_expr);
780 : :
781 : 259216 : for (i = 0; i < n; ++i)
782 : : {
783 : 228703 : treemple temp;
784 : 228703 : tree lab = CASE_LABEL (gimple_switch_label (switch_expr, i));
785 : 228703 : temp.t = lab;
786 : 228703 : 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 : 695169 : do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
835 : : struct leh_tf_state *tf)
836 : : {
837 : 695169 : ggoto *x;
838 : :
839 : 695169 : gcc_assert (q->is_label);
840 : :
841 : 695169 : q->cont_stmt = gimple_build_goto (tf->dest_array[q->index]);
842 : :
843 : 695169 : if (mod)
844 : 1313 : gimple_seq_add_seq (&q->repl_stmt, mod);
845 : :
846 : 695169 : x = gimple_build_goto (finlab);
847 : 695169 : gimple_set_location (x, q->location);
848 : 695169 : gimple_seq_add_stmt (&q->repl_stmt, x);
849 : 695169 : }
850 : :
851 : : /* Emit a standard landing pad sequence into SEQ for REGION. */
852 : :
853 : : static void
854 : 889755 : emit_post_landing_pad (gimple_seq *seq, eh_region region)
855 : : {
856 : 889755 : eh_landing_pad lp = region->landing_pads;
857 : 889755 : glabel *x;
858 : :
859 : 889755 : if (lp == NULL)
860 : 0 : lp = gen_eh_landing_pad (region);
861 : :
862 : 889755 : lp->post_landing_pad = create_artificial_label (UNKNOWN_LOCATION);
863 : 889755 : EH_LANDING_PAD_NR (lp->post_landing_pad) = lp->index;
864 : :
865 : 889755 : x = gimple_build_label (lp->post_landing_pad);
866 : 889755 : gimple_seq_add_stmt (seq, x);
867 : 889755 : }
868 : :
869 : : /* Emit a RESX statement into SEQ for REGION. */
870 : :
871 : : static void
872 : 889753 : emit_resx (gimple_seq *seq, eh_region region)
873 : : {
874 : 889753 : gresx *x = gimple_build_resx (region->index);
875 : 889753 : gimple_seq_add_stmt (seq, x);
876 : 889753 : if (region->outer)
877 : 525322 : record_stmt_eh_region (region->outer, x);
878 : 889753 : }
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 : 2708805 : note_eh_region_may_contain_throw (eh_region region)
885 : : {
886 : 3234127 : while (bitmap_set_bit (eh_region_may_contain_throw_map, region->index))
887 : : {
888 : 963710 : if (region->type == ERT_MUST_NOT_THROW)
889 : : break;
890 : 889755 : region = region->outer;
891 : 889755 : if (region == NULL)
892 : : break;
893 : : }
894 : 2708805 : }
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 : 1297683 : eh_region_may_contain_throw (eh_region r)
901 : : {
902 : 1297683 : 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 : 41672 : frob_into_branch_around (gtry *tp, eh_region region, tree over)
922 : : {
923 : 41672 : gimple *x;
924 : 41672 : gimple_seq cleanup, result;
925 : 41672 : location_t loc = gimple_location (tp);
926 : :
927 : 41672 : cleanup = gimple_try_cleanup (tp);
928 : 41672 : result = gimple_try_eval (tp);
929 : :
930 : 41672 : if (region)
931 : 41672 : emit_post_landing_pad (&eh_seq, region);
932 : :
933 : 41672 : 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 : 41672 : gimple_seq_add_seq (&eh_seq, cleanup);
942 : :
943 : 41672 : if (over)
944 : : {
945 : 13193 : x = gimple_build_label (over);
946 : 13193 : gimple_seq_add_stmt (&result, x);
947 : : }
948 : 41672 : 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 : 1052407 : lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state,
956 : : location_t loc)
957 : : {
958 : 1052407 : gtry *region = NULL;
959 : 1052407 : gimple_seq new_seq;
960 : 1052407 : gimple_stmt_iterator gsi;
961 : :
962 : 1052407 : new_seq = copy_gimple_seq_and_replace_locals (seq);
963 : :
964 : 2543434 : for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
965 : : {
966 : 1491027 : gimple *stmt = gsi_stmt (gsi);
967 : 1491027 : if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
968 : : {
969 : 977489 : tree block = gimple_block (stmt);
970 : 977489 : gimple_set_location (stmt, loc);
971 : 977489 : gimple_set_block (stmt, block);
972 : : }
973 : : }
974 : :
975 : 1052407 : if (outer_state->tf)
976 : 583501 : region = outer_state->tf->try_finally_expr;
977 : 1052407 : collect_finally_tree_1 (new_seq, region);
978 : :
979 : 1052407 : 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 : 115526 : lower_try_finally_fallthru_label (struct leh_tf_state *tf)
988 : : {
989 : 115526 : tree label = tf->fallthru_label;
990 : 115526 : treemple temp;
991 : :
992 : 115526 : if (!label)
993 : : {
994 : 115526 : label = create_artificial_label (gimple_location (tf->try_finally_expr));
995 : 115526 : tf->fallthru_label = label;
996 : 115526 : if (tf->outer->tf)
997 : : {
998 : 55980 : temp.t = label;
999 : 55980 : record_in_finally_tree (temp, tf->outer->tf->try_finally_expr);
1000 : : }
1001 : : }
1002 : 115526 : return label;
1003 : : }
1004 : :
1005 : : /* A subroutine of lower_try_finally. If FINALLY consits of a
1006 : : GIMPLE_EH_ELSE node, return it. */
1007 : :
1008 : : static inline geh_else *
1009 : 2710021 : get_eh_else (gimple_seq finally)
1010 : : {
1011 : 2710021 : gimple *x = gimple_seq_first_stmt (finally);
1012 : 2710021 : if (x && gimple_code (x) == GIMPLE_EH_ELSE)
1013 : : {
1014 : 645 : gcc_assert (gimple_seq_singleton_p (finally));
1015 : 645 : 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 : 848083 : honor_protect_cleanup_actions (struct leh_state *outer_state,
1042 : : struct leh_state *this_state,
1043 : : struct leh_tf_state *tf)
1044 : : {
1045 : 848083 : 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 : 848083 : if (geh_else *eh_else = get_eh_else (finally))
1052 : : {
1053 : 267 : gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else));
1054 : 267 : 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 : 267 : eh_region save_ehp = outer_state->ehp_region;
1061 : 267 : outer_state->ehp_region = this_state->cur_region;
1062 : 267 : lower_eh_constructs_1 (outer_state, &finally);
1063 : 267 : outer_state->ehp_region = save_ehp;
1064 : : }
1065 : : else
1066 : : {
1067 : : /* First check for nothing to do. */
1068 : 847816 : if (lang_hooks.eh_protect_cleanup_actions == NULL)
1069 : 181694 : return;
1070 : 666122 : tree actions = lang_hooks.eh_protect_cleanup_actions ();
1071 : 666122 : if (actions == NULL)
1072 : : return;
1073 : :
1074 : 666122 : if (this_state)
1075 : 607901 : finally = lower_try_finally_dup_block (finally, outer_state,
1076 : 607901 : 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 : 666122 : gimple_stmt_iterator gsi = gsi_start (finally);
1086 : 666122 : gimple *x = !gsi_end_p (gsi) ? gsi_stmt (gsi) : NULL;
1087 : 666106 : if (x
1088 : 666106 : && gimple_code (x) == GIMPLE_TRY
1089 : 5894 : && gimple_try_kind (x) == GIMPLE_TRY_CATCH
1090 : 5894 : && 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 : 666122 : geh_mnt *eh_mnt = gimple_build_eh_must_not_throw (actions);
1098 : 666122 : gtry *try_stmt = gimple_build_try (finally,
1099 : : gimple_seq_alloc_with_stmt (eh_mnt),
1100 : : GIMPLE_TRY_CATCH);
1101 : 666122 : finally = lower_eh_must_not_throw (outer_state, try_stmt);
1102 : : }
1103 : :
1104 : : /* Drop all of this into the exception sequence. */
1105 : 666389 : emit_post_landing_pad (&eh_seq, tf->region);
1106 : 666389 : gimple_seq_add_seq (&eh_seq, finally);
1107 : 666389 : if (gimple_seq_may_fallthru (finally))
1108 : 666389 : 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 : 666389 : 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 : 1440772 : lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
1188 : : {
1189 : 1440772 : struct goto_queue_node *q, *qe;
1190 : 1440772 : geh_else *eh_else;
1191 : 1440772 : glabel *label_stmt;
1192 : 1440772 : gimple *x;
1193 : 1440772 : gimple_seq finally;
1194 : 1440772 : gimple_stmt_iterator gsi;
1195 : 1440772 : tree finally_label;
1196 : 1440772 : location_t loc = gimple_location (tf->try_finally_expr);
1197 : :
1198 : 1440772 : finally = gimple_try_cleanup (tf->top_p);
1199 : 1440772 : 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 : 1440772 : eh_else = get_eh_else (finally);
1205 : 1440772 : if (eh_else)
1206 : : {
1207 : 354 : if (tf->may_throw)
1208 : 0 : finally = gimple_eh_else_e_body (eh_else);
1209 : : else
1210 : 354 : finally = gimple_eh_else_n_body (eh_else);
1211 : : }
1212 : :
1213 : 1440772 : lower_eh_constructs_1 (state, &finally);
1214 : :
1215 : 3624686 : for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
1216 : : {
1217 : 2183914 : gimple *stmt = gsi_stmt (gsi);
1218 : 2183914 : if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
1219 : : {
1220 : 1107227 : tree block = gimple_block (stmt);
1221 : 1107227 : gimple_set_location (stmt, gimple_location (tf->try_finally_expr));
1222 : 1107227 : gimple_set_block (stmt, block);
1223 : : }
1224 : : }
1225 : :
1226 : 1440772 : 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 : 1132 : emit_post_landing_pad (&eh_seq, tf->region);
1231 : 1132 : gimple_seq_add_seq (&eh_seq, finally);
1232 : 1132 : emit_resx (&eh_seq, tf->region);
1233 : 1070239 : return;
1234 : : }
1235 : :
1236 : 1439640 : 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 : 1067975 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1241 : 1067975 : return;
1242 : : }
1243 : :
1244 : 371665 : finally_label = create_artificial_label (loc);
1245 : 371665 : label_stmt = gimple_build_label (finally_label);
1246 : 371665 : gimple_seq_add_stmt (&tf->top_p_seq, label_stmt);
1247 : :
1248 : 371665 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1249 : :
1250 : 371665 : q = tf->goto_queue;
1251 : 371665 : qe = q + tf->goto_queue_active;
1252 : :
1253 : 371665 : 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 : 809794 : for (; q < qe; ++q)
1264 : 438129 : do_goto_redirection (q, finally_label, NULL, tf);
1265 : 371665 : replace_goto_queue (tf);
1266 : :
1267 : 371665 : 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 : 371665 : x = tf->goto_queue[0].cont_stmt;
1280 : 371665 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1281 : 371665 : 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 : 207048 : lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
1290 : : {
1291 : 207048 : gimple_seq finally;
1292 : 207048 : gimple_seq new_stmt;
1293 : 207048 : gimple_seq seq;
1294 : 207048 : gimple *x;
1295 : 207048 : geh_else *eh_else;
1296 : 207048 : tree tmp;
1297 : 207048 : location_t tf_loc = gimple_location (tf->try_finally_expr);
1298 : :
1299 : 207048 : 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 : 207048 : eh_else = get_eh_else (finally);
1304 : 207048 : if (eh_else)
1305 : 6 : finally = gimple_eh_else_n_body (eh_else);
1306 : :
1307 : 207048 : tf->top_p_seq = gimple_try_eval (tf->top_p);
1308 : 207048 : new_stmt = NULL;
1309 : :
1310 : 207048 : if (tf->may_fallthru)
1311 : : {
1312 : 112191 : seq = lower_try_finally_dup_block (finally, state, tf_loc);
1313 : 112191 : lower_eh_constructs_1 (state, &seq);
1314 : 112191 : gimple_seq_add_seq (&new_stmt, seq);
1315 : :
1316 : 112191 : tmp = lower_try_finally_fallthru_label (tf);
1317 : 112191 : x = gimple_build_goto (tmp);
1318 : 112191 : gimple_set_location (x, tf_loc);
1319 : 112191 : gimple_seq_add_stmt (&new_stmt, x);
1320 : : }
1321 : :
1322 : 207048 : 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 : 177779 : if (eh_else)
1327 : 0 : seq = gimple_eh_else_e_body (eh_else);
1328 : : else
1329 : 177779 : seq = lower_try_finally_dup_block (finally, state, tf_loc);
1330 : 177779 : lower_eh_constructs_1 (state, &seq);
1331 : :
1332 : 177779 : emit_post_landing_pad (&eh_seq, tf->region);
1333 : 177779 : gimple_seq_add_seq (&eh_seq, seq);
1334 : 177779 : emit_resx (&eh_seq, tf->region);
1335 : : }
1336 : :
1337 : 207048 : if (tf->goto_queue)
1338 : : {
1339 : 150542 : struct goto_queue_node *q, *qe;
1340 : 150542 : int return_index, index;
1341 : 150542 : struct labels_s
1342 : : {
1343 : : struct goto_queue_node *q;
1344 : : tree label;
1345 : : } *labels;
1346 : :
1347 : 150542 : return_index = tf->dest_array.length ();
1348 : 150542 : labels = XCNEWVEC (struct labels_s, return_index + 1);
1349 : :
1350 : 150542 : q = tf->goto_queue;
1351 : 150542 : qe = q + tf->goto_queue_active;
1352 : 406269 : for (; q < qe; q++)
1353 : : {
1354 : 255727 : index = q->index < 0 ? return_index : q->index;
1355 : :
1356 : 255727 : if (!labels[index].q)
1357 : 154536 : labels[index].q = q;
1358 : : }
1359 : :
1360 : 455620 : for (index = 0; index < return_index + 1; index++)
1361 : : {
1362 : 305078 : tree lab;
1363 : :
1364 : 305078 : q = labels[index].q;
1365 : 305078 : if (! q)
1366 : 150542 : continue;
1367 : :
1368 : 309072 : lab = labels[index].label
1369 : 154536 : = create_artificial_label (tf_loc);
1370 : :
1371 : 154536 : if (index == return_index)
1372 : 0 : do_return_redirection (q, lab, NULL);
1373 : : else
1374 : 154536 : do_goto_redirection (q, lab, NULL, tf);
1375 : :
1376 : 154536 : x = gimple_build_label (lab);
1377 : 154536 : gimple_seq_add_stmt (&new_stmt, x);
1378 : :
1379 : 154536 : seq = lower_try_finally_dup_block (finally, state, q->location);
1380 : 154536 : lower_eh_constructs_1 (state, &seq);
1381 : 154536 : gimple_seq_add_seq (&new_stmt, seq);
1382 : :
1383 : 154536 : gimple_seq_add_stmt (&new_stmt, q->cont_stmt);
1384 : 154536 : maybe_record_in_goto_queue (state, q->cont_stmt);
1385 : : }
1386 : :
1387 : 406269 : for (q = tf->goto_queue; q < qe; q++)
1388 : : {
1389 : 255727 : tree lab;
1390 : :
1391 : 255727 : index = q->index < 0 ? return_index : q->index;
1392 : :
1393 : 255727 : if (labels[index].q == q)
1394 : 154536 : continue;
1395 : :
1396 : 101191 : lab = labels[index].label;
1397 : :
1398 : 101191 : if (index == return_index)
1399 : 0 : do_return_redirection (q, lab, NULL);
1400 : : else
1401 : 101191 : do_goto_redirection (q, lab, NULL, tf);
1402 : : }
1403 : :
1404 : 150542 : replace_goto_queue (tf);
1405 : 150542 : 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 : 207048 : gimple_seq_add_seq (&tf->top_p_seq, new_stmt);
1411 : 207048 : }
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 : 3534 : lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
1420 : : {
1421 : 3534 : struct goto_queue_node *q, *qe;
1422 : 3534 : tree finally_tmp, finally_label;
1423 : 3534 : int return_index, eh_index, fallthru_index;
1424 : 3534 : int nlabels, ndests, j, last_case_index;
1425 : 3534 : tree last_case;
1426 : 3534 : auto_vec<tree> case_label_vec;
1427 : 3534 : gimple_seq switch_body = NULL;
1428 : 3534 : gimple *x;
1429 : 3534 : geh_else *eh_else;
1430 : 3534 : tree tmp;
1431 : 3534 : gimple *switch_stmt;
1432 : 3534 : gimple_seq finally;
1433 : 3534 : hash_map<tree, gimple *> *cont_map = NULL;
1434 : : /* The location of the TRY_FINALLY stmt. */
1435 : 3534 : location_t tf_loc = gimple_location (tf->try_finally_expr);
1436 : : /* The location of the finally block. */
1437 : 3534 : location_t finally_loc;
1438 : :
1439 : 3534 : finally = gimple_try_cleanup (tf->top_p);
1440 : 3534 : eh_else = get_eh_else (finally);
1441 : :
1442 : : /* Mash the TRY block to the head of the chain. */
1443 : 3534 : 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 : 3534 : x = gimple_seq_last_stmt (finally);
1448 : 3534 : finally_loc = x ? gimple_location (x) : tf_loc;
1449 : :
1450 : : /* Prepare for switch statement generation. */
1451 : 3534 : nlabels = tf->dest_array.length ();
1452 : 3534 : return_index = nlabels;
1453 : 3534 : eh_index = return_index + tf->may_return;
1454 : 3534 : fallthru_index = eh_index + (tf->may_throw && !eh_else);
1455 : 3534 : ndests = fallthru_index + tf->may_fallthru;
1456 : :
1457 : 3534 : finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
1458 : 3534 : 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 : 3534 : case_label_vec.create (ndests);
1464 : 3534 : last_case = NULL;
1465 : 3534 : 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 : 3534 : if (tf->may_fallthru)
1472 : : {
1473 : 3335 : x = gimple_build_assign (finally_tmp,
1474 : : build_int_cst (integer_type_node,
1475 : 3335 : fallthru_index));
1476 : 3335 : gimple_set_location (x, finally_loc);
1477 : 3335 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1478 : :
1479 : 3335 : tmp = build_int_cst (integer_type_node, fallthru_index);
1480 : 3335 : last_case = build_case_label (tmp, NULL,
1481 : : create_artificial_label (finally_loc));
1482 : 3335 : case_label_vec.quick_push (last_case);
1483 : 3335 : last_case_index++;
1484 : :
1485 : 3335 : x = gimple_build_label (CASE_LABEL (last_case));
1486 : 3335 : gimple_seq_add_stmt (&switch_body, x);
1487 : :
1488 : 3335 : tmp = lower_try_finally_fallthru_label (tf);
1489 : 3335 : x = gimple_build_goto (tmp);
1490 : 3335 : gimple_set_location (x, finally_loc);
1491 : 3335 : 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 : 3534 : if (eh_else)
1497 : : {
1498 : 6 : 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 : 6 : finally = gimple_eh_else_n_body (eh_else);
1509 : : }
1510 : 3528 : else if (tf->may_throw)
1511 : : {
1512 : 2781 : emit_post_landing_pad (&eh_seq, tf->region);
1513 : :
1514 : 2781 : x = gimple_build_assign (finally_tmp,
1515 : 2781 : build_int_cst (integer_type_node, eh_index));
1516 : 2781 : gimple_seq_add_stmt (&eh_seq, x);
1517 : :
1518 : 2781 : x = gimple_build_goto (finally_label);
1519 : 2781 : gimple_set_location (x, tf_loc);
1520 : 2781 : gimple_seq_add_stmt (&eh_seq, x);
1521 : :
1522 : 2781 : tmp = build_int_cst (integer_type_node, eh_index);
1523 : 2781 : last_case = build_case_label (tmp, NULL,
1524 : : create_artificial_label (tf_loc));
1525 : 2781 : case_label_vec.quick_push (last_case);
1526 : 2781 : last_case_index++;
1527 : :
1528 : 2781 : x = gimple_build_label (CASE_LABEL (last_case));
1529 : 2781 : gimple_seq_add_stmt (&eh_seq, x);
1530 : 2781 : emit_resx (&eh_seq, tf->region);
1531 : : }
1532 : :
1533 : 3534 : x = gimple_build_label (finally_label);
1534 : 3534 : gimple_seq_add_stmt (&tf->top_p_seq, x);
1535 : :
1536 : 3534 : lower_eh_constructs_1 (state, &finally);
1537 : 3534 : gimple_seq_add_seq (&tf->top_p_seq, finally);
1538 : :
1539 : : /* Redirect each incoming goto edge. */
1540 : 3534 : q = tf->goto_queue;
1541 : 3534 : qe = q + tf->goto_queue_active;
1542 : 3534 : 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 : 4847 : for (; q < qe; ++q)
1546 : : {
1547 : 1313 : gimple_seq mod = NULL;
1548 : 1313 : int switch_id;
1549 : 1313 : unsigned int case_index;
1550 : :
1551 : 1313 : 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 : 1313 : x = gimple_build_assign (finally_tmp,
1563 : 1313 : build_int_cst (integer_type_node, q->index));
1564 : 1313 : gimple_seq_add_stmt (&mod, x);
1565 : 1313 : do_goto_redirection (q, finally_label, mod, tf);
1566 : 1313 : switch_id = q->index;
1567 : : }
1568 : :
1569 : 1313 : case_index = j + q->index;
1570 : 1518 : if (case_label_vec.length () <= case_index || !case_label_vec[case_index])
1571 : : {
1572 : 1108 : tree case_lab;
1573 : 1108 : tmp = build_int_cst (integer_type_node, switch_id);
1574 : 1108 : 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 : 1108 : if (!cont_map)
1579 : 834 : cont_map = new hash_map<tree, gimple *>;
1580 : 1108 : cont_map->put (case_lab, q->cont_stmt);
1581 : 1108 : case_label_vec.quick_push (case_lab);
1582 : : }
1583 : : }
1584 : 4642 : for (j = last_case_index; j < last_case_index + nlabels; j++)
1585 : : {
1586 : 1108 : gimple *cont_stmt;
1587 : :
1588 : 1108 : last_case = case_label_vec[j];
1589 : :
1590 : 1108 : gcc_assert (last_case);
1591 : 1108 : gcc_assert (cont_map);
1592 : :
1593 : 1108 : cont_stmt = *cont_map->get (last_case);
1594 : :
1595 : 1108 : x = gimple_build_label (CASE_LABEL (last_case));
1596 : 1108 : gimple_seq_add_stmt (&switch_body, x);
1597 : 1108 : gimple_seq_add_stmt (&switch_body, cont_stmt);
1598 : 1108 : maybe_record_in_goto_queue (state, cont_stmt);
1599 : : }
1600 : 3534 : if (cont_map)
1601 : 834 : delete cont_map;
1602 : :
1603 : 3534 : 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 : 3534 : CASE_LOW (last_case) = NULL;
1608 : 3534 : tree tem = case_label_vec.pop ();
1609 : 3534 : gcc_assert (tem == last_case);
1610 : 3534 : sort_case_labels (case_label_vec);
1611 : :
1612 : : /* Build the switch statement, setting last_case to be the default
1613 : : label. */
1614 : 3534 : switch_stmt = gimple_build_switch (finally_tmp, last_case,
1615 : : case_label_vec);
1616 : 3534 : 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 : 3534 : gimple_seq_add_stmt (&tf->top_p_seq, switch_stmt);
1621 : 3534 : gimple_seq_add_seq (&tf->top_p_seq, switch_body);
1622 : 3534 : }
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 : 210582 : decide_copy_try_finally (int ndests, bool may_throw, gimple_seq finally)
1634 : : {
1635 : 210582 : int f_estimate, sw_estimate;
1636 : 210582 : 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 : 210582 : eh_else = get_eh_else (finally);
1641 : 210582 : if (eh_else)
1642 : : {
1643 : 12 : ndests -= may_throw;
1644 : 12 : finally = gimple_eh_else_n_body (eh_else);
1645 : : }
1646 : :
1647 : 210582 : if (!optimize)
1648 : : {
1649 : 17110 : gimple_stmt_iterator gsi;
1650 : :
1651 : 17110 : if (ndests == 1)
1652 : : return true;
1653 : :
1654 : 44584 : 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 : 30988 : gimple *stmt = gsi_stmt (gsi);
1659 : 30988 : if (!is_gimple_debug (stmt)
1660 : 30988 : && !gimple_clobber_p (stmt)
1661 : 34619 : && !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 : 193472 : f_estimate = estimate_num_insns_seq (finally, &eni_size_weights);
1669 : 193472 : f_estimate = (f_estimate + 1) * ndests;
1670 : :
1671 : : /* Switch statement (cost 10), N variable assignments, N gotos. */
1672 : 193472 : sw_estimate = 10 + 2 * ndests;
1673 : :
1674 : : /* Optimize for size clearly wants our best guess. */
1675 : 193472 : if (optimize_function_for_size_p (cfun))
1676 : 2375 : return f_estimate < sw_estimate;
1677 : :
1678 : : /* ??? These numbers are completely made up so far. */
1679 : 191097 : if (optimize > 1)
1680 : 375076 : return f_estimate < 100 || f_estimate < sw_estimate * 2;
1681 : : else
1682 : 7111 : 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 : 1459331 : cleanup_is_dead_in (leh_state *state)
1695 : : {
1696 : 1459331 : if (flag_checking)
1697 : : {
1698 : 1459319 : eh_region reg = state->cur_region;
1699 : 27137745 : while (reg && reg->type == ERT_CLEANUP)
1700 : 25678426 : reg = reg->outer;
1701 : :
1702 : 1459319 : gcc_assert (reg == state->outer_non_cleanup);
1703 : : }
1704 : :
1705 : 1459331 : eh_region reg = state->outer_non_cleanup;
1706 : 1459331 : 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 : 1668861 : lower_try_finally (struct leh_state *state, gtry *tp)
1716 : : {
1717 : 1668861 : struct leh_tf_state this_tf;
1718 : 1668861 : struct leh_state this_state;
1719 : 1668861 : int ndests;
1720 : 1668861 : gimple_seq old_eh_seq;
1721 : :
1722 : : /* Process the try block. */
1723 : :
1724 : 1668861 : memset (&this_tf, 0, sizeof (this_tf));
1725 : 1668861 : this_tf.try_finally_expr = tp;
1726 : 1668861 : this_tf.top_p = tp;
1727 : 1668861 : this_tf.outer = state;
1728 : 1668861 : if (using_eh_for_cleanups_p () && !cleanup_is_dead_in (state))
1729 : : {
1730 : 1128775 : this_tf.region = gen_eh_region_cleanup (state->cur_region);
1731 : 1128775 : this_state.cur_region = this_tf.region;
1732 : : }
1733 : : else
1734 : : {
1735 : 540086 : this_tf.region = NULL;
1736 : 540086 : this_state.cur_region = state->cur_region;
1737 : : }
1738 : :
1739 : 1668861 : this_state.outer_non_cleanup = state->outer_non_cleanup;
1740 : 1668861 : this_state.ehp_region = state->ehp_region;
1741 : 1668861 : this_state.tf = &this_tf;
1742 : :
1743 : 1668861 : old_eh_seq = eh_seq;
1744 : 1668861 : eh_seq = NULL;
1745 : :
1746 : 1668861 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1747 : :
1748 : : /* Determine if the try block is escaped through the bottom. */
1749 : 1668861 : 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 : 1668861 : if (this_tf.region)
1753 : 1128775 : this_tf.may_throw = eh_region_may_contain_throw (this_tf.region);
1754 : 1668861 : if (this_tf.may_throw)
1755 : 789862 : 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 : 1668861 : ndests = this_tf.dest_array.length ();
1762 : 1668861 : ndests += this_tf.may_fallthru;
1763 : 1668861 : ndests += this_tf.may_return;
1764 : 1668861 : ndests += this_tf.may_throw;
1765 : :
1766 : : /* If the FINALLY block is not reachable, dike it out. */
1767 : 1668861 : if (ndests == 0)
1768 : : {
1769 : 17505 : gimple_seq_add_seq (&this_tf.top_p_seq, gimple_try_eval (tp));
1770 : 17505 : 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 : 1651356 : 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 : 1651354 : else if (ndests == 1)
1780 : 1440772 : lower_try_finally_onedest (state, &this_tf);
1781 : 210582 : else if (decide_copy_try_finally (ndests, this_tf.may_throw,
1782 : : gimple_try_cleanup (tp)))
1783 : 207048 : lower_try_finally_copy (state, &this_tf);
1784 : : else
1785 : 3534 : 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 : 1668861 : if (this_tf.fallthru_label)
1790 : : {
1791 : : /* This must be reached only if ndests == 0. */
1792 : 115526 : gimple *x = gimple_build_label (this_tf.fallthru_label);
1793 : 115526 : gimple_seq_add_stmt (&this_tf.top_p_seq, x);
1794 : : }
1795 : :
1796 : 1668861 : this_tf.dest_array.release ();
1797 : 1668861 : free (this_tf.goto_queue);
1798 : 1668861 : if (this_tf.goto_queue_map)
1799 : 329 : 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 : 1668861 : if (old_eh_seq)
1804 : : {
1805 : 144058 : if (eh_seq == NULL)
1806 : 14504 : eh_seq = old_eh_seq;
1807 : : else
1808 : : {
1809 : 129554 : gimple_seq new_eh_seq = eh_seq;
1810 : 129554 : eh_seq = old_eh_seq;
1811 : 129554 : gimple_seq_add_seq (&eh_seq, new_eh_seq);
1812 : : }
1813 : : }
1814 : :
1815 : 1668861 : 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 : 45794 : lower_catch (struct leh_state *state, gtry *tp)
1824 : : {
1825 : 45794 : eh_region try_region = NULL;
1826 : 45794 : struct leh_state this_state = *state;
1827 : 45794 : gimple_stmt_iterator gsi;
1828 : 45794 : tree out_label;
1829 : 45794 : gimple_seq new_seq, cleanup;
1830 : 45794 : gimple *x;
1831 : 45794 : geh_dispatch *eh_dispatch;
1832 : 45794 : location_t try_catch_loc = gimple_location (tp);
1833 : 45794 : location_t catch_loc = UNKNOWN_LOCATION;
1834 : :
1835 : 45794 : if (flag_exceptions)
1836 : : {
1837 : 45788 : try_region = gen_eh_region_try (state->cur_region);
1838 : 45788 : this_state.cur_region = try_region;
1839 : 45788 : this_state.outer_non_cleanup = this_state.cur_region;
1840 : : }
1841 : :
1842 : 45794 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1843 : :
1844 : 45794 : if (!eh_region_may_contain_throw (try_region))
1845 : 4598 : return gimple_try_eval (tp);
1846 : :
1847 : 41196 : new_seq = NULL;
1848 : 41196 : eh_dispatch = gimple_build_eh_dispatch (try_region->index);
1849 : 41196 : gimple_seq_add_stmt (&new_seq, eh_dispatch);
1850 : 41196 : emit_resx (&new_seq, try_region);
1851 : :
1852 : 41196 : this_state.cur_region = state->cur_region;
1853 : 41196 : this_state.outer_non_cleanup = state->outer_non_cleanup;
1854 : 41196 : 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 : 41196 : gimple_seq old_eh_seq = eh_seq;
1860 : 41196 : eh_seq = NULL;
1861 : :
1862 : 41196 : out_label = NULL;
1863 : 41196 : cleanup = gimple_try_cleanup (tp);
1864 : 41196 : for (gsi = gsi_start (cleanup);
1865 : 47040 : !gsi_end_p (gsi);
1866 : 5844 : gsi_next (&gsi))
1867 : : {
1868 : 44090 : eh_catch c;
1869 : 44090 : gcatch *catch_stmt;
1870 : 44090 : gimple_seq handler;
1871 : :
1872 : 44090 : catch_stmt = as_a <gcatch *> (gsi_stmt (gsi));
1873 : 44090 : if (catch_loc == UNKNOWN_LOCATION)
1874 : 41196 : catch_loc = gimple_location (catch_stmt);
1875 : 44090 : c = gen_eh_region_catch (try_region, gimple_catch_types (catch_stmt));
1876 : :
1877 : 44090 : handler = gimple_catch_handler (catch_stmt);
1878 : 44090 : lower_eh_constructs_1 (&this_state, &handler);
1879 : :
1880 : 44090 : c->label = create_artificial_label (UNKNOWN_LOCATION);
1881 : 44090 : x = gimple_build_label (c->label);
1882 : 44090 : gimple_seq_add_stmt (&new_seq, x);
1883 : :
1884 : 44090 : gimple_seq_add_seq (&new_seq, handler);
1885 : :
1886 : 44090 : if (gimple_seq_may_fallthru (new_seq))
1887 : : {
1888 : 13740 : if (!out_label)
1889 : 13193 : out_label = create_artificial_label (try_catch_loc);
1890 : :
1891 : 13740 : x = gimple_build_goto (out_label);
1892 : 13740 : gimple_seq_add_stmt (&new_seq, x);
1893 : : }
1894 : 44090 : 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 : 41196 : gimple_set_location (eh_dispatch, catch_loc);
1901 : :
1902 : 41196 : gimple_try_set_cleanup (tp, new_seq);
1903 : :
1904 : 41196 : gimple_seq new_eh_seq = eh_seq;
1905 : 41196 : eh_seq = old_eh_seq;
1906 : 41196 : gimple_seq ret_seq = frob_into_branch_around (tp, try_region, out_label);
1907 : 41196 : gimple_seq_add_seq (&eh_seq, new_eh_seq);
1908 : 41196 : 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 : 4732 : lower_eh_filter (struct leh_state *state, gtry *tp)
1917 : : {
1918 : 4732 : struct leh_state this_state = *state;
1919 : 4732 : eh_region this_region = NULL;
1920 : 4732 : gimple *inner, *x;
1921 : 4732 : gimple_seq new_seq;
1922 : :
1923 : 4732 : inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
1924 : :
1925 : 4732 : if (flag_exceptions)
1926 : : {
1927 : 4732 : this_region = gen_eh_region_allowed (state->cur_region,
1928 : : gimple_eh_filter_types (inner));
1929 : 4732 : this_state.cur_region = this_region;
1930 : 4732 : this_state.outer_non_cleanup = this_state.cur_region;
1931 : : }
1932 : :
1933 : 4732 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1934 : :
1935 : 4732 : if (!eh_region_may_contain_throw (this_region))
1936 : 4256 : return gimple_try_eval (tp);
1937 : :
1938 : 476 : this_state.cur_region = state->cur_region;
1939 : 476 : this_state.ehp_region = this_region;
1940 : :
1941 : 476 : new_seq = NULL;
1942 : 476 : x = gimple_build_eh_dispatch (this_region->index);
1943 : 476 : gimple_set_location (x, gimple_location (tp));
1944 : 476 : gimple_seq_add_stmt (&new_seq, x);
1945 : 476 : emit_resx (&new_seq, this_region);
1946 : :
1947 : 476 : this_region->u.allowed.label = create_artificial_label (UNKNOWN_LOCATION);
1948 : 476 : x = gimple_build_label (this_region->u.allowed.label);
1949 : 476 : gimple_seq_add_stmt (&new_seq, x);
1950 : :
1951 : 476 : lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure_ptr (inner));
1952 : 476 : gimple_seq_add_seq (&new_seq, gimple_eh_filter_failure (inner));
1953 : :
1954 : 476 : gimple_try_set_cleanup (tp, new_seq);
1955 : :
1956 : 476 : 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 : 1320003 : lower_eh_must_not_throw (struct leh_state *state, gtry *tp)
1965 : : {
1966 : 1320003 : struct leh_state this_state = *state;
1967 : :
1968 : 1320003 : if (flag_exceptions)
1969 : : {
1970 : 1320003 : gimple *inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
1971 : 1320003 : eh_region this_region;
1972 : :
1973 : 1320003 : this_region = gen_eh_region_must_not_throw (state->cur_region);
1974 : 1320003 : this_region->u.must_not_throw.failure_decl
1975 : 1320003 : = gimple_eh_must_not_throw_fndecl (
1976 : 1320003 : as_a <geh_mnt *> (inner));
1977 : 1320003 : this_region->u.must_not_throw.failure_loc
1978 : 1320003 : = 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 : 1320003 : TREE_USED (this_region->u.must_not_throw.failure_decl) = 1;
1984 : :
1985 : 1320003 : this_state.cur_region = this_region;
1986 : 1320003 : this_state.outer_non_cleanup = this_state.cur_region;
1987 : : }
1988 : :
1989 : 1320003 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
1990 : :
1991 : 1320003 : 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 : 153326 : lower_cleanup (struct leh_state *state, gtry *tp)
1999 : : {
2000 : 153326 : struct leh_state this_state = *state;
2001 : 153326 : eh_region this_region = NULL;
2002 : 153326 : struct leh_tf_state fake_tf;
2003 : 153326 : gimple_seq result;
2004 : 153326 : bool cleanup_dead = cleanup_is_dead_in (state);
2005 : :
2006 : 153326 : if (flag_exceptions && !cleanup_dead)
2007 : : {
2008 : 117857 : this_region = gen_eh_region_cleanup (state->cur_region);
2009 : 117857 : this_state.cur_region = this_region;
2010 : 117857 : this_state.outer_non_cleanup = state->outer_non_cleanup;
2011 : : }
2012 : :
2013 : 153326 : lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp));
2014 : :
2015 : 153326 : if (cleanup_dead || !eh_region_may_contain_throw (this_region))
2016 : 95105 : 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 : 58221 : memset (&fake_tf, 0, sizeof (fake_tf));
2021 : 58221 : fake_tf.top_p = fake_tf.try_finally_expr = tp;
2022 : 58221 : fake_tf.outer = state;
2023 : 58221 : fake_tf.region = this_region;
2024 : 58221 : fake_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
2025 : 58221 : fake_tf.may_throw = true;
2026 : :
2027 : 58221 : honor_protect_cleanup_actions (state, NULL, &fake_tf);
2028 : :
2029 : 58221 : 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 : 58221 : result = gimple_try_eval (tp);
2043 : 58221 : 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 : 58221 : return result;
2050 : : }
2051 : :
2052 : : /* Main loop for lowering eh constructs. Also moves gsi to the next
2053 : : statement. */
2054 : :
2055 : : static void
2056 : 90693350 : lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
2057 : : {
2058 : 90693350 : gimple_seq replace;
2059 : 90693350 : gimple *x;
2060 : 90693350 : gimple *stmt = gsi_stmt (*gsi);
2061 : :
2062 : 90693350 : switch (gimple_code (stmt))
2063 : : {
2064 : 11206035 : case GIMPLE_CALL:
2065 : 11206035 : {
2066 : 11206035 : tree fndecl = gimple_call_fndecl (stmt);
2067 : 11206035 : tree rhs, lhs;
2068 : :
2069 : 11206035 : if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
2070 : 2199874 : switch (DECL_FUNCTION_CODE (fndecl))
2071 : : {
2072 : 19174 : 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 : 19174 : if (state->ehp_region)
2077 : : {
2078 : 38338 : tree nr = build_int_cst (integer_type_node,
2079 : 19169 : state->ehp_region->index);
2080 : 19169 : 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 : 19169 : 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 : 2526604 : return;
2105 : :
2106 : : default:
2107 : : break;
2108 : : }
2109 : : }
2110 : : /* FALLTHRU */
2111 : :
2112 : 54280890 : 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 : 54280890 : if (stmt_could_throw_p (cfun, stmt)
2119 : 3535259 : && gimple_has_lhs (stmt)
2120 : 2596206 : && gimple_stmt_may_fallthru (stmt)
2121 : 2596203 : && !tree_could_throw_p (gimple_get_lhs (stmt))
2122 : 56675841 : && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt))))
2123 : : {
2124 : 1750778 : tree lhs = gimple_get_lhs (stmt);
2125 : 1750778 : tree tmp = create_tmp_var (TREE_TYPE (lhs));
2126 : 1750778 : gimple *s = gimple_build_assign (lhs, tmp);
2127 : 1750778 : gimple_set_location (s, gimple_location (stmt));
2128 : 1750778 : gimple_set_block (s, gimple_block (stmt));
2129 : 1750778 : gimple_set_lhs (stmt, tmp);
2130 : 1750778 : gsi_insert_after (gsi, s, GSI_SAME_STMT);
2131 : : }
2132 : : /* Look for things that can throw exceptions, and record them. */
2133 : 54280890 : if (state->cur_region && stmt_could_throw_p (cfun, stmt))
2134 : : {
2135 : 2708805 : record_stmt_eh_region (state->cur_region, stmt);
2136 : 2708805 : note_eh_region_may_contain_throw (state->cur_region);
2137 : : }
2138 : : break;
2139 : :
2140 : 14060550 : case GIMPLE_COND:
2141 : 14060550 : case GIMPLE_GOTO:
2142 : 14060550 : case GIMPLE_RETURN:
2143 : 14060550 : case GIMPLE_ASM:
2144 : 14060550 : maybe_record_in_goto_queue (state, stmt);
2145 : 14060550 : break;
2146 : :
2147 : 52211 : case GIMPLE_SWITCH:
2148 : 52211 : verify_norecord_switch_expr (state, as_a <gswitch *> (stmt));
2149 : 52211 : break;
2150 : :
2151 : 2526594 : case GIMPLE_TRY:
2152 : 2526594 : {
2153 : 2526594 : gtry *try_stmt = as_a <gtry *> (stmt);
2154 : 2526594 : if (gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY)
2155 : 1668861 : replace = lower_try_finally (state, try_stmt);
2156 : : else
2157 : : {
2158 : 857733 : x = gimple_seq_first_stmt (gimple_try_cleanup (try_stmt));
2159 : 857733 : if (!x)
2160 : : {
2161 : 0 : replace = gimple_try_eval (try_stmt);
2162 : 0 : lower_eh_constructs_1 (state, &replace);
2163 : : }
2164 : : else
2165 : 857733 : switch (gimple_code (x))
2166 : : {
2167 : 45794 : case GIMPLE_CATCH:
2168 : 45794 : replace = lower_catch (state, try_stmt);
2169 : 45794 : break;
2170 : 4732 : case GIMPLE_EH_FILTER:
2171 : 4732 : replace = lower_eh_filter (state, try_stmt);
2172 : 4732 : break;
2173 : 653881 : case GIMPLE_EH_MUST_NOT_THROW:
2174 : 653881 : replace = lower_eh_must_not_throw (state, try_stmt);
2175 : 653881 : break;
2176 : 0 : case GIMPLE_EH_ELSE:
2177 : : /* This code is only valid with GIMPLE_TRY_FINALLY. */
2178 : 0 : gcc_unreachable ();
2179 : 153326 : default:
2180 : 153326 : replace = lower_cleanup (state, try_stmt);
2181 : 153326 : break;
2182 : : }
2183 : : }
2184 : : }
2185 : :
2186 : : /* Remove the old stmt and insert the transformed sequence
2187 : : instead. */
2188 : 2526594 : gsi_insert_seq_before (gsi, replace, GSI_SAME_STMT);
2189 : 2526594 : gsi_remove (gsi, true);
2190 : :
2191 : : /* Return since we don't want gsi_next () */
2192 : 2526594 : 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 : 88166751 : 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 : 8088379 : lower_eh_constructs_1 (struct leh_state *state, gimple_seq *pseq)
2211 : : {
2212 : 8088379 : gimple_stmt_iterator gsi;
2213 : 106723484 : for (gsi = gsi_start (*pseq); !gsi_end_p (gsi);)
2214 : 90693350 : lower_eh_constructs_2 (state, &gsi);
2215 : 8088379 : }
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 : 290033 : pass_lower_eh (gcc::context *ctxt)
2236 : 580066 : : 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 : 2962016 : pass_lower_eh::execute (function *fun)
2246 : : {
2247 : 2962016 : struct leh_state null_state;
2248 : 2962016 : gimple_seq bodyp;
2249 : :
2250 : 2962016 : bodyp = gimple_body (current_function_decl);
2251 : 2962016 : if (bodyp == NULL)
2252 : : return 0;
2253 : :
2254 : 2962016 : finally_tree = new hash_table<finally_tree_hasher> (31);
2255 : 2962016 : eh_region_may_contain_throw_map = BITMAP_ALLOC (NULL);
2256 : 2962016 : memset (&null_state, 0, sizeof (null_state));
2257 : :
2258 : 2962016 : collect_finally_tree_1 (bodyp, NULL);
2259 : 2962016 : lower_eh_constructs_1 (&null_state, &bodyp);
2260 : 2962016 : 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 : 2962016 : gcc_assert (!gimple_seq_may_fallthru (bodyp));
2266 : 2962016 : 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 : 2962016 : gcc_assert (bodyp == gimple_body (current_function_decl));
2271 : :
2272 : 2962016 : delete finally_tree;
2273 : 2962016 : finally_tree = NULL;
2274 : 2962016 : BITMAP_FREE (eh_region_may_contain_throw_map);
2275 : 2962016 : 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 : 2962016 : if (function_needs_eh_personality (fun) == eh_personality_lang
2280 : 2962016 : && !DECL_FUNCTION_PERSONALITY (current_function_decl))
2281 : 832307 : DECL_FUNCTION_PERSONALITY (current_function_decl)
2282 : 1664614 : = lang_hooks.eh_personality ();
2283 : :
2284 : : return 0;
2285 : : }
2286 : :
2287 : : } // anon namespace
2288 : :
2289 : : gimple_opt_pass *
2290 : 290033 : make_pass_lower_eh (gcc::context *ctxt)
2291 : : {
2292 : 290033 : 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 : 50759 : make_eh_dispatch_edges (geh_dispatch *stmt)
2301 : : {
2302 : 50759 : eh_region r;
2303 : 50759 : eh_catch c;
2304 : 50759 : basic_block src, dst;
2305 : :
2306 : 50759 : r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
2307 : 50759 : src = gimple_bb (stmt);
2308 : :
2309 : 50759 : switch (r->type)
2310 : : {
2311 : 50131 : case ERT_TRY:
2312 : 56795 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
2313 : : {
2314 : 53295 : dst = label_to_block (cfun, c->label);
2315 : 53295 : make_edge (src, dst, 0);
2316 : :
2317 : : /* A catch-all handler doesn't have a fallthru. */
2318 : 53295 : if (c->type_list == NULL)
2319 : : return false;
2320 : : }
2321 : : break;
2322 : :
2323 : 628 : case ERT_ALLOWED_EXCEPTIONS:
2324 : 628 : dst = label_to_block (cfun, r->u.allowed.label);
2325 : 628 : make_edge (src, dst, 0);
2326 : 628 : 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 : 6063606 : make_eh_edge (gimple *stmt)
2340 : : {
2341 : 6063606 : basic_block src, dst;
2342 : 6063606 : eh_landing_pad lp;
2343 : 6063606 : int lp_nr;
2344 : :
2345 : 6063606 : lp_nr = lookup_stmt_eh_lp (stmt);
2346 : 6063606 : if (lp_nr <= 0)
2347 : : return NULL;
2348 : :
2349 : 3855447 : lp = get_eh_landing_pad_from_number (lp_nr);
2350 : 3855447 : gcc_assert (lp != NULL);
2351 : :
2352 : 3855447 : src = gimple_bb (stmt);
2353 : 3855447 : dst = label_to_block (cfun, lp->post_landing_pad);
2354 : 3855447 : 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 : 2887446 : redirect_eh_edge_1 (edge edge_in, basic_block new_bb, bool change_region)
2368 : : {
2369 : 2887446 : eh_landing_pad old_lp, new_lp;
2370 : 2887446 : basic_block old_bb;
2371 : 2887446 : gimple *throw_stmt;
2372 : 2887446 : int old_lp_nr, new_lp_nr;
2373 : 2887446 : tree old_label, new_label;
2374 : 2887446 : edge_iterator ei;
2375 : 2887446 : edge e;
2376 : :
2377 : 2887446 : old_bb = edge_in->dest;
2378 : 2887446 : old_label = gimple_block_label (old_bb);
2379 : 2887446 : old_lp_nr = EH_LANDING_PAD_NR (old_label);
2380 : 2887446 : gcc_assert (old_lp_nr > 0);
2381 : 2887446 : old_lp = get_eh_landing_pad_from_number (old_lp_nr);
2382 : :
2383 : 2887446 : throw_stmt = *gsi_last_bb (edge_in->src);
2384 : 2887446 : gcc_checking_assert (lookup_stmt_eh_lp (throw_stmt) == old_lp_nr);
2385 : :
2386 : 2887446 : new_label = gimple_block_label (new_bb);
2387 : :
2388 : : /* Look for an existing region that might be using NEW_BB already. */
2389 : 2887446 : new_lp_nr = EH_LANDING_PAD_NR (new_label);
2390 : 2887446 : if (new_lp_nr)
2391 : : {
2392 : 1681185 : new_lp = get_eh_landing_pad_from_number (new_lp_nr);
2393 : 1681185 : 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 : 1681185 : gcc_assert (change_region || new_lp->region == old_lp->region);
2398 : : }
2399 : : else
2400 : : {
2401 : 1206261 : new_lp = NULL;
2402 : 1206261 : gcc_assert (!change_region);
2403 : : }
2404 : :
2405 : : /* Notice when we redirect the last EH edge away from OLD_BB. */
2406 : 11885286 : FOR_EACH_EDGE (e, ei, old_bb->preds)
2407 : 10480006 : if (e != edge_in && (e->flags & EDGE_EH))
2408 : : break;
2409 : :
2410 : 2887446 : 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 : 1681185 : if (e == NULL && !change_region)
2418 : 928133 : 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 : 1206261 : if (e == NULL)
2426 : : {
2427 : 256822 : EH_LANDING_PAD_NR (old_lp->post_landing_pad) = 0;
2428 : 256822 : new_lp = old_lp;
2429 : : }
2430 : : else
2431 : 949439 : new_lp = gen_eh_landing_pad (old_lp->region);
2432 : 1206261 : new_lp->post_landing_pad = new_label;
2433 : 1206261 : EH_LANDING_PAD_NR (new_label) = new_lp->index;
2434 : : }
2435 : :
2436 : : /* Maybe move the throwing statement to the new region. */
2437 : 2887446 : if (old_lp != new_lp)
2438 : : {
2439 : 2630624 : remove_stmt_from_eh_lp (throw_stmt);
2440 : 2630624 : add_stmt_to_eh_lp (throw_stmt, new_lp->index);
2441 : : }
2442 : 2887446 : }
2443 : :
2444 : : /* Redirect EH edge E to NEW_BB. */
2445 : :
2446 : : edge
2447 : 1109274 : redirect_eh_edge (edge edge_in, basic_block new_bb)
2448 : : {
2449 : 1109274 : redirect_eh_edge_1 (edge_in, new_bb, false);
2450 : 1109274 : 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 : 1847484734 : 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 : 1847484734 : *handled = true;
2507 : 1847484734 : switch (op)
2508 : : {
2509 : 2118745 : case TRUNC_DIV_EXPR:
2510 : 2118745 : case CEIL_DIV_EXPR:
2511 : 2118745 : case FLOOR_DIV_EXPR:
2512 : 2118745 : case ROUND_DIV_EXPR:
2513 : 2118745 : case EXACT_DIV_EXPR:
2514 : 2118745 : case CEIL_MOD_EXPR:
2515 : 2118745 : case FLOOR_MOD_EXPR:
2516 : 2118745 : case ROUND_MOD_EXPR:
2517 : 2118745 : case TRUNC_MOD_EXPR:
2518 : 2118745 : if (!TREE_CONSTANT (divisor) || integer_zerop (divisor))
2519 : 682265 : return true;
2520 : 1436480 : if (TREE_CODE (divisor) == VECTOR_CST)
2521 : : {
2522 : : /* Inspired by initializer_each_zero_or_onep. */
2523 : 430 : unsigned HOST_WIDE_INT nelts = vector_cst_encoded_nelts (divisor);
2524 : 430 : if (VECTOR_CST_STEPPED_P (divisor)
2525 : 430 : && !TYPE_VECTOR_SUBPARTS (TREE_TYPE (divisor))
2526 : 0 : .is_constant (&nelts))
2527 : 4716610 : return true;
2528 : 1492 : for (unsigned int i = 0; i < nelts; ++i)
2529 : : {
2530 : 1095 : tree elt = vector_cst_elt (divisor, i);
2531 : 1095 : if (integer_zerop (elt))
2532 : : return true;
2533 : : }
2534 : : }
2535 : : return false;
2536 : :
2537 : 417642 : case RDIV_EXPR:
2538 : 417642 : if (fp_operation)
2539 : : {
2540 : 417642 : if (honor_snans)
2541 : : return true;
2542 : 409828 : return flag_trapping_math;
2543 : : }
2544 : : /* Fixed point operations also use RDIV_EXPR. */
2545 : 0 : if (!TREE_CONSTANT (divisor) || fixed_zerop (divisor))
2546 : 0 : 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 : 207883791 : case EQ_EXPR:
2561 : 207883791 : case NE_EXPR:
2562 : 207883791 : case UNORDERED_EXPR:
2563 : 207883791 : case ORDERED_EXPR:
2564 : 207883791 : case UNLT_EXPR:
2565 : 207883791 : case UNLE_EXPR:
2566 : 207883791 : case UNGT_EXPR:
2567 : 207883791 : case UNGE_EXPR:
2568 : 207883791 : case UNEQ_EXPR:
2569 : 207883791 : return honor_snans;
2570 : :
2571 : 1325430 : case NEGATE_EXPR:
2572 : 1325430 : case ABS_EXPR:
2573 : 1325430 : case CONJ_EXPR:
2574 : : /* These operations don't trap with floating point. */
2575 : 1325430 : if (honor_trapv)
2576 : : return true;
2577 : : return false;
2578 : :
2579 : : case ABSU_EXPR:
2580 : : /* ABSU_EXPR never traps. */
2581 : : return false;
2582 : :
2583 : 82009412 : case PLUS_EXPR:
2584 : 82009412 : case MINUS_EXPR:
2585 : 82009412 : case MULT_EXPR:
2586 : : /* Any floating arithmetic may trap. */
2587 : 82009412 : if (fp_operation && flag_trapping_math)
2588 : : return true;
2589 : 80294206 : 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 : 229792 : case FIX_TRUNC_EXPR:
2601 : 229792 : case VEC_PACK_FIX_TRUNC_EXPR:
2602 : 229792 : case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
2603 : 229792 : case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
2604 : : /* The FIX_TRUNC family are always potentially trapping. */
2605 : 229792 : return flag_trapping_math;
2606 : :
2607 : 75397 : case COND_EXPR:
2608 : 75397 : 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 : 75397 : *handled = false;
2613 : 75397 : return false;
2614 : :
2615 : 1473346563 : default:
2616 : : /* Any floating arithmetic may trap. */
2617 : 1473346563 : if (fp_operation && flag_trapping_math)
2618 : : return true;
2619 : :
2620 : 1471055686 : *handled = false;
2621 : 1471055686 : 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 : 4077919725 : operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
2632 : : tree divisor)
2633 : : {
2634 : 44755791 : bool honor_nans = (fp_operation && flag_trapping_math
2635 : 4111068916 : && !flag_finite_math_only);
2636 : 44755791 : bool honor_snans = fp_operation && flag_signaling_nans != 0;
2637 : 4077919725 : bool handled;
2638 : :
2639 : : /* This function cannot tell whether or not COND_EXPR could trap,
2640 : : because that depends on its condition op. */
2641 : 4077919725 : gcc_assert (op != COND_EXPR);
2642 : :
2643 : 4077919725 : if (TREE_CODE_CLASS (op) != tcc_comparison
2644 : : && TREE_CODE_CLASS (op) != tcc_unary
2645 : 4077919725 : && TREE_CODE_CLASS (op) != tcc_binary)
2646 : : return false;
2647 : :
2648 : 269370859 : return operation_could_trap_helper_p (op, fp_operation, honor_trapv,
2649 : : honor_nans, honor_snans, divisor,
2650 : 269370859 : &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 : 250242422 : in_array_bounds_p (tree ref)
2660 : : {
2661 : 250242422 : tree idx = TREE_OPERAND (ref, 1);
2662 : 250242422 : tree min, max;
2663 : :
2664 : 250242422 : if (TREE_CODE (idx) != INTEGER_CST)
2665 : : return false;
2666 : :
2667 : 247183842 : min = array_ref_low_bound (ref);
2668 : 247183842 : max = array_ref_up_bound (ref);
2669 : 247183842 : if (!min
2670 : 247183842 : || !max
2671 : 247167390 : || TREE_CODE (min) != INTEGER_CST
2672 : 247167390 : || TREE_CODE (max) != INTEGER_CST)
2673 : : return false;
2674 : :
2675 : 247162531 : if (tree_int_cst_lt (idx, min)
2676 : 247162531 : || tree_int_cst_lt (max, idx))
2677 : 54269 : 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 : 1874 : range_in_array_bounds_p (tree ref)
2688 : : {
2689 : 1874 : tree domain_type = TYPE_DOMAIN (TREE_TYPE (ref));
2690 : 1874 : tree range_min, range_max, min, max;
2691 : :
2692 : 1874 : range_min = TYPE_MIN_VALUE (domain_type);
2693 : 1874 : range_max = TYPE_MAX_VALUE (domain_type);
2694 : 1874 : if (!range_min
2695 : 1874 : || !range_max
2696 : 1874 : || TREE_CODE (range_min) != INTEGER_CST
2697 : 1874 : || TREE_CODE (range_max) != INTEGER_CST)
2698 : : return false;
2699 : :
2700 : 1874 : min = array_ref_low_bound (ref);
2701 : 1874 : max = array_ref_up_bound (ref);
2702 : 1874 : if (!min
2703 : 1874 : || !max
2704 : 1874 : || TREE_CODE (min) != INTEGER_CST
2705 : 1874 : || TREE_CODE (max) != INTEGER_CST)
2706 : : return false;
2707 : :
2708 : 1874 : if (tree_int_cst_lt (range_min, min)
2709 : 1874 : || tree_int_cst_lt (max, range_max))
2710 : 209 : 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 : 619437 : access_in_bounds_of_type_p (tree type, poly_uint64 size, poly_uint64 offset)
2720 : : {
2721 : 619437 : tree type_size_tree;
2722 : 619437 : poly_uint64 type_size_max, min = offset, wid = size, max;
2723 : :
2724 : 619437 : type_size_tree = TYPE_SIZE (type);
2725 : 619437 : if (!type_size_tree || !poly_int_tree_p (type_size_tree, &type_size_max))
2726 : 20 : return false;
2727 : :
2728 : 619417 : max = min + wid;
2729 : 619417 : if (maybe_lt (max, min)
2730 : 619417 : || maybe_lt (type_size_max, max))
2731 : : 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 : 244763403 : ref_outside_object_p (tree size, poly_offset_int off, tree refsz)
2741 : : {
2742 : 244763403 : if (size == NULL_TREE
2743 : 244763403 : || refsz == NULL_TREE
2744 : 244750021 : || !poly_int_tree_p (size)
2745 : 244749978 : || !poly_int_tree_p (refsz)
2746 : 244734186 : || maybe_le (wi::to_poly_offset (size), off)
2747 : 489425652 : || maybe_gt (off + wi::to_poly_offset (refsz),
2748 : : wi::to_poly_offset (size)))
2749 : 253531 : return true;
2750 : : /* Now we are sure the whole base of the access is inside
2751 : : the object. */
2752 : : return false;
2753 : : }
2754 : :
2755 : : /* Return true if EXPR can trap, as in dereferencing an invalid pointer
2756 : : location or floating point arithmetic. C.f. the rtl version, may_trap_p.
2757 : : This routine expects only GIMPLE lhs or rhs input. */
2758 : :
2759 : : bool
2760 : 3808505893 : tree_could_trap_p (tree expr)
2761 : : {
2762 : 3808505893 : enum tree_code code;
2763 : 3808505893 : bool fp_operation = false;
2764 : 3808505893 : bool honor_trapv = false;
2765 : 3808505893 : tree t, base, div = NULL_TREE;
2766 : :
2767 : 3808505893 : if (!expr)
2768 : : return false;
2769 : :
2770 : : /* In COND_EXPR and VEC_COND_EXPR only the condition may trap, but
2771 : : they won't appear as operands in GIMPLE form, so this is just for the
2772 : : GENERIC uses where it needs to recurse on the operands and so
2773 : : *COND_EXPR itself doesn't trap. */
2774 : 3803626508 : if (TREE_CODE (expr) == COND_EXPR || TREE_CODE (expr) == VEC_COND_EXPR)
2775 : : return false;
2776 : :
2777 : 3803625209 : code = TREE_CODE (expr);
2778 : 3803625209 : t = TREE_TYPE (expr);
2779 : :
2780 : 3803625209 : if (t)
2781 : : {
2782 : 3803617829 : if (COMPARISON_CLASS_P (expr))
2783 : 5988128 : fp_operation = FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
2784 : : else
2785 : 3797629701 : fp_operation = FLOAT_TYPE_P (t);
2786 : 3803617829 : honor_trapv = INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t);
2787 : : }
2788 : :
2789 : 3803625209 : if (TREE_CODE_CLASS (code) == tcc_binary)
2790 : 402099 : div = TREE_OPERAND (expr, 1);
2791 : 3803625209 : if (operation_could_trap_p (code, fp_operation, honor_trapv, div))
2792 : : return true;
2793 : :
2794 : 3802268342 : restart:
2795 : 4739988993 : switch (code)
2796 : : {
2797 : 1244375 : case BIT_FIELD_REF:
2798 : 1244375 : if (DECL_P (TREE_OPERAND (expr, 0))
2799 : 1244375 : && !access_in_bounds_of_type_p (TREE_TYPE (TREE_OPERAND (expr, 0)),
2800 : : bit_field_size (expr),
2801 : : bit_field_offset (expr)))
2802 : : return true;
2803 : : /* Fall through. */
2804 : :
2805 : 937720651 : case COMPONENT_REF:
2806 : 937720651 : case REALPART_EXPR:
2807 : 937720651 : case IMAGPART_EXPR:
2808 : 937720651 : case VIEW_CONVERT_EXPR:
2809 : 937720651 : case WITH_SIZE_EXPR:
2810 : 937720651 : expr = TREE_OPERAND (expr, 0);
2811 : 937720651 : code = TREE_CODE (expr);
2812 : 937720651 : goto restart;
2813 : :
2814 : 2097 : case ARRAY_RANGE_REF:
2815 : 2097 : base = TREE_OPERAND (expr, 0);
2816 : 2097 : if (tree_could_trap_p (base))
2817 : : return true;
2818 : 1874 : if (TREE_THIS_NOTRAP (expr))
2819 : : return false;
2820 : 1874 : return !range_in_array_bounds_p (expr);
2821 : :
2822 : 261125113 : case ARRAY_REF:
2823 : 261125113 : base = TREE_OPERAND (expr, 0);
2824 : 261125113 : if (tree_could_trap_p (base))
2825 : : return true;
2826 : 250272288 : if (TREE_THIS_NOTRAP (expr))
2827 : : return false;
2828 : 250242422 : return !in_array_bounds_p (expr);
2829 : :
2830 : 639795528 : case TARGET_MEM_REF:
2831 : 639795528 : case MEM_REF:
2832 : 639795528 : if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR
2833 : 639795528 : && tree_could_trap_p (TREE_OPERAND (TREE_OPERAND (expr, 0), 0)))
2834 : : return true;
2835 : 639795528 : if (TREE_THIS_NOTRAP (expr))
2836 : : return false;
2837 : : /* We cannot prove that the access is in-bounds when we have
2838 : : variable-index TARGET_MEM_REFs. */
2839 : 549602497 : if (code == TARGET_MEM_REF
2840 : 558024676 : && (TMR_INDEX (expr) || TMR_INDEX2 (expr)))
2841 : : return true;
2842 : 541993574 : if (TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
2843 : : {
2844 : 242649964 : tree base = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
2845 : 242649964 : poly_offset_int off = mem_ref_offset (expr);
2846 : 242649964 : if (maybe_lt (off, 0))
2847 : : return true;
2848 : 242646891 : if (TREE_CODE (base) == STRING_CST)
2849 : 192901 : return maybe_le (TREE_STRING_LENGTH (base), off);
2850 : 242453990 : tree size = DECL_SIZE_UNIT (base);
2851 : 242453990 : tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
2852 : 242453990 : return ref_outside_object_p (size, off, refsz);
2853 : : }
2854 : 299343610 : if (cfun
2855 : 299186346 : && TREE_CODE (TREE_TYPE (cfun->decl)) == METHOD_TYPE
2856 : 305139166 : && ((TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
2857 : 4944407 : && SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (expr, 0))
2858 : 2889616 : && (SSA_NAME_VAR (TREE_OPERAND (expr, 0))
2859 : 2889616 : == DECL_ARGUMENTS (cfun->decl)))
2860 : 3494470 : || TREE_OPERAND (expr, 0) == DECL_ARGUMENTS (cfun->decl)))
2861 : : {
2862 : 2311318 : poly_offset_int off = mem_ref_offset (expr);
2863 : 2311318 : if (maybe_lt (off, 0))
2864 : : return true;
2865 : 2309413 : tree size = TYPE_SIZE_UNIT
2866 : : (TYPE_METHOD_BASETYPE (TREE_TYPE (cfun->decl)));
2867 : 2309413 : tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
2868 : 2309413 : return ref_outside_object_p (size, off, refsz);
2869 : : }
2870 : : return true;
2871 : :
2872 : 780782 : case INDIRECT_REF:
2873 : 780782 : return !TREE_THIS_NOTRAP (expr);
2874 : :
2875 : 0 : case ASM_EXPR:
2876 : 0 : return TREE_THIS_VOLATILE (expr);
2877 : :
2878 : 335360 : case CALL_EXPR:
2879 : : /* Internal function calls do not trap. */
2880 : 335360 : if (CALL_EXPR_FN (expr) == NULL_TREE)
2881 : : return false;
2882 : 335236 : t = get_callee_fndecl (expr);
2883 : : /* Assume that indirect and calls to weak functions may trap. */
2884 : 335236 : if (!t || !DECL_P (t))
2885 : : return true;
2886 : 335236 : if (DECL_WEAK (t))
2887 : : return tree_could_trap_p (t);
2888 : : return false;
2889 : :
2890 : 3074 : case FUNCTION_DECL:
2891 : : /* Assume that accesses to weak functions may trap, unless we know
2892 : : they are certainly defined in current TU or in some other
2893 : : LTO partition. */
2894 : 3074 : if (DECL_WEAK (expr) && !DECL_COMDAT (expr) && DECL_EXTERNAL (expr))
2895 : : {
2896 : 13 : cgraph_node *node = cgraph_node::get (expr);
2897 : 13 : if (node)
2898 : 13 : node = node->function_symbol ();
2899 : 26 : return !(node && node->in_other_partition);
2900 : : }
2901 : : return false;
2902 : :
2903 : 1049893628 : case VAR_DECL:
2904 : : /* Assume that accesses to weak vars may trap, unless we know
2905 : : they are certainly defined in current TU or in some other
2906 : : LTO partition. */
2907 : 1049893628 : if (DECL_WEAK (expr) && !DECL_COMDAT (expr) && DECL_EXTERNAL (expr))
2908 : : {
2909 : 14965 : varpool_node *node = varpool_node::get (expr);
2910 : 14965 : if (node)
2911 : 14920 : node = node->ultimate_alias_target ();
2912 : 29885 : return !(node && node->in_other_partition);
2913 : : }
2914 : : return false;
2915 : :
2916 : : default:
2917 : : return false;
2918 : : }
2919 : : }
2920 : :
2921 : : /* Return non-NULL if there is an integer operation with trapping overflow
2922 : : we can rewrite into non-trapping. Called via walk_tree from
2923 : : rewrite_to_non_trapping_overflow. */
2924 : :
2925 : : static tree
2926 : 270 : find_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
2927 : : {
2928 : 270 : if (EXPR_P (*tp)
2929 : 159 : && ANY_INTEGRAL_TYPE_P (TREE_TYPE (*tp))
2930 : 407 : && !operation_no_trapping_overflow (TREE_TYPE (*tp), TREE_CODE (*tp)))
2931 : 9 : return *tp;
2932 : 261 : if (IS_TYPE_OR_DECL_P (*tp)
2933 : 258 : || (TREE_CODE (*tp) == SAVE_EXPR && data == NULL))
2934 : 3 : *walk_subtrees = 0;
2935 : : return NULL_TREE;
2936 : : }
2937 : :
2938 : : /* Rewrite selected operations into unsigned arithmetics, so that they
2939 : : don't trap on overflow. */
2940 : :
2941 : : static tree
2942 : 74 : replace_trapping_overflow (tree *tp, int *walk_subtrees, void *data)
2943 : : {
2944 : 74 : if (find_trapping_overflow (tp, walk_subtrees, data))
2945 : : {
2946 : 6 : tree type = TREE_TYPE (*tp);
2947 : 6 : tree utype = unsigned_type_for (type);
2948 : 6 : *walk_subtrees = 0;
2949 : 6 : int len = TREE_OPERAND_LENGTH (*tp);
2950 : 18 : for (int i = 0; i < len; ++i)
2951 : 12 : walk_tree (&TREE_OPERAND (*tp, i), replace_trapping_overflow,
2952 : : data, (hash_set<tree> *) data);
2953 : :
2954 : 6 : if (TREE_CODE (*tp) == ABS_EXPR)
2955 : : {
2956 : 0 : TREE_SET_CODE (*tp, ABSU_EXPR);
2957 : 0 : TREE_TYPE (*tp) = utype;
2958 : 0 : *tp = fold_convert (type, *tp);
2959 : : }
2960 : : else
2961 : : {
2962 : 6 : TREE_TYPE (*tp) = utype;
2963 : 6 : len = TREE_OPERAND_LENGTH (*tp);
2964 : 18 : for (int i = 0; i < len; ++i)
2965 : 12 : TREE_OPERAND (*tp, i)
2966 : 24 : = fold_convert (utype, TREE_OPERAND (*tp, i));
2967 : 6 : *tp = fold_convert (type, *tp);
2968 : : }
2969 : : }
2970 : 74 : return NULL_TREE;
2971 : : }
2972 : :
2973 : : /* If any subexpression of EXPR can trap due to -ftrapv, rewrite it
2974 : : using unsigned arithmetics to avoid traps in it. */
2975 : :
2976 : : tree
2977 : 46563 : rewrite_to_non_trapping_overflow (tree expr)
2978 : : {
2979 : 46563 : if (!flag_trapv)
2980 : 46526 : return expr;
2981 : 37 : hash_set<tree> pset;
2982 : 37 : if (!walk_tree (&expr, find_trapping_overflow, &pset, &pset))
2983 : 34 : return expr;
2984 : 3 : expr = unshare_expr (expr);
2985 : 3 : pset.empty ();
2986 : 3 : walk_tree (&expr, replace_trapping_overflow, &pset, &pset);
2987 : 3 : return expr;
2988 : 37 : }
2989 : :
2990 : : /* Helper for stmt_could_throw_p. Return true if STMT (assumed to be a
2991 : : an assignment or a conditional) may throw. */
2992 : :
2993 : : static bool
2994 : 1643681177 : stmt_could_throw_1_p (gassign *stmt)
2995 : : {
2996 : 1643681177 : enum tree_code code = gimple_assign_rhs_code (stmt);
2997 : 1643681177 : bool honor_nans = false;
2998 : 1643681177 : bool honor_snans = false;
2999 : 1643681177 : bool fp_operation = false;
3000 : 1643681177 : bool honor_trapv = false;
3001 : 1643681177 : tree t;
3002 : 1643681177 : size_t i;
3003 : 1643681177 : bool handled, ret;
3004 : :
3005 : 1643681177 : if (TREE_CODE_CLASS (code) == tcc_comparison
3006 : : || TREE_CODE_CLASS (code) == tcc_unary
3007 : 1643681177 : || TREE_CODE_CLASS (code) == tcc_binary)
3008 : : {
3009 : 235395314 : if (TREE_CODE_CLASS (code) == tcc_comparison)
3010 : 30959285 : t = TREE_TYPE (gimple_assign_rhs1 (stmt));
3011 : : else
3012 : 204436029 : t = TREE_TYPE (gimple_assign_lhs (stmt));
3013 : 235395314 : fp_operation = FLOAT_TYPE_P (t);
3014 : 235395314 : if (fp_operation)
3015 : : {
3016 : 7402469 : honor_nans = flag_trapping_math && !flag_finite_math_only;
3017 : 7402469 : honor_snans = flag_signaling_nans != 0;
3018 : : }
3019 : 227992845 : else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
3020 : : honor_trapv = true;
3021 : : }
3022 : :
3023 : : /* First check the LHS. */
3024 : 1643681177 : if (tree_could_trap_p (gimple_assign_lhs (stmt)))
3025 : : return true;
3026 : :
3027 : : /* Check if the main expression may trap. */
3028 : 1722440172 : ret = operation_could_trap_helper_p (code, fp_operation, honor_trapv,
3029 : : honor_nans, honor_snans,
3030 : : gimple_assign_rhs2 (stmt),
3031 : : &handled);
3032 : 1572543697 : if (handled)
3033 : : return ret;
3034 : :
3035 : : /* If the expression does not trap, see if any of the individual operands may
3036 : : trap. */
3037 : 2742866560 : for (i = 1; i < gimple_num_ops (stmt); i++)
3038 : 1506910240 : if (tree_could_trap_p (gimple_op (stmt, i)))
3039 : : return true;
3040 : :
3041 : : return false;
3042 : : }
3043 : :
3044 : :
3045 : : /* Return true if statement STMT within FUN could throw an exception. */
3046 : :
3047 : : bool
3048 : 16810739988 : stmt_could_throw_p (function *fun, gimple *stmt)
3049 : : {
3050 : 16810739988 : if (!flag_exceptions)
3051 : : return false;
3052 : :
3053 : : /* The only statements that can throw an exception are assignments,
3054 : : conditionals, calls, resx, and asms. */
3055 : 12614586601 : switch (gimple_code (stmt))
3056 : : {
3057 : : case GIMPLE_RESX:
3058 : : return true;
3059 : :
3060 : 1069837324 : case GIMPLE_CALL:
3061 : 1069837324 : return !gimple_call_nothrow_p (as_a <gcall *> (stmt));
3062 : :
3063 : 198401152 : case GIMPLE_COND:
3064 : 198401152 : {
3065 : 198401152 : if (fun && !fun->can_throw_non_call_exceptions)
3066 : : return false;
3067 : 67529772 : gcond *cond = as_a <gcond *> (stmt);
3068 : 67529772 : tree lhs = gimple_cond_lhs (cond);
3069 : 67529772 : return operation_could_trap_p (gimple_cond_code (cond),
3070 : 67529772 : FLOAT_TYPE_P (TREE_TYPE (lhs)),
3071 : 67529772 : false, NULL_TREE);
3072 : : }
3073 : :
3074 : 3966773386 : case GIMPLE_ASSIGN:
3075 : 3966773386 : if ((fun && !fun->can_throw_non_call_exceptions)
3076 : 5658837308 : || gimple_clobber_p (stmt))
3077 : : return false;
3078 : 1643681177 : return stmt_could_throw_1_p (as_a <gassign *> (stmt));
3079 : :
3080 : 759642 : case GIMPLE_ASM:
3081 : 759642 : if (fun && !fun->can_throw_non_call_exceptions)
3082 : : return false;
3083 : 59391 : return gimple_asm_volatile_p (as_a <gasm *> (stmt));
3084 : :
3085 : : default:
3086 : : return false;
3087 : : }
3088 : : }
3089 : :
3090 : : /* Return true if STMT in function FUN must be assumed necessary because of
3091 : : non-call exceptions. */
3092 : :
3093 : : bool
3094 : 25833266 : stmt_unremovable_because_of_non_call_eh_p (function *fun, gimple *stmt)
3095 : : {
3096 : 25833266 : return (fun->can_throw_non_call_exceptions
3097 : 5789277 : && !fun->can_delete_dead_exceptions
3098 : 31601084 : && stmt_could_throw_p (fun, stmt));
3099 : : }
3100 : :
3101 : : /* Return true if expression T could throw an exception. */
3102 : :
3103 : : bool
3104 : 42230782 : tree_could_throw_p (tree t)
3105 : : {
3106 : 42230782 : if (!flag_exceptions)
3107 : : return false;
3108 : 35761901 : if (TREE_CODE (t) == MODIFY_EXPR)
3109 : : {
3110 : 0 : if (cfun->can_throw_non_call_exceptions
3111 : 0 : && tree_could_trap_p (TREE_OPERAND (t, 0)))
3112 : : return true;
3113 : 0 : t = TREE_OPERAND (t, 1);
3114 : : }
3115 : :
3116 : 35761901 : if (TREE_CODE (t) == WITH_SIZE_EXPR)
3117 : 0 : t = TREE_OPERAND (t, 0);
3118 : 35761901 : if (TREE_CODE (t) == CALL_EXPR)
3119 : 417086 : return (call_expr_flags (t) & ECF_NOTHROW) == 0;
3120 : 35344815 : if (cfun->can_throw_non_call_exceptions)
3121 : 22190550 : return tree_could_trap_p (t);
3122 : : return false;
3123 : : }
3124 : :
3125 : : /* Return true if STMT can throw an exception that is not caught within its
3126 : : function FUN. FUN can be NULL but the function is extra conservative
3127 : : then. */
3128 : :
3129 : : bool
3130 : 871311804 : stmt_can_throw_external (function *fun, gimple *stmt)
3131 : : {
3132 : 871311804 : int lp_nr;
3133 : :
3134 : 871311804 : if (!stmt_could_throw_p (fun, stmt))
3135 : : return false;
3136 : 45954839 : if (!fun)
3137 : : return true;
3138 : :
3139 : 45948636 : lp_nr = lookup_stmt_eh_lp_fn (fun, stmt);
3140 : 45948636 : return lp_nr == 0;
3141 : : }
3142 : :
3143 : : /* Return true if STMT can throw an exception that is caught within its
3144 : : function FUN. */
3145 : :
3146 : : bool
3147 : 14470046518 : stmt_can_throw_internal (function *fun, gimple *stmt)
3148 : : {
3149 : 14470046518 : int lp_nr;
3150 : :
3151 : 14470046518 : gcc_checking_assert (fun);
3152 : 14470046518 : if (!stmt_could_throw_p (fun, stmt))
3153 : : return false;
3154 : :
3155 : 618782951 : lp_nr = lookup_stmt_eh_lp_fn (fun, stmt);
3156 : 618782951 : return lp_nr > 0;
3157 : : }
3158 : :
3159 : : /* Given a statement STMT in IFUN, if STMT can no longer throw, then
3160 : : remove any entry it might have from the EH table. Return true if
3161 : : any change was made. */
3162 : :
3163 : : bool
3164 : 189098722 : maybe_clean_eh_stmt_fn (struct function *ifun, gimple *stmt)
3165 : : {
3166 : 189098722 : if (stmt_could_throw_p (ifun, stmt))
3167 : : return false;
3168 : 172128533 : return remove_stmt_from_eh_lp_fn (ifun, stmt);
3169 : : }
3170 : :
3171 : : /* Likewise, but always use the current function. */
3172 : :
3173 : : bool
3174 : 189098722 : maybe_clean_eh_stmt (gimple *stmt)
3175 : : {
3176 : 189098722 : return maybe_clean_eh_stmt_fn (cfun, stmt);
3177 : : }
3178 : :
3179 : : /* Given a statement OLD_STMT and a new statement NEW_STMT that has replaced
3180 : : OLD_STMT in the function, remove OLD_STMT from the EH table and put NEW_STMT
3181 : : in the table if it should be in there. Return TRUE if a replacement was
3182 : : done that my require an EH edge purge. */
3183 : :
3184 : : bool
3185 : 46413138 : maybe_clean_or_replace_eh_stmt (gimple *old_stmt, gimple *new_stmt)
3186 : : {
3187 : 46413138 : int lp_nr = lookup_stmt_eh_lp (old_stmt);
3188 : :
3189 : 46413138 : if (lp_nr != 0)
3190 : : {
3191 : 1542077 : bool new_stmt_could_throw = stmt_could_throw_p (cfun, new_stmt);
3192 : :
3193 : 1542077 : if (new_stmt == old_stmt && new_stmt_could_throw)
3194 : : return false;
3195 : :
3196 : 317629 : remove_stmt_from_eh_lp (old_stmt);
3197 : 317629 : if (new_stmt_could_throw)
3198 : : {
3199 : 317 : add_stmt_to_eh_lp (new_stmt, lp_nr);
3200 : 317 : return false;
3201 : : }
3202 : : else
3203 : : return true;
3204 : : }
3205 : :
3206 : : return false;
3207 : : }
3208 : :
3209 : : /* Given a statement OLD_STMT in OLD_FUN and a duplicate statement NEW_STMT
3210 : : in NEW_FUN, copy the EH table data from OLD_STMT to NEW_STMT. The MAP
3211 : : operand is the return value of duplicate_eh_regions. */
3212 : :
3213 : : bool
3214 : 85838370 : maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple *new_stmt,
3215 : : struct function *old_fun, gimple *old_stmt,
3216 : : hash_map<void *, void *> *map,
3217 : : int default_lp_nr)
3218 : : {
3219 : 85838370 : int old_lp_nr, new_lp_nr;
3220 : :
3221 : 85838370 : if (!stmt_could_throw_p (new_fun, new_stmt))
3222 : : return false;
3223 : :
3224 : 1692244 : old_lp_nr = lookup_stmt_eh_lp_fn (old_fun, old_stmt);
3225 : 1692244 : if (old_lp_nr == 0)
3226 : : {
3227 : 1501469 : if (default_lp_nr == 0)
3228 : : return false;
3229 : : new_lp_nr = default_lp_nr;
3230 : : }
3231 : 190775 : else if (old_lp_nr > 0)
3232 : : {
3233 : 137256 : eh_landing_pad old_lp, new_lp;
3234 : :
3235 : 137256 : old_lp = (*old_fun->eh->lp_array)[old_lp_nr];
3236 : 137256 : new_lp = static_cast<eh_landing_pad> (*map->get (old_lp));
3237 : 137256 : new_lp_nr = new_lp->index;
3238 : : }
3239 : : else
3240 : : {
3241 : 53519 : eh_region old_r, new_r;
3242 : :
3243 : 53519 : old_r = (*old_fun->eh->region_array)[-old_lp_nr];
3244 : 53519 : new_r = static_cast<eh_region> (*map->get (old_r));
3245 : 53519 : new_lp_nr = -new_r->index;
3246 : : }
3247 : :
3248 : 783982 : add_stmt_to_eh_lp_fn (new_fun, new_stmt, new_lp_nr);
3249 : 783982 : return true;
3250 : : }
3251 : :
3252 : : /* Similar, but both OLD_STMT and NEW_STMT are within the current function,
3253 : : and thus no remapping is required. */
3254 : :
3255 : : bool
3256 : 21448901 : maybe_duplicate_eh_stmt (gimple *new_stmt, gimple *old_stmt)
3257 : : {
3258 : 21448901 : int lp_nr;
3259 : :
3260 : 21448901 : if (!stmt_could_throw_p (cfun, new_stmt))
3261 : : return false;
3262 : :
3263 : 65215 : lp_nr = lookup_stmt_eh_lp (old_stmt);
3264 : 65215 : if (lp_nr == 0)
3265 : : return false;
3266 : :
3267 : 7144 : add_stmt_to_eh_lp (new_stmt, lp_nr);
3268 : 7144 : return true;
3269 : : }
3270 : :
3271 : : /* Returns TRUE if oneh and twoh are exception handlers (gimple_try_cleanup of
3272 : : GIMPLE_TRY) that are similar enough to be considered the same. Currently
3273 : : this only handles handlers consisting of a single call, as that's the
3274 : : important case for C++: a destructor call for a particular object showing
3275 : : up in multiple handlers. */
3276 : :
3277 : : static bool
3278 : 1 : same_handler_p (gimple_seq oneh, gimple_seq twoh)
3279 : : {
3280 : 1 : gimple_stmt_iterator gsi;
3281 : 1 : gimple *ones, *twos;
3282 : 1 : unsigned int ai;
3283 : :
3284 : 1 : gsi = gsi_start (oneh);
3285 : 1 : if (!gsi_one_before_end_p (gsi))
3286 : : return false;
3287 : 1 : ones = gsi_stmt (gsi);
3288 : :
3289 : 1 : gsi = gsi_start (twoh);
3290 : 1 : if (!gsi_one_before_end_p (gsi))
3291 : : return false;
3292 : 1 : twos = gsi_stmt (gsi);
3293 : :
3294 : 1 : if (!is_gimple_call (ones)
3295 : 1 : || !is_gimple_call (twos)
3296 : 1 : || gimple_call_lhs (ones)
3297 : 1 : || gimple_call_lhs (twos)
3298 : 1 : || gimple_call_chain (ones)
3299 : 1 : || gimple_call_chain (twos)
3300 : 1 : || !gimple_call_same_target_p (ones, twos)
3301 : 2 : || gimple_call_num_args (ones) != gimple_call_num_args (twos))
3302 : 0 : return false;
3303 : :
3304 : 2 : for (ai = 0; ai < gimple_call_num_args (ones); ++ai)
3305 : 1 : if (!operand_equal_p (gimple_call_arg (ones, ai),
3306 : 1 : gimple_call_arg (twos, ai), 0))
3307 : : return false;
3308 : :
3309 : : return true;
3310 : : }
3311 : :
3312 : : /* Optimize
3313 : : try { A() } finally { try { ~B() } catch { ~A() } }
3314 : : try { ... } finally { ~A() }
3315 : : into
3316 : : try { A() } catch { ~B() }
3317 : : try { ~B() ... } finally { ~A() }
3318 : :
3319 : : This occurs frequently in C++, where A is a local variable and B is a
3320 : : temporary used in the initializer for A. */
3321 : :
3322 : : static void
3323 : 53382 : optimize_double_finally (gtry *one, gtry *two)
3324 : : {
3325 : 53382 : gimple *oneh;
3326 : 53382 : gimple_stmt_iterator gsi;
3327 : 53382 : gimple_seq cleanup;
3328 : :
3329 : 53382 : cleanup = gimple_try_cleanup (one);
3330 : 53382 : gsi = gsi_start (cleanup);
3331 : 53382 : if (!gsi_one_before_end_p (gsi))
3332 : 53382 : return;
3333 : :
3334 : 52016 : oneh = gsi_stmt (gsi);
3335 : 52016 : if (gimple_code (oneh) != GIMPLE_TRY
3336 : 52016 : || gimple_try_kind (oneh) != GIMPLE_TRY_CATCH)
3337 : : return;
3338 : :
3339 : 1 : if (same_handler_p (gimple_try_cleanup (oneh), gimple_try_cleanup (two)))
3340 : : {
3341 : 1 : gimple_seq seq = gimple_try_eval (oneh);
3342 : :
3343 : 1 : gimple_try_set_cleanup (one, seq);
3344 : 1 : gimple_try_set_kind (one, GIMPLE_TRY_CATCH);
3345 : 1 : seq = copy_gimple_seq_and_replace_locals (seq);
3346 : 1 : gimple_seq_add_seq (&seq, gimple_try_eval (two));
3347 : 1 : gimple_try_set_eval (two, seq);
3348 : : }
3349 : : }
3350 : :
3351 : : /* Perform EH refactoring optimizations that are simpler to do when code
3352 : : flow has been lowered but EH structures haven't. */
3353 : :
3354 : : static void
3355 : 6576683 : refactor_eh_r (gimple_seq seq)
3356 : : {
3357 : 6576683 : gimple_stmt_iterator gsi;
3358 : 6576683 : gimple *one, *two;
3359 : :
3360 : 6576683 : one = NULL;
3361 : 6576683 : two = NULL;
3362 : 6576683 : gsi = gsi_start (seq);
3363 : 51252271 : while (1)
3364 : : {
3365 : 57828954 : one = two;
3366 : 57828954 : if (gsi_end_p (gsi))
3367 : : two = NULL;
3368 : : else
3369 : : two = gsi_stmt (gsi);
3370 : 57828954 : if (one && two)
3371 : 44820672 : if (gtry *try_one = dyn_cast <gtry *> (one))
3372 : 1458028 : if (gtry *try_two = dyn_cast <gtry *> (two))
3373 : 68272 : if (gimple_try_kind (try_one) == GIMPLE_TRY_FINALLY
3374 : 68272 : && gimple_try_kind (try_two) == GIMPLE_TRY_FINALLY)
3375 : 53382 : optimize_double_finally (try_one, try_two);
3376 : 57828954 : if (one)
3377 : 51252271 : switch (gimple_code (one))
3378 : : {
3379 : 2153223 : case GIMPLE_TRY:
3380 : 2153223 : refactor_eh_r (gimple_try_eval (one));
3381 : 2153223 : refactor_eh_r (gimple_try_cleanup (one));
3382 : 2153223 : break;
3383 : 39678 : case GIMPLE_CATCH:
3384 : 39678 : refactor_eh_r (gimple_catch_handler (as_a <gcatch *> (one)));
3385 : 39678 : break;
3386 : 4732 : case GIMPLE_EH_FILTER:
3387 : 4732 : refactor_eh_r (gimple_eh_filter_failure (one));
3388 : 4732 : break;
3389 : 635 : case GIMPLE_EH_ELSE:
3390 : 635 : {
3391 : 635 : geh_else *eh_else_stmt = as_a <geh_else *> (one);
3392 : 635 : refactor_eh_r (gimple_eh_else_n_body (eh_else_stmt));
3393 : 635 : refactor_eh_r (gimple_eh_else_e_body (eh_else_stmt));
3394 : : }
3395 : 635 : break;
3396 : : default:
3397 : : break;
3398 : : }
3399 : 57828954 : if (two)
3400 : 51252271 : gsi_next (&gsi);
3401 : : else
3402 : : break;
3403 : : }
3404 : 6576683 : }
3405 : :
3406 : : namespace {
3407 : :
3408 : : const pass_data pass_data_refactor_eh =
3409 : : {
3410 : : GIMPLE_PASS, /* type */
3411 : : "ehopt", /* name */
3412 : : OPTGROUP_NONE, /* optinfo_flags */
3413 : : TV_TREE_EH, /* tv_id */
3414 : : PROP_gimple_lcf, /* properties_required */
3415 : : 0, /* properties_provided */
3416 : : 0, /* properties_destroyed */
3417 : : 0, /* todo_flags_start */
3418 : : 0, /* todo_flags_finish */
3419 : : };
3420 : :
3421 : : class pass_refactor_eh : public gimple_opt_pass
3422 : : {
3423 : : public:
3424 : 290033 : pass_refactor_eh (gcc::context *ctxt)
3425 : 580066 : : gimple_opt_pass (pass_data_refactor_eh, ctxt)
3426 : : {}
3427 : :
3428 : : /* opt_pass methods: */
3429 : 2962021 : bool gate (function *) final override { return flag_exceptions != 0; }
3430 : 2224557 : unsigned int execute (function *) final override
3431 : : {
3432 : 2224557 : refactor_eh_r (gimple_body (current_function_decl));
3433 : 2224557 : return 0;
3434 : : }
3435 : :
3436 : : }; // class pass_refactor_eh
3437 : :
3438 : : } // anon namespace
3439 : :
3440 : : gimple_opt_pass *
3441 : 290033 : make_pass_refactor_eh (gcc::context *ctxt)
3442 : : {
3443 : 290033 : return new pass_refactor_eh (ctxt);
3444 : : }
3445 : :
3446 : : /* At the end of gimple optimization, we can lower RESX. */
3447 : :
3448 : : static bool
3449 : 177067 : lower_resx (basic_block bb, gresx *stmt,
3450 : : hash_map<eh_region, tree> *mnt_map)
3451 : : {
3452 : 177067 : int lp_nr;
3453 : 177067 : eh_region src_r, dst_r;
3454 : 177067 : gimple_stmt_iterator gsi;
3455 : 177067 : gcall *x;
3456 : 177067 : tree fn, src_nr;
3457 : 177067 : bool ret = false;
3458 : :
3459 : 177067 : lp_nr = lookup_stmt_eh_lp (stmt);
3460 : 177067 : if (lp_nr != 0)
3461 : 98454 : dst_r = get_eh_region_from_lp_number (lp_nr);
3462 : : else
3463 : 78613 : dst_r = NULL;
3464 : :
3465 : 177067 : src_r = get_eh_region_from_number (gimple_resx_region (stmt));
3466 : 177067 : gsi = gsi_last_bb (bb);
3467 : :
3468 : 177067 : if (src_r == NULL)
3469 : : {
3470 : : /* We can wind up with no source region when pass_cleanup_eh shows
3471 : : that there are no entries into an eh region and deletes it, but
3472 : : then the block that contains the resx isn't removed. This can
3473 : : happen without optimization when the switch statement created by
3474 : : lower_try_finally_switch isn't simplified to remove the eh case.
3475 : :
3476 : : Resolve this by expanding the resx node to an abort. */
3477 : :
3478 : 0 : fn = builtin_decl_implicit (BUILT_IN_TRAP);
3479 : 0 : x = gimple_build_call (fn, 0);
3480 : 0 : gimple_call_set_ctrl_altering (x, true);
3481 : 0 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3482 : :
3483 : 0 : while (EDGE_COUNT (bb->succs) > 0)
3484 : 0 : remove_edge (EDGE_SUCC (bb, 0));
3485 : : }
3486 : 177067 : else if (dst_r)
3487 : : {
3488 : : /* When we have a destination region, we resolve this by copying
3489 : : the excptr and filter values into place, and changing the edge
3490 : : to immediately after the landing pad. */
3491 : 98454 : edge e;
3492 : :
3493 : 98454 : if (lp_nr < 0)
3494 : : {
3495 : 407 : basic_block new_bb;
3496 : 407 : tree lab;
3497 : :
3498 : : /* We are resuming into a MUST_NOT_CALL region. Expand a call to
3499 : : the failure decl into a new block, if needed. */
3500 : 407 : gcc_assert (dst_r->type == ERT_MUST_NOT_THROW);
3501 : :
3502 : 407 : tree *slot = mnt_map->get (dst_r);
3503 : 407 : if (slot == NULL)
3504 : : {
3505 : 354 : gimple_stmt_iterator gsi2;
3506 : :
3507 : 354 : new_bb = create_empty_bb (bb);
3508 : 354 : new_bb->count = bb->count;
3509 : 354 : add_bb_to_loop (new_bb, bb->loop_father);
3510 : 354 : lab = gimple_block_label (new_bb);
3511 : 354 : gsi2 = gsi_start_bb (new_bb);
3512 : :
3513 : : /* Handle failure fns that expect either no arguments or the
3514 : : exception pointer. */
3515 : 354 : fn = dst_r->u.must_not_throw.failure_decl;
3516 : 354 : if (TYPE_ARG_TYPES (TREE_TYPE (fn)) != void_list_node)
3517 : : {
3518 : 354 : tree epfn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
3519 : 354 : src_nr = build_int_cst (integer_type_node, src_r->index);
3520 : 354 : x = gimple_build_call (epfn, 1, src_nr);
3521 : 354 : tree var = create_tmp_var (ptr_type_node);
3522 : 354 : var = make_ssa_name (var, x);
3523 : 354 : gimple_call_set_lhs (x, var);
3524 : 354 : gsi_insert_after (&gsi2, x, GSI_CONTINUE_LINKING);
3525 : 354 : x = gimple_build_call (fn, 1, var);
3526 : : }
3527 : : else
3528 : 0 : x = gimple_build_call (fn, 0);
3529 : 354 : gimple_set_location (x, dst_r->u.must_not_throw.failure_loc);
3530 : 354 : gsi_insert_after (&gsi2, x, GSI_CONTINUE_LINKING);
3531 : :
3532 : 354 : mnt_map->put (dst_r, lab);
3533 : : }
3534 : : else
3535 : : {
3536 : 53 : lab = *slot;
3537 : 53 : new_bb = label_to_block (cfun, lab);
3538 : : }
3539 : :
3540 : 407 : gcc_assert (EDGE_COUNT (bb->succs) == 0);
3541 : 407 : e = make_single_succ_edge (bb, new_bb, EDGE_FALLTHRU);
3542 : : }
3543 : : else
3544 : : {
3545 : 98047 : edge_iterator ei;
3546 : 98047 : tree dst_nr = build_int_cst (integer_type_node, dst_r->index);
3547 : :
3548 : 98047 : fn = builtin_decl_implicit (BUILT_IN_EH_COPY_VALUES);
3549 : 98047 : src_nr = build_int_cst (integer_type_node, src_r->index);
3550 : 98047 : x = gimple_build_call (fn, 2, dst_nr, src_nr);
3551 : 98047 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3552 : :
3553 : : /* Update the flags for the outgoing edge. */
3554 : 98047 : e = single_succ_edge (bb);
3555 : 98047 : gcc_assert (e->flags & EDGE_EH);
3556 : 98047 : e->flags = (e->flags & ~EDGE_EH) | EDGE_FALLTHRU;
3557 : 98047 : e->probability = profile_probability::always ();
3558 : :
3559 : : /* If there are no more EH users of the landing pad, delete it. */
3560 : 146626 : FOR_EACH_EDGE (e, ei, e->dest->preds)
3561 : 126778 : if (e->flags & EDGE_EH)
3562 : : break;
3563 : 98047 : if (e == NULL)
3564 : : {
3565 : 19848 : eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr);
3566 : 19848 : remove_eh_landing_pad (lp);
3567 : : }
3568 : : }
3569 : :
3570 : 98454 : ret = true;
3571 : : }
3572 : : else
3573 : : {
3574 : 78613 : tree var;
3575 : :
3576 : : /* When we don't have a destination region, this exception escapes
3577 : : up the call chain. We resolve this by generating a call to the
3578 : : _Unwind_Resume library function. */
3579 : :
3580 : : /* The ARM EABI redefines _Unwind_Resume as __cxa_end_cleanup
3581 : : with no arguments for C++. Check for that. */
3582 : 78613 : if (src_r->use_cxa_end_cleanup)
3583 : : {
3584 : 0 : fn = builtin_decl_implicit (BUILT_IN_CXA_END_CLEANUP);
3585 : 0 : x = gimple_build_call (fn, 0);
3586 : 0 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3587 : : }
3588 : : else
3589 : : {
3590 : 78613 : fn = builtin_decl_implicit (BUILT_IN_EH_POINTER);
3591 : 78613 : src_nr = build_int_cst (integer_type_node, src_r->index);
3592 : 78613 : x = gimple_build_call (fn, 1, src_nr);
3593 : 78613 : var = create_tmp_var (ptr_type_node);
3594 : 78613 : var = make_ssa_name (var, x);
3595 : 78613 : gimple_call_set_lhs (x, var);
3596 : 78613 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3597 : :
3598 : : /* When exception handling is delegated to a caller function, we
3599 : : have to guarantee that shadow memory variables living on stack
3600 : : will be cleaner before control is given to a parent function. */
3601 : 78613 : if (sanitize_flags_p (SANITIZE_ADDRESS))
3602 : : {
3603 : 271 : tree decl
3604 : 271 : = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
3605 : 271 : gimple *g = gimple_build_call (decl, 0);
3606 : 271 : gimple_set_location (g, gimple_location (stmt));
3607 : 271 : gsi_insert_before (&gsi, g, GSI_SAME_STMT);
3608 : : }
3609 : :
3610 : 78613 : fn = builtin_decl_implicit (BUILT_IN_UNWIND_RESUME);
3611 : 78613 : x = gimple_build_call (fn, 1, var);
3612 : 78613 : gimple_call_set_ctrl_altering (x, true);
3613 : 78613 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
3614 : : }
3615 : :
3616 : 78613 : gcc_assert (EDGE_COUNT (bb->succs) == 0);
3617 : : }
3618 : :
3619 : 177067 : gsi_remove (&gsi, true);
3620 : :
3621 : 177067 : return ret;
3622 : : }
3623 : :
3624 : : namespace {
3625 : :
3626 : : const pass_data pass_data_lower_resx =
3627 : : {
3628 : : GIMPLE_PASS, /* type */
3629 : : "resx", /* name */
3630 : : OPTGROUP_NONE, /* optinfo_flags */
3631 : : TV_TREE_EH, /* tv_id */
3632 : : PROP_gimple_lcf, /* properties_required */
3633 : : 0, /* properties_provided */
3634 : : 0, /* properties_destroyed */
3635 : : 0, /* todo_flags_start */
3636 : : 0, /* todo_flags_finish */
3637 : : };
3638 : :
3639 : : class pass_lower_resx : public gimple_opt_pass
3640 : : {
3641 : : public:
3642 : 290033 : pass_lower_resx (gcc::context *ctxt)
3643 : 580066 : : gimple_opt_pass (pass_data_lower_resx, ctxt)
3644 : : {}
3645 : :
3646 : : /* opt_pass methods: */
3647 : 1478885 : bool gate (function *) final override { return flag_exceptions != 0; }
3648 : : unsigned int execute (function *) final override;
3649 : :
3650 : : }; // class pass_lower_resx
3651 : :
3652 : : unsigned
3653 : 808106 : pass_lower_resx::execute (function *fun)
3654 : : {
3655 : 808106 : basic_block bb;
3656 : 808106 : bool dominance_invalidated = false;
3657 : 808106 : bool any_rewritten = false;
3658 : :
3659 : 808106 : hash_map<eh_region, tree> mnt_map;
3660 : :
3661 : 9898333 : FOR_EACH_BB_FN (bb, fun)
3662 : : {
3663 : 25807571 : if (gresx *last = safe_dyn_cast <gresx *> (*gsi_last_bb (bb)))
3664 : : {
3665 : 177067 : dominance_invalidated |= lower_resx (bb, last, &mnt_map);
3666 : 177067 : any_rewritten = true;
3667 : : }
3668 : : }
3669 : :
3670 : 808106 : if (dominance_invalidated)
3671 : : {
3672 : 21985 : free_dominance_info (CDI_DOMINATORS);
3673 : 21985 : free_dominance_info (CDI_POST_DOMINATORS);
3674 : : }
3675 : :
3676 : 808106 : return any_rewritten ? TODO_update_ssa_only_virtuals : 0;
3677 : 808106 : }
3678 : :
3679 : : } // anon namespace
3680 : :
3681 : : gimple_opt_pass *
3682 : 290033 : make_pass_lower_resx (gcc::context *ctxt)
3683 : : {
3684 : 290033 : return new pass_lower_resx (ctxt);
3685 : : }
3686 : :
3687 : : /* Try to optimize var = {v} {CLOBBER} stmts followed just by
3688 : : external throw. */
3689 : :
3690 : : static void
3691 : 620787 : optimize_clobbers (basic_block bb)
3692 : : {
3693 : 620787 : gimple_stmt_iterator gsi = gsi_last_bb (bb);
3694 : 620787 : bool any_clobbers = false;
3695 : 620787 : bool seen_stack_restore = false;
3696 : 620787 : edge_iterator ei;
3697 : 620787 : edge e;
3698 : :
3699 : : /* Only optimize anything if the bb contains at least one clobber,
3700 : : ends with resx (checked by caller), optionally contains some
3701 : : debug stmts or labels, or at most one __builtin_stack_restore
3702 : : call, and has an incoming EH edge. */
3703 : 4989696 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3704 : : {
3705 : 2478630 : gimple *stmt = gsi_stmt (gsi);
3706 : 2478630 : if (is_gimple_debug (stmt))
3707 : 1387236 : continue;
3708 : 1091394 : if (gimple_clobber_p (stmt))
3709 : : {
3710 : 486403 : any_clobbers = true;
3711 : 486403 : continue;
3712 : : }
3713 : 605413 : if (!seen_stack_restore
3714 : 604991 : && gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
3715 : : {
3716 : 422 : seen_stack_restore = true;
3717 : 422 : continue;
3718 : : }
3719 : 604569 : if (gimple_code (stmt) == GIMPLE_LABEL)
3720 : : break;
3721 : 422001 : return;
3722 : : }
3723 : 362553 : if (!any_clobbers)
3724 : : return;
3725 : 220386 : FOR_EACH_EDGE (e, ei, bb->preds)
3726 : 213047 : if (e->flags & EDGE_EH)
3727 : : break;
3728 : 206125 : if (e == NULL)
3729 : : return;
3730 : 198786 : gsi = gsi_last_bb (bb);
3731 : 1904558 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3732 : : {
3733 : 753493 : gimple *stmt = gsi_stmt (gsi);
3734 : 753493 : if (!gimple_clobber_p (stmt))
3735 : 390863 : continue;
3736 : 362630 : unlink_stmt_vdef (stmt);
3737 : 362630 : gsi_remove (&gsi, true);
3738 : 362630 : release_defs (stmt);
3739 : : }
3740 : : }
3741 : :
3742 : : /* Try to sink var = {v} {CLOBBER} stmts followed just by
3743 : : internal throw to successor BB.
3744 : : SUNK, if not NULL, is an array of sequences indexed by basic-block
3745 : : index to sink to and to pick up sinking opportunities from.
3746 : : If FOUND_OPPORTUNITY is not NULL then do not perform the optimization
3747 : : but set *FOUND_OPPORTUNITY to true. */
3748 : :
3749 : : static int
3750 : 679681 : sink_clobbers (basic_block bb,
3751 : : gimple_seq *sunk = NULL, bool *found_opportunity = NULL)
3752 : : {
3753 : 679681 : edge e;
3754 : 679681 : edge_iterator ei;
3755 : 679681 : gimple_stmt_iterator gsi, dgsi;
3756 : 679681 : basic_block succbb;
3757 : 679681 : bool any_clobbers = false;
3758 : 679681 : unsigned todo = 0;
3759 : :
3760 : : /* Only optimize if BB has a single EH successor and
3761 : : all predecessor edges are EH too. */
3762 : 1192654 : if (!single_succ_p (bb)
3763 : 679279 : || (single_succ_edge (bb)->flags & EDGE_EH) == 0)
3764 : : return 0;
3765 : :
3766 : 2797122 : FOR_EACH_EDGE (e, ei, bb->preds)
3767 : : {
3768 : 2136782 : if ((e->flags & EDGE_EH) == 0)
3769 : : return 0;
3770 : : }
3771 : :
3772 : : /* And BB contains only CLOBBER stmts before the final
3773 : : RESX. */
3774 : 660340 : gsi = gsi_last_bb (bb);
3775 : 6210542 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3776 : : {
3777 : 3105271 : gimple *stmt = gsi_stmt (gsi);
3778 : 3105271 : if (is_gimple_debug (stmt))
3779 : 2033963 : continue;
3780 : 1071308 : if (gimple_code (stmt) == GIMPLE_LABEL)
3781 : : break;
3782 : 818692 : if (!gimple_clobber_p (stmt))
3783 : : return 0;
3784 : : any_clobbers = true;
3785 : : }
3786 : 252616 : if (!any_clobbers && (!sunk || gimple_seq_empty_p (sunk[bb->index])))
3787 : : return 0;
3788 : :
3789 : : /* If this was a dry run, tell it we found clobbers to sink. */
3790 : 169386 : if (found_opportunity)
3791 : : {
3792 : 3080 : *found_opportunity = true;
3793 : 3080 : return 0;
3794 : : }
3795 : :
3796 : 166306 : edge succe = single_succ_edge (bb);
3797 : 166306 : succbb = succe->dest;
3798 : :
3799 : : /* See if there is a virtual PHI node to take an updated virtual
3800 : : operand from. */
3801 : 166306 : gphi *vphi = NULL;
3802 : 166306 : for (gphi_iterator gpi = gsi_start_phis (succbb);
3803 : 166717 : !gsi_end_p (gpi); gsi_next (&gpi))
3804 : : {
3805 : 121481 : tree res = gimple_phi_result (gpi.phi ());
3806 : 242962 : if (virtual_operand_p (res))
3807 : : {
3808 : : vphi = gpi.phi ();
3809 : : break;
3810 : : }
3811 : : }
3812 : :
3813 : 166306 : gimple *first_sunk = NULL;
3814 : 166306 : gimple *last_sunk = NULL;
3815 : 166306 : if (sunk && !(succbb->flags & BB_VISITED))
3816 : 8731 : dgsi = gsi_start (sunk[succbb->index]);
3817 : : else
3818 : 159195 : dgsi = gsi_after_labels (succbb);
3819 : 166306 : gsi = gsi_last_bb (bb);
3820 : 856150 : for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
3821 : : {
3822 : 428075 : gimple *stmt = gsi_stmt (gsi);
3823 : 428075 : tree lhs;
3824 : 428075 : if (is_gimple_debug (stmt))
3825 : 66251 : continue;
3826 : 361824 : if (gimple_code (stmt) == GIMPLE_LABEL)
3827 : : break;
3828 : 195518 : lhs = gimple_assign_lhs (stmt);
3829 : : /* Unfortunately we don't have dominance info updated at this
3830 : : point, so checking if
3831 : : dominated_by_p (CDI_DOMINATORS, succbb,
3832 : : gimple_bb (SSA_NAME_DEF_STMT (TREE_OPERAND (lhs, 0)))
3833 : : would be too costly. Thus, avoid sinking any clobbers that
3834 : : refer to non-(D) SSA_NAMEs. */
3835 : 195525 : if (TREE_CODE (lhs) == MEM_REF
3836 : 79 : && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME
3837 : 195568 : && !SSA_NAME_IS_DEFAULT_DEF (TREE_OPERAND (lhs, 0)))
3838 : : {
3839 : 7 : unlink_stmt_vdef (stmt);
3840 : 7 : gsi_remove (&gsi, true);
3841 : 7 : release_defs (stmt);
3842 : 7 : continue;
3843 : : }
3844 : :
3845 : : /* As we do not change stmt order when sinking across a
3846 : : forwarder edge we can keep virtual operands in place. */
3847 : 195511 : gsi_remove (&gsi, false);
3848 : 195511 : gsi_insert_before (&dgsi, stmt, GSI_NEW_STMT);
3849 : 195511 : if (!first_sunk)
3850 : 166293 : first_sunk = stmt;
3851 : : last_sunk = stmt;
3852 : : }
3853 : 166306 : if (sunk && !gimple_seq_empty_p (sunk[bb->index]))
3854 : : {
3855 : 1638 : if (!first_sunk)
3856 : 6 : first_sunk = gsi_stmt (gsi_last (sunk[bb->index]));
3857 : 1638 : last_sunk = gsi_stmt (gsi_start (sunk[bb->index]));
3858 : 1638 : gsi_insert_seq_before_without_update (&dgsi,
3859 : : sunk[bb->index], GSI_NEW_STMT);
3860 : 1638 : sunk[bb->index] = NULL;
3861 : : }
3862 : 166306 : if (first_sunk)
3863 : : {
3864 : : /* Adjust virtual operands if we sunk across a virtual PHI. */
3865 : 166299 : if (vphi)
3866 : : {
3867 : 121070 : imm_use_iterator iter;
3868 : 121070 : use_operand_p use_p;
3869 : 121070 : gimple *use_stmt;
3870 : 121070 : tree phi_def = gimple_phi_result (vphi);
3871 : 364005 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, phi_def)
3872 : 365637 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
3873 : 243772 : SET_USE (use_p, gimple_vdef (first_sunk));
3874 : 121070 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (phi_def))
3875 : : {
3876 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_vdef (first_sunk)) = 1;
3877 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (phi_def) = 0;
3878 : : }
3879 : 242140 : SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (vphi, succe),
3880 : : gimple_vuse (last_sunk));
3881 : 121070 : SET_USE (gimple_vuse_op (last_sunk), phi_def);
3882 : : }
3883 : : /* If there isn't a single predecessor but no virtual PHI node
3884 : : arrange for virtual operands to be renamed. */
3885 : 68372 : else if (!single_pred_p (succbb)
3886 : 68372 : && TREE_CODE (gimple_vuse (last_sunk)) == SSA_NAME)
3887 : : {
3888 : 23058 : mark_virtual_operand_for_renaming (gimple_vuse (last_sunk));
3889 : 23058 : todo |= TODO_update_ssa_only_virtuals;
3890 : : }
3891 : : }
3892 : :
3893 : 166306 : return todo;
3894 : : }
3895 : :
3896 : : /* At the end of inlining, we can lower EH_DISPATCH. Return true when
3897 : : we have found some duplicate labels and removed some edges. */
3898 : :
3899 : : static bool
3900 : 41862 : lower_eh_dispatch (basic_block src, geh_dispatch *stmt)
3901 : : {
3902 : 41862 : gimple_stmt_iterator gsi;
3903 : 41862 : int region_nr;
3904 : 41862 : eh_region r;
3905 : 41862 : tree filter, fn;
3906 : 41862 : gimple *x;
3907 : 41862 : bool redirected = false;
3908 : :
3909 : 41862 : region_nr = gimple_eh_dispatch_region (stmt);
3910 : 41862 : r = get_eh_region_from_number (region_nr);
3911 : :
3912 : 41862 : gsi = gsi_last_bb (src);
3913 : :
3914 : 41862 : switch (r->type)
3915 : : {
3916 : 41576 : case ERT_TRY:
3917 : 41576 : {
3918 : 41576 : auto_vec<tree> labels;
3919 : 41576 : tree default_label = NULL;
3920 : 41576 : eh_catch c;
3921 : 41576 : edge_iterator ei;
3922 : 41576 : edge e;
3923 : 41576 : hash_set<tree> seen_values;
3924 : :
3925 : : /* Collect the labels for a switch. Zero the post_landing_pad
3926 : : field becase we'll no longer have anything keeping these labels
3927 : : in existence and the optimizer will be free to merge these
3928 : : blocks at will. */
3929 : 47359 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
3930 : : {
3931 : 44395 : tree tp_node, flt_node, lab = c->label;
3932 : 44395 : bool have_label = false;
3933 : :
3934 : 44395 : c->label = NULL;
3935 : 44395 : tp_node = c->type_list;
3936 : 44395 : flt_node = c->filter_list;
3937 : :
3938 : 44395 : if (tp_node == NULL)
3939 : : {
3940 : : default_label = lab;
3941 : : break;
3942 : : }
3943 : 5783 : do
3944 : : {
3945 : : /* Filter out duplicate labels that arise when this handler
3946 : : is shadowed by an earlier one. When no labels are
3947 : : attached to the handler anymore, we remove
3948 : : the corresponding edge and then we delete unreachable
3949 : : blocks at the end of this pass. */
3950 : 5783 : if (! seen_values.contains (TREE_VALUE (flt_node)))
3951 : : {
3952 : 5762 : tree t = build_case_label (TREE_VALUE (flt_node),
3953 : 5762 : NULL, lab);
3954 : 5762 : labels.safe_push (t);
3955 : 5762 : seen_values.add (TREE_VALUE (flt_node));
3956 : 5762 : have_label = true;
3957 : : }
3958 : :
3959 : 5783 : tp_node = TREE_CHAIN (tp_node);
3960 : 5783 : flt_node = TREE_CHAIN (flt_node);
3961 : : }
3962 : 5783 : while (tp_node);
3963 : 5783 : if (! have_label)
3964 : : {
3965 : 21 : remove_edge (find_edge (src, label_to_block (cfun, lab)));
3966 : 21 : redirected = true;
3967 : : }
3968 : : }
3969 : :
3970 : : /* Clean up the edge flags. */
3971 : 88914 : FOR_EACH_EDGE (e, ei, src->succs)
3972 : : {
3973 : 47338 : if (e->flags & EDGE_FALLTHRU)
3974 : : {
3975 : : /* If there was no catch-all, use the fallthru edge. */
3976 : 2964 : if (default_label == NULL)
3977 : 2964 : default_label = gimple_block_label (e->dest);
3978 : 2964 : e->flags &= ~EDGE_FALLTHRU;
3979 : : }
3980 : : }
3981 : 41576 : gcc_assert (default_label != NULL);
3982 : :
3983 : : /* Don't generate a switch if there's only a default case.
3984 : : This is common in the form of try { A; } catch (...) { B; }. */
3985 : 41576 : if (!labels.exists ())
3986 : : {
3987 : 36810 : e = single_succ_edge (src);
3988 : 36810 : e->flags |= EDGE_FALLTHRU;
3989 : : }
3990 : : else
3991 : : {
3992 : 4766 : fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
3993 : 4766 : x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
3994 : 4766 : region_nr));
3995 : 4766 : filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)));
3996 : 4766 : filter = make_ssa_name (filter, x);
3997 : 4766 : gimple_call_set_lhs (x, filter);
3998 : 4766 : gimple_set_location (x, gimple_location (stmt));
3999 : 4766 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4000 : :
4001 : : /* Turn the default label into a default case. */
4002 : 4766 : default_label = build_case_label (NULL, NULL, default_label);
4003 : 4766 : sort_case_labels (labels);
4004 : :
4005 : 4766 : x = gimple_build_switch (filter, default_label, labels);
4006 : 4766 : gimple_set_location (x, gimple_location (stmt));
4007 : 4766 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4008 : : }
4009 : 41576 : }
4010 : 41576 : break;
4011 : :
4012 : 286 : case ERT_ALLOWED_EXCEPTIONS:
4013 : 286 : {
4014 : 286 : edge b_e = BRANCH_EDGE (src);
4015 : 286 : edge f_e = FALLTHRU_EDGE (src);
4016 : :
4017 : 286 : fn = builtin_decl_implicit (BUILT_IN_EH_FILTER);
4018 : 286 : x = gimple_build_call (fn, 1, build_int_cst (integer_type_node,
4019 : 286 : region_nr));
4020 : 286 : filter = create_tmp_var (TREE_TYPE (TREE_TYPE (fn)));
4021 : 286 : filter = make_ssa_name (filter, x);
4022 : 286 : gimple_call_set_lhs (x, filter);
4023 : 286 : gimple_set_location (x, gimple_location (stmt));
4024 : 286 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4025 : :
4026 : 286 : r->u.allowed.label = NULL;
4027 : 286 : x = gimple_build_cond (EQ_EXPR, filter,
4028 : 286 : build_int_cst (TREE_TYPE (filter),
4029 : 286 : r->u.allowed.filter),
4030 : : NULL_TREE, NULL_TREE);
4031 : 286 : gsi_insert_before (&gsi, x, GSI_SAME_STMT);
4032 : :
4033 : 286 : b_e->flags = b_e->flags | EDGE_TRUE_VALUE;
4034 : 286 : f_e->flags = (f_e->flags & ~EDGE_FALLTHRU) | EDGE_FALSE_VALUE;
4035 : : }
4036 : 286 : break;
4037 : :
4038 : 0 : default:
4039 : 0 : gcc_unreachable ();
4040 : : }
4041 : :
4042 : : /* Replace the EH_DISPATCH with the SWITCH or COND generated above. */
4043 : 41862 : gsi_remove (&gsi, true);
4044 : 41862 : return redirected;
4045 : : }
4046 : :
4047 : : namespace {
4048 : :
4049 : : const pass_data pass_data_lower_eh_dispatch =
4050 : : {
4051 : : GIMPLE_PASS, /* type */
4052 : : "ehdisp", /* name */
4053 : : OPTGROUP_NONE, /* optinfo_flags */
4054 : : TV_TREE_EH, /* tv_id */
4055 : : PROP_gimple_lcf, /* properties_required */
4056 : : 0, /* properties_provided */
4057 : : 0, /* properties_destroyed */
4058 : : 0, /* todo_flags_start */
4059 : : 0, /* todo_flags_finish */
4060 : : };
4061 : :
4062 : : class pass_lower_eh_dispatch : public gimple_opt_pass
4063 : : {
4064 : : public:
4065 : 290033 : pass_lower_eh_dispatch (gcc::context *ctxt)
4066 : 580066 : : gimple_opt_pass (pass_data_lower_eh_dispatch, ctxt)
4067 : : {}
4068 : :
4069 : : /* opt_pass methods: */
4070 : 1479055 : bool gate (function *fun) final override
4071 : : {
4072 : 1479055 : return fun->eh->region_tree != NULL;
4073 : : }
4074 : : unsigned int execute (function *) final override;
4075 : :
4076 : : }; // class pass_lower_eh_dispatch
4077 : :
4078 : : unsigned
4079 : 147491 : pass_lower_eh_dispatch::execute (function *fun)
4080 : : {
4081 : 147491 : basic_block bb;
4082 : 147491 : int flags = 0;
4083 : 147491 : bool redirected = false;
4084 : 147491 : bool any_resx_to_process = false;
4085 : :
4086 : 147491 : assign_filter_values ();
4087 : :
4088 : 5413353 : FOR_EACH_BB_FN (bb, fun)
4089 : : {
4090 : 5265862 : gimple *last = *gsi_last_bb (bb);
4091 : 5265862 : if (last == NULL)
4092 : 74569 : continue;
4093 : 5191293 : if (gimple_code (last) == GIMPLE_EH_DISPATCH)
4094 : : {
4095 : 41862 : redirected |= lower_eh_dispatch (bb,
4096 : : as_a <geh_dispatch *> (last));
4097 : 41862 : flags |= TODO_update_ssa_only_virtuals;
4098 : : }
4099 : 5149431 : else if (gimple_code (last) == GIMPLE_RESX)
4100 : : {
4101 : 215662 : if (stmt_can_throw_external (fun, last))
4102 : 99105 : optimize_clobbers (bb);
4103 : 116557 : else if (!any_resx_to_process)
4104 : 110251 : sink_clobbers (bb, NULL, &any_resx_to_process);
4105 : : }
4106 : 5191293 : bb->flags &= ~BB_VISITED;
4107 : : }
4108 : 147491 : if (redirected)
4109 : : {
4110 : 12 : free_dominance_info (CDI_DOMINATORS);
4111 : 12 : delete_unreachable_blocks ();
4112 : : }
4113 : :
4114 : 147491 : if (any_resx_to_process)
4115 : : {
4116 : : /* Make sure to catch all secondary sinking opportunities by processing
4117 : : blocks in RPO order and after all CFG modifications from lowering
4118 : : and unreachable block removal. */
4119 : 3080 : int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
4120 : 3080 : int rpo_n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, false);
4121 : 3080 : gimple_seq *sunk = XCNEWVEC (gimple_seq, last_basic_block_for_fn (fun));
4122 : 113448 : for (int i = 0; i < rpo_n; ++i)
4123 : : {
4124 : 110368 : bb = BASIC_BLOCK_FOR_FN (fun, rpo[i]);
4125 : 110368 : gimple *last = *gsi_last_bb (bb);
4126 : 110368 : if (last
4127 : 108873 : && gimple_code (last) == GIMPLE_RESX
4128 : 124202 : && !stmt_can_throw_external (fun, last))
4129 : 10440 : flags |= sink_clobbers (bb, sunk);
4130 : : /* If there were any clobbers sunk into this BB, insert them now. */
4131 : 110368 : if (!gimple_seq_empty_p (sunk[bb->index]))
4132 : : {
4133 : 3853 : gimple_stmt_iterator gsi = gsi_after_labels (bb);
4134 : 3853 : gsi_insert_seq_before (&gsi, sunk[bb->index], GSI_NEW_STMT);
4135 : 3853 : sunk[bb->index] = NULL;
4136 : : }
4137 : 110368 : bb->flags |= BB_VISITED;
4138 : : }
4139 : 3080 : free (rpo);
4140 : 3080 : free (sunk);
4141 : : }
4142 : :
4143 : 147491 : return flags;
4144 : : }
4145 : :
4146 : : } // anon namespace
4147 : :
4148 : : gimple_opt_pass *
4149 : 290033 : make_pass_lower_eh_dispatch (gcc::context *ctxt)
4150 : : {
4151 : 290033 : return new pass_lower_eh_dispatch (ctxt);
4152 : : }
4153 : :
4154 : : /* Walk statements, see what regions and, optionally, landing pads
4155 : : are really referenced.
4156 : :
4157 : : Returns in R_REACHABLEP an sbitmap with bits set for reachable regions,
4158 : : and in LP_REACHABLE an sbitmap with bits set for reachable landing pads.
4159 : :
4160 : : Passing NULL for LP_REACHABLE is valid, in this case only reachable
4161 : : regions are marked.
4162 : :
4163 : : The caller is responsible for freeing the returned sbitmaps. */
4164 : :
4165 : : static void
4166 : 1462589 : mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep)
4167 : : {
4168 : 1462589 : sbitmap r_reachable, lp_reachable;
4169 : 1462589 : basic_block bb;
4170 : 1462589 : bool mark_landing_pads = (lp_reachablep != NULL);
4171 : 1462589 : gcc_checking_assert (r_reachablep != NULL);
4172 : :
4173 : 1462589 : r_reachable = sbitmap_alloc (cfun->eh->region_array->length ());
4174 : 1462589 : bitmap_clear (r_reachable);
4175 : 1462589 : *r_reachablep = r_reachable;
4176 : :
4177 : 1462589 : if (mark_landing_pads)
4178 : : {
4179 : 1175784 : lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ());
4180 : 1175784 : bitmap_clear (lp_reachable);
4181 : 1175784 : *lp_reachablep = lp_reachable;
4182 : : }
4183 : : else
4184 : : lp_reachable = NULL;
4185 : :
4186 : 21860838 : FOR_EACH_BB_FN (bb, cfun)
4187 : : {
4188 : 20398249 : gimple_stmt_iterator gsi;
4189 : :
4190 : 185348465 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
4191 : : {
4192 : 144551967 : gimple *stmt = gsi_stmt (gsi);
4193 : :
4194 : 144551967 : if (mark_landing_pads)
4195 : : {
4196 : 85909628 : int lp_nr = lookup_stmt_eh_lp (stmt);
4197 : :
4198 : : /* Negative LP numbers are MUST_NOT_THROW regions which
4199 : : are not considered BB enders. */
4200 : 85909628 : if (lp_nr < 0)
4201 : 91236 : bitmap_set_bit (r_reachable, -lp_nr);
4202 : :
4203 : : /* Positive LP numbers are real landing pads, and BB enders. */
4204 : 85818392 : else if (lp_nr > 0)
4205 : : {
4206 : 3440918 : gcc_assert (gsi_one_before_end_p (gsi));
4207 : 3440918 : eh_region region = get_eh_region_from_lp_number (lp_nr);
4208 : 3440918 : bitmap_set_bit (r_reachable, region->index);
4209 : 3440918 : bitmap_set_bit (lp_reachable, lp_nr);
4210 : : }
4211 : : }
4212 : :
4213 : : /* Avoid removing regions referenced from RESX/EH_DISPATCH. */
4214 : 144551967 : switch (gimple_code (stmt))
4215 : : {
4216 : 1127929 : case GIMPLE_RESX:
4217 : 2255858 : bitmap_set_bit (r_reachable,
4218 : 1127929 : gimple_resx_region (as_a <gresx *> (stmt)));
4219 : 1127929 : break;
4220 : 65050 : case GIMPLE_EH_DISPATCH:
4221 : 130100 : bitmap_set_bit (r_reachable,
4222 : : gimple_eh_dispatch_region (
4223 : 65050 : as_a <geh_dispatch *> (stmt)));
4224 : 65050 : break;
4225 : 8002372 : case GIMPLE_CALL:
4226 : 8002372 : if (gimple_call_builtin_p (stmt, BUILT_IN_EH_COPY_VALUES))
4227 : 2304 : for (int i = 0; i < 2; ++i)
4228 : : {
4229 : 1536 : tree rt = gimple_call_arg (stmt, i);
4230 : 1536 : HOST_WIDE_INT ri = tree_to_shwi (rt);
4231 : :
4232 : 1536 : gcc_assert (ri == (int)ri);
4233 : 1536 : bitmap_set_bit (r_reachable, ri);
4234 : : }
4235 : : break;
4236 : : default:
4237 : : break;
4238 : : }
4239 : : }
4240 : : }
4241 : 1462589 : }
4242 : :
4243 : : /* Remove unreachable handlers and unreachable landing pads. */
4244 : :
4245 : : static void
4246 : 1175784 : remove_unreachable_handlers (void)
4247 : : {
4248 : 1175784 : sbitmap r_reachable, lp_reachable;
4249 : 1175784 : eh_region region;
4250 : 1175784 : eh_landing_pad lp;
4251 : 1175784 : unsigned i;
4252 : :
4253 : 1175784 : mark_reachable_handlers (&r_reachable, &lp_reachable);
4254 : :
4255 : 1175784 : if (dump_file)
4256 : : {
4257 : 3 : fprintf (dump_file, "Before removal of unreachable regions:\n");
4258 : 3 : dump_eh_tree (dump_file, cfun);
4259 : 3 : fprintf (dump_file, "Reachable regions: ");
4260 : 3 : dump_bitmap_file (dump_file, r_reachable);
4261 : 3 : fprintf (dump_file, "Reachable landing pads: ");
4262 : 3 : dump_bitmap_file (dump_file, lp_reachable);
4263 : : }
4264 : :
4265 : 1175784 : if (dump_file)
4266 : : {
4267 : 18 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
4268 : 15 : if (region && !bitmap_bit_p (r_reachable, region->index))
4269 : 6 : fprintf (dump_file,
4270 : : "Removing unreachable region %d\n",
4271 : : region->index);
4272 : : }
4273 : :
4274 : 1175784 : remove_unreachable_eh_regions (r_reachable);
4275 : :
4276 : 5973166 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
4277 : 3621598 : if (lp && !bitmap_bit_p (lp_reachable, lp->index))
4278 : : {
4279 : 13788 : if (dump_file)
4280 : 0 : fprintf (dump_file,
4281 : : "Removing unreachable landing pad %d\n",
4282 : : lp->index);
4283 : 13788 : remove_eh_landing_pad (lp);
4284 : : }
4285 : :
4286 : 1175784 : if (dump_file)
4287 : : {
4288 : 3 : fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
4289 : 3 : dump_eh_tree (dump_file, cfun);
4290 : 3 : fprintf (dump_file, "\n\n");
4291 : : }
4292 : :
4293 : 1175784 : sbitmap_free (r_reachable);
4294 : 1175784 : sbitmap_free (lp_reachable);
4295 : :
4296 : 1175784 : if (flag_checking)
4297 : 1175769 : verify_eh_tree (cfun);
4298 : 1175784 : }
4299 : :
4300 : : /* Remove unreachable handlers if any landing pads have been removed after
4301 : : last ehcleanup pass (due to gimple_purge_dead_eh_edges). */
4302 : :
4303 : : void
4304 : 1719835 : maybe_remove_unreachable_handlers (void)
4305 : : {
4306 : 1719835 : eh_landing_pad lp;
4307 : 1719835 : unsigned i;
4308 : :
4309 : 1719835 : if (cfun->eh == NULL)
4310 : : return;
4311 : :
4312 : 5399505 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp)
4313 : 3683484 : if (lp
4314 : 3683484 : && (lp->post_landing_pad == NULL_TREE
4315 : 425816 : || label_to_block (cfun, lp->post_landing_pad) == NULL))
4316 : : {
4317 : 3814 : remove_unreachable_handlers ();
4318 : 3814 : return;
4319 : : }
4320 : : }
4321 : :
4322 : : /* Remove regions that do not have landing pads. This assumes
4323 : : that remove_unreachable_handlers has already been run, and
4324 : : that we've just manipulated the landing pads since then.
4325 : :
4326 : : Preserve regions with landing pads and regions that prevent
4327 : : exceptions from propagating further, even if these regions
4328 : : are not reachable. */
4329 : :
4330 : : static void
4331 : 286805 : remove_unreachable_handlers_no_lp (void)
4332 : : {
4333 : 286805 : eh_region region;
4334 : 286805 : sbitmap r_reachable;
4335 : 286805 : unsigned i;
4336 : :
4337 : 286805 : mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL);
4338 : :
4339 : 3114542 : FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region)
4340 : : {
4341 : 2540932 : if (! region)
4342 : 1637870 : continue;
4343 : :
4344 : 903062 : if (region->landing_pads != NULL
4345 : 583172 : || region->type == ERT_MUST_NOT_THROW)
4346 : 353224 : bitmap_set_bit (r_reachable, region->index);
4347 : :
4348 : 903062 : if (dump_file
4349 : 903062 : && !bitmap_bit_p (r_reachable, region->index))
4350 : 6 : fprintf (dump_file,
4351 : : "Removing unreachable region %d\n",
4352 : : region->index);
4353 : : }
4354 : :
4355 : 286805 : remove_unreachable_eh_regions (r_reachable);
4356 : :
4357 : 286805 : sbitmap_free (r_reachable);
4358 : 286805 : }
4359 : :
4360 : : /* Undo critical edge splitting on an EH landing pad. Earlier, we
4361 : : optimisticaly split all sorts of edges, including EH edges. The
4362 : : optimization passes in between may not have needed them; if not,
4363 : : we should undo the split.
4364 : :
4365 : : Recognize this case by having one EH edge incoming to the BB and
4366 : : one normal edge outgoing; BB should be empty apart from the
4367 : : post_landing_pad label.
4368 : :
4369 : : Note that this is slightly different from the empty handler case
4370 : : handled by cleanup_empty_eh, in that the actual handler may yet
4371 : : have actual code but the landing pad has been separated from the
4372 : : handler. As such, cleanup_empty_eh relies on this transformation
4373 : : having been done first. */
4374 : :
4375 : : static bool
4376 : 1852497 : unsplit_eh (eh_landing_pad lp)
4377 : : {
4378 : 1852497 : basic_block bb = label_to_block (cfun, lp->post_landing_pad);
4379 : 1852497 : gimple_stmt_iterator gsi;
4380 : 1852497 : edge e_in, e_out;
4381 : :
4382 : : /* Quickly check the edge counts on BB for singularity. */
4383 : 3788149 : if (!single_pred_p (bb) || !single_succ_p (bb))
4384 : : return false;
4385 : 1413094 : e_in = single_pred_edge (bb);
4386 : 1413094 : e_out = single_succ_edge (bb);
4387 : :
4388 : : /* Input edge must be EH and output edge must be normal. */
4389 : 1413094 : if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0)
4390 : : return false;
4391 : :
4392 : : /* The block must be empty except for the labels and debug insns. */
4393 : 1120927 : gsi = gsi_after_labels (bb);
4394 : 1120927 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4395 : 7185 : gsi_next_nondebug (&gsi);
4396 : 1120927 : if (!gsi_end_p (gsi))
4397 : : return false;
4398 : :
4399 : : /* The destination block must not already have a landing pad
4400 : : for a different region. */
4401 : 3142449 : for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
4402 : : {
4403 : 2075879 : glabel *label_stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
4404 : 1045537 : tree lab;
4405 : 1045537 : int lp_nr;
4406 : :
4407 : 1045537 : if (!label_stmt)
4408 : : break;
4409 : 1045537 : lab = gimple_label_label (label_stmt);
4410 : 1045537 : lp_nr = EH_LANDING_PAD_NR (lab);
4411 : 1045537 : if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
4412 : : return false;
4413 : : }
4414 : :
4415 : : /* The new destination block must not already be a destination of
4416 : : the source block, lest we merge fallthru and eh edges and get
4417 : : all sorts of confused. */
4418 : 1048456 : if (find_edge (e_in->src, e_out->dest))
4419 : : return false;
4420 : :
4421 : : /* ??? We can get degenerate phis due to cfg cleanups. I would have
4422 : : thought this should have been cleaned up by a phicprop pass, but
4423 : : that doesn't appear to handle virtuals. Propagate by hand. */
4424 : 1048452 : if (!gimple_seq_empty_p (phi_nodes (bb)))
4425 : : {
4426 : 10 : for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi); )
4427 : : {
4428 : 5 : gimple *use_stmt;
4429 : 5 : gphi *phi = gpi.phi ();
4430 : 5 : tree lhs = gimple_phi_result (phi);
4431 : 5 : tree rhs = gimple_phi_arg_def (phi, 0);
4432 : 5 : use_operand_p use_p;
4433 : 5 : imm_use_iterator iter;
4434 : :
4435 : 19 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
4436 : : {
4437 : 27 : FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
4438 : 9 : SET_USE (use_p, rhs);
4439 : 5 : }
4440 : :
4441 : 5 : if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
4442 : 0 : SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs) = 1;
4443 : :
4444 : 5 : remove_phi_node (&gpi, true);
4445 : : }
4446 : : }
4447 : :
4448 : 1048452 : if (dump_file && (dump_flags & TDF_DETAILS))
4449 : 0 : fprintf (dump_file, "Unsplit EH landing pad %d to block %i.\n",
4450 : 0 : lp->index, e_out->dest->index);
4451 : :
4452 : : /* Redirect the edge. Since redirect_eh_edge_1 expects to be moving
4453 : : a successor edge, humor it. But do the real CFG change with the
4454 : : predecessor of E_OUT in order to preserve the ordering of arguments
4455 : : to the PHI nodes in E_OUT->DEST. */
4456 : 1048452 : redirect_eh_edge_1 (e_in, e_out->dest, false);
4457 : 1048452 : redirect_edge_pred (e_out, e_in->src);
4458 : 1048452 : e_out->flags = e_in->flags;
4459 : 1048452 : e_out->probability = e_in->probability;
4460 : 1048452 : remove_edge (e_in);
4461 : :
4462 : 1048452 : return true;
4463 : : }
4464 : :
4465 : : /* Examine each landing pad block and see if it matches unsplit_eh. */
4466 : :
4467 : : static bool
4468 : 558250 : unsplit_all_eh (void)
4469 : : {
4470 : 558250 : bool changed = false;
4471 : 558250 : eh_landing_pad lp;
4472 : 558250 : int i;
4473 : :
4474 : 3177275 : for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
4475 : 2619025 : if (lp)
4476 : 1852497 : changed |= unsplit_eh (lp);
4477 : :
4478 : 558250 : return changed;
4479 : : }
4480 : :
4481 : : /* Wrapper around unsplit_all_eh that makes it usable everywhere. */
4482 : :
4483 : : void
4484 : 240963 : unsplit_eh_edges (void)
4485 : : {
4486 : 240963 : bool changed;
4487 : :
4488 : : /* unsplit_all_eh can die looking up unreachable landing pads. */
4489 : 240963 : maybe_remove_unreachable_handlers ();
4490 : :
4491 : 240963 : changed = unsplit_all_eh ();
4492 : :
4493 : : /* If EH edges have been unsplit, delete unreachable forwarder blocks. */
4494 : 240963 : if (changed)
4495 : : {
4496 : 12460 : free_dominance_info (CDI_DOMINATORS);
4497 : 12460 : free_dominance_info (CDI_POST_DOMINATORS);
4498 : 12460 : delete_unreachable_blocks ();
4499 : : }
4500 : 240963 : }
4501 : :
4502 : : /* A subroutine of cleanup_empty_eh. Redirect all EH edges incoming
4503 : : to OLD_BB to NEW_BB; return true on success, false on failure.
4504 : :
4505 : : OLD_BB_OUT is the edge into NEW_BB from OLD_BB, so if we miss any
4506 : : PHI variables from OLD_BB we can pick them up from OLD_BB_OUT.
4507 : : Virtual PHIs may be deleted and marked for renaming. */
4508 : :
4509 : : static bool
4510 : 270961 : cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb,
4511 : : edge old_bb_out, bool change_region)
4512 : : {
4513 : 270961 : gphi_iterator ngsi, ogsi;
4514 : 270961 : edge_iterator ei;
4515 : 270961 : edge e;
4516 : 270961 : bitmap ophi_handled;
4517 : :
4518 : : /* The destination block must not be a regular successor for any
4519 : : of the preds of the landing pad. Thus, avoid turning
4520 : : <..>
4521 : : | \ EH
4522 : : | <..>
4523 : : | /
4524 : : <..>
4525 : : into
4526 : : <..>
4527 : : | | EH
4528 : : <..>
4529 : : which CFG verification would choke on. See PR45172 and PR51089. */
4530 : 270961 : if (!single_pred_p (new_bb))
4531 : 1089136 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4532 : 855336 : if (find_edge (e->src, new_bb))
4533 : : return false;
4534 : :
4535 : 1520059 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4536 : 1249108 : redirect_edge_var_map_clear (e);
4537 : :
4538 : 270951 : ophi_handled = BITMAP_ALLOC (NULL);
4539 : :
4540 : : /* First, iterate through the PHIs on NEW_BB and set up the edge_var_map
4541 : : for the edges we're going to move. */
4542 : 466261 : for (ngsi = gsi_start_phis (new_bb); !gsi_end_p (ngsi); gsi_next (&ngsi))
4543 : : {
4544 : 195314 : gphi *ophi, *nphi = ngsi.phi ();
4545 : 195314 : tree nresult, nop;
4546 : :
4547 : 195314 : nresult = gimple_phi_result (nphi);
4548 : 195314 : nop = gimple_phi_arg_def (nphi, old_bb_out->dest_idx);
4549 : :
4550 : : /* Find the corresponding PHI in OLD_BB so we can forward-propagate
4551 : : the source ssa_name. */
4552 : 195314 : ophi = NULL;
4553 : 211863 : for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
4554 : : {
4555 : 75845 : ophi = ogsi.phi ();
4556 : 75845 : if (gimple_phi_result (ophi) == nop)
4557 : : break;
4558 : 16549 : ophi = NULL;
4559 : : }
4560 : :
4561 : : /* If we did find the corresponding PHI, copy those inputs. */
4562 : 195314 : if (ophi)
4563 : : {
4564 : : /* If NOP is used somewhere else beyond phis in new_bb, give up. */
4565 : 59296 : if (!has_single_use (nop))
4566 : : {
4567 : 3550 : imm_use_iterator imm_iter;
4568 : 3550 : use_operand_p use_p;
4569 : :
4570 : 14279 : FOR_EACH_IMM_USE_FAST (use_p, imm_iter, nop)
4571 : : {
4572 : 7183 : if (!gimple_debug_bind_p (USE_STMT (use_p))
4573 : 7183 : && (gimple_code (USE_STMT (use_p)) != GIMPLE_PHI
4574 : 7177 : || gimple_bb (USE_STMT (use_p)) != new_bb))
4575 : 4 : goto fail;
4576 : 3550 : }
4577 : : }
4578 : 59292 : bitmap_set_bit (ophi_handled, SSA_NAME_VERSION (nop));
4579 : 612087 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4580 : : {
4581 : 552795 : location_t oloc;
4582 : 552795 : tree oop;
4583 : :
4584 : 552795 : if ((e->flags & EDGE_EH) == 0)
4585 : 2810 : continue;
4586 : 549985 : oop = gimple_phi_arg_def (ophi, e->dest_idx);
4587 : 549985 : oloc = gimple_phi_arg_location (ophi, e->dest_idx);
4588 : 549985 : redirect_edge_var_map_add (e, nresult, oop, oloc);
4589 : : }
4590 : : }
4591 : : /* If we didn't find the PHI, if it's a real variable or a VOP, we know
4592 : : from the fact that OLD_BB is tree_empty_eh_handler_p that the
4593 : : variable is unchanged from input to the block and we can simply
4594 : : re-use the input to NEW_BB from the OLD_BB_OUT edge. */
4595 : : else
4596 : : {
4597 : 136018 : location_t nloc
4598 : 136018 : = gimple_phi_arg_location (nphi, old_bb_out->dest_idx);
4599 : 366871 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4600 : 230853 : redirect_edge_var_map_add (e, nresult, nop, nloc);
4601 : : }
4602 : : }
4603 : :
4604 : : /* Second, verify that all PHIs from OLD_BB have been handled. If not,
4605 : : we don't know what values from the other edges into NEW_BB to use. */
4606 : 330221 : for (ogsi = gsi_start_phis (old_bb); !gsi_end_p (ogsi); gsi_next (&ogsi))
4607 : : {
4608 : 105321 : gphi *ophi = ogsi.phi ();
4609 : 105321 : tree oresult = gimple_phi_result (ophi);
4610 : 105321 : if (!bitmap_bit_p (ophi_handled, SSA_NAME_VERSION (oresult)))
4611 : 46047 : goto fail;
4612 : : }
4613 : :
4614 : : /* Finally, move the edges and update the PHIs. */
4615 : 955661 : for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); )
4616 : 730761 : if (e->flags & EDGE_EH)
4617 : : {
4618 : : /* ??? CFG manipluation routines do not try to update loop
4619 : : form on edge redirection. Do so manually here for now. */
4620 : : /* If we redirect a loop entry or latch edge that will either create
4621 : : a multiple entry loop or rotate the loop. If the loops merge
4622 : : we may have created a loop with multiple latches.
4623 : : All of this isn't easily fixed thus cancel the affected loop
4624 : : and mark the other loop as possibly having multiple latches. */
4625 : 729720 : if (e->dest == e->dest->loop_father->header)
4626 : : {
4627 : 0 : mark_loop_for_removal (e->dest->loop_father);
4628 : 0 : new_bb->loop_father->latch = NULL;
4629 : 0 : loops_state_set (LOOPS_MAY_HAVE_MULTIPLE_LATCHES);
4630 : : }
4631 : 729720 : redirect_eh_edge_1 (e, new_bb, change_region);
4632 : 729720 : redirect_edge_succ (e, new_bb);
4633 : 729720 : flush_pending_stmts (e);
4634 : : }
4635 : : else
4636 : 1041 : ei_next (&ei);
4637 : :
4638 : 224900 : BITMAP_FREE (ophi_handled);
4639 : 224900 : return true;
4640 : :
4641 : 46051 : fail:
4642 : 564398 : FOR_EACH_EDGE (e, ei, old_bb->preds)
4643 : 518347 : redirect_edge_var_map_clear (e);
4644 : 46051 : BITMAP_FREE (ophi_handled);
4645 : 46051 : return false;
4646 : : }
4647 : :
4648 : : /* A subroutine of cleanup_empty_eh. Move a landing pad LP from its
4649 : : old region to NEW_REGION at BB. */
4650 : :
4651 : : static void
4652 : 22695 : cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
4653 : : eh_landing_pad lp, eh_region new_region)
4654 : : {
4655 : 22695 : gimple_stmt_iterator gsi;
4656 : 22695 : eh_landing_pad *pp;
4657 : :
4658 : 22695 : for (pp = &lp->region->landing_pads; *pp != lp; pp = &(*pp)->next_lp)
4659 : 0 : continue;
4660 : 22695 : *pp = lp->next_lp;
4661 : :
4662 : 22695 : lp->region = new_region;
4663 : 22695 : lp->next_lp = new_region->landing_pads;
4664 : 22695 : new_region->landing_pads = lp;
4665 : :
4666 : : /* Delete the RESX that was matched within the empty handler block. */
4667 : 22695 : gsi = gsi_last_bb (bb);
4668 : 22695 : unlink_stmt_vdef (gsi_stmt (gsi));
4669 : 22695 : gsi_remove (&gsi, true);
4670 : :
4671 : : /* Clean up E_OUT for the fallthru. */
4672 : 22695 : e_out->flags = (e_out->flags & ~EDGE_EH) | EDGE_FALLTHRU;
4673 : 22695 : e_out->probability = profile_probability::always ();
4674 : 0 : }
4675 : :
4676 : : /* A subroutine of cleanup_empty_eh. Handle more complex cases of
4677 : : unsplitting than unsplit_eh was prepared to handle, e.g. when
4678 : : multiple incoming edges and phis are involved. */
4679 : :
4680 : : static bool
4681 : 27072 : cleanup_empty_eh_unsplit (basic_block bb, edge e_out, eh_landing_pad lp)
4682 : : {
4683 : 27072 : gimple_stmt_iterator gsi;
4684 : 27072 : tree lab;
4685 : :
4686 : : /* We really ought not have totally lost everything following
4687 : : a landing pad label. Given that BB is empty, there had better
4688 : : be a successor. */
4689 : 27072 : gcc_assert (e_out != NULL);
4690 : :
4691 : : /* The destination block must not already have a landing pad
4692 : : for a different region. */
4693 : 27072 : lab = NULL;
4694 : 80122 : for (gsi = gsi_start_bb (e_out->dest); !gsi_end_p (gsi); gsi_next (&gsi))
4695 : : {
4696 : 53050 : glabel *stmt = dyn_cast <glabel *> (gsi_stmt (gsi));
4697 : 25978 : int lp_nr;
4698 : :
4699 : 25978 : if (!stmt)
4700 : : break;
4701 : 25978 : lab = gimple_label_label (stmt);
4702 : 25978 : lp_nr = EH_LANDING_PAD_NR (lab);
4703 : 25978 : if (lp_nr && get_eh_region_from_lp_number (lp_nr) != lp->region)
4704 : : return false;
4705 : : }
4706 : :
4707 : : /* Attempt to move the PHIs into the successor block. */
4708 : 27072 : if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, false))
4709 : : {
4710 : 4558 : if (dump_file && (dump_flags & TDF_DETAILS))
4711 : 0 : fprintf (dump_file,
4712 : : "Unsplit EH landing pad %d to block %i "
4713 : : "(via cleanup_empty_eh).\n",
4714 : 0 : lp->index, e_out->dest->index);
4715 : 4558 : return true;
4716 : : }
4717 : :
4718 : : return false;
4719 : : }
4720 : :
4721 : : /* Return true if edge E_FIRST is part of an empty infinite loop
4722 : : or leads to such a loop through a series of single successor
4723 : : empty bbs. */
4724 : :
4725 : : static bool
4726 : 27122 : infinite_empty_loop_p (edge e_first)
4727 : : {
4728 : 27122 : bool inf_loop = false;
4729 : 27122 : edge e;
4730 : :
4731 : 27122 : if (e_first->dest == e_first->src)
4732 : : return true;
4733 : :
4734 : 27120 : e_first->src->aux = (void *) 1;
4735 : 27192 : for (e = e_first; single_succ_p (e->dest); e = single_succ_edge (e->dest))
4736 : : {
4737 : 8359 : gimple_stmt_iterator gsi;
4738 : 8359 : if (e->dest->aux)
4739 : : {
4740 : : inf_loop = true;
4741 : 8287 : break;
4742 : : }
4743 : 8311 : e->dest->aux = (void *) 1;
4744 : 8311 : gsi = gsi_after_labels (e->dest);
4745 : 8311 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4746 : 2964 : gsi_next_nondebug (&gsi);
4747 : 8311 : if (!gsi_end_p (gsi))
4748 : : break;
4749 : : }
4750 : 27120 : e_first->src->aux = NULL;
4751 : 35431 : for (e = e_first; e->dest->aux; e = single_succ_edge (e->dest))
4752 : 8311 : e->dest->aux = NULL;
4753 : :
4754 : : return inf_loop;
4755 : : }
4756 : :
4757 : : /* Examine the block associated with LP to determine if it's an empty
4758 : : handler for its EH region. If so, attempt to redirect EH edges to
4759 : : an outer region. Return true the CFG was updated in any way. This
4760 : : is similar to jump forwarding, just across EH edges. */
4761 : :
4762 : : static bool
4763 : 1362938 : cleanup_empty_eh (eh_landing_pad lp)
4764 : : {
4765 : 1362938 : basic_block bb = label_to_block (cfun, lp->post_landing_pad);
4766 : 1362938 : gimple_stmt_iterator gsi;
4767 : 1362938 : gimple *resx;
4768 : 1362938 : eh_region new_region;
4769 : 1362938 : edge_iterator ei;
4770 : 1362938 : edge e, e_out;
4771 : 1362938 : bool has_non_eh_pred;
4772 : 1362938 : bool ret = false;
4773 : 1362938 : int new_lp_nr;
4774 : :
4775 : : /* There can be zero or one edges out of BB. This is the quickest test. */
4776 : 1362938 : switch (EDGE_COUNT (bb->succs))
4777 : : {
4778 : : case 0:
4779 : : e_out = NULL;
4780 : : break;
4781 : 724094 : case 1:
4782 : 724094 : e_out = single_succ_edge (bb);
4783 : 724094 : break;
4784 : : default:
4785 : : return false;
4786 : : }
4787 : :
4788 : 1246714 : gsi = gsi_last_nondebug_bb (bb);
4789 : 1246714 : resx = gsi_stmt (gsi);
4790 : 1246714 : if (resx && is_gimple_resx (resx))
4791 : : {
4792 : 1080672 : if (stmt_can_throw_external (cfun, resx))
4793 : 521682 : optimize_clobbers (bb);
4794 : 558990 : else if (sink_clobbers (bb))
4795 : 1246714 : ret = true;
4796 : : }
4797 : :
4798 : 1246714 : gsi = gsi_after_labels (bb);
4799 : :
4800 : : /* Make sure to skip debug statements. */
4801 : 1246714 : if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi)))
4802 : 460699 : gsi_next_nondebug (&gsi);
4803 : :
4804 : : /* If the block is totally empty, look for more unsplitting cases. */
4805 : 1246714 : if (gsi_end_p (gsi))
4806 : : {
4807 : : /* For the degenerate case of an infinite loop bail out.
4808 : : If bb has no successors and is totally empty, which can happen e.g.
4809 : : because of incorrect noreturn attribute, bail out too. */
4810 : 27122 : if (e_out == NULL
4811 : 27122 : || infinite_empty_loop_p (e_out))
4812 : 50 : return ret;
4813 : :
4814 : 27072 : return ret | cleanup_empty_eh_unsplit (bb, e_out, lp);
4815 : : }
4816 : :
4817 : : /* The block should consist only of a single RESX statement, modulo a
4818 : : preceding call to __builtin_stack_restore if there is no outgoing
4819 : : edge, since the call can be eliminated in this case. */
4820 : 1219592 : resx = gsi_stmt (gsi);
4821 : 1219592 : if (!e_out && gimple_call_builtin_p (resx, BUILT_IN_STACK_RESTORE))
4822 : : {
4823 : 321 : gsi_next_nondebug (&gsi);
4824 : 321 : resx = gsi_stmt (gsi);
4825 : : }
4826 : 1219592 : if (!is_gimple_resx (resx))
4827 : : return ret;
4828 : 556668 : gcc_assert (gsi_one_nondebug_before_end_p (gsi));
4829 : :
4830 : : /* Determine if there are non-EH edges, or resx edges into the handler. */
4831 : 556668 : has_non_eh_pred = false;
4832 : 3166119 : FOR_EACH_EDGE (e, ei, bb->preds)
4833 : 2609451 : if (!(e->flags & EDGE_EH))
4834 : 15838 : has_non_eh_pred = true;
4835 : :
4836 : : /* Find the handler that's outer of the empty handler by looking at
4837 : : where the RESX instruction was vectored. */
4838 : 556668 : new_lp_nr = lookup_stmt_eh_lp (resx);
4839 : 556668 : new_region = get_eh_region_from_lp_number (new_lp_nr);
4840 : :
4841 : : /* If there's no destination region within the current function,
4842 : : redirection is trivial via removing the throwing statements from
4843 : : the EH region, removing the EH edges, and allowing the block
4844 : : to go unreachable. */
4845 : 556668 : if (new_region == NULL)
4846 : : {
4847 : 312774 : gcc_assert (e_out == NULL);
4848 : 1954633 : for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
4849 : 1641859 : if (e->flags & EDGE_EH)
4850 : : {
4851 : 1629250 : gimple *stmt = *gsi_last_bb (e->src);
4852 : 1629250 : remove_stmt_from_eh_lp (stmt);
4853 : 1629250 : remove_edge (e);
4854 : : }
4855 : : else
4856 : 12609 : ei_next (&ei);
4857 : 312774 : goto succeed;
4858 : : }
4859 : :
4860 : : /* If the destination region is a MUST_NOT_THROW, allow the runtime
4861 : : to handle the abort and allow the blocks to go unreachable. */
4862 : 243894 : if (new_region->type == ERT_MUST_NOT_THROW)
4863 : : {
4864 : 11 : for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
4865 : 6 : if (e->flags & EDGE_EH)
4866 : : {
4867 : 6 : gimple *stmt = *gsi_last_bb (e->src);
4868 : 6 : remove_stmt_from_eh_lp (stmt);
4869 : 6 : add_stmt_to_eh_lp (stmt, new_lp_nr);
4870 : 6 : remove_edge (e);
4871 : : }
4872 : : else
4873 : 0 : ei_next (&ei);
4874 : 5 : goto succeed;
4875 : : }
4876 : :
4877 : : /* Try to redirect the EH edges and merge the PHIs into the destination
4878 : : landing pad block. If the merge succeeds, we'll already have redirected
4879 : : all the EH edges. The handler itself will go unreachable if there were
4880 : : no normal edges. */
4881 : 243889 : if (cleanup_empty_eh_merge_phis (e_out->dest, bb, e_out, true))
4882 : 220342 : goto succeed;
4883 : :
4884 : : /* Finally, if all input edges are EH edges, then we can (potentially)
4885 : : reduce the number of transfers from the runtime by moving the landing
4886 : : pad from the original region to the new region. This is a win when
4887 : : we remove the last CLEANUP region along a particular exception
4888 : : propagation path. Since nothing changes except for the region with
4889 : : which the landing pad is associated, the PHI nodes do not need to be
4890 : : adjusted at all. */
4891 : 23547 : if (!has_non_eh_pred)
4892 : : {
4893 : 22695 : cleanup_empty_eh_move_lp (bb, e_out, lp, new_region);
4894 : 22695 : if (dump_file && (dump_flags & TDF_DETAILS))
4895 : 0 : fprintf (dump_file, "Empty EH handler %i moved to EH region %i.\n",
4896 : : lp->index, new_region->index);
4897 : :
4898 : : /* ??? The CFG didn't change, but we may have rendered the
4899 : : old EH region unreachable. Trigger a cleanup there. */
4900 : 22695 : return true;
4901 : : }
4902 : :
4903 : : return ret;
4904 : :
4905 : 533121 : succeed:
4906 : 533121 : if (dump_file && (dump_flags & TDF_DETAILS))
4907 : 6 : fprintf (dump_file, "Empty EH handler %i removed.\n", lp->index);
4908 : 533121 : remove_eh_landing_pad (lp);
4909 : 533121 : return true;
4910 : : }
4911 : :
4912 : : /* Do a post-order traversal of the EH region tree. Examine each
4913 : : post_landing_pad block and see if we can eliminate it as empty. */
4914 : :
4915 : : static bool
4916 : 345028 : cleanup_all_empty_eh (void)
4917 : : {
4918 : 345028 : bool changed = false;
4919 : 345028 : eh_landing_pad lp;
4920 : 345028 : int i;
4921 : :
4922 : : /* The post-order traversal may lead to quadraticness in the redirection
4923 : : of incoming EH edges from inner LPs, so first try to walk the region
4924 : : tree from inner to outer LPs in order to eliminate these edges. */
4925 : 2861830 : for (i = vec_safe_length (cfun->eh->lp_array) - 1; i >= 1; --i)
4926 : : {
4927 : 2171774 : lp = (*cfun->eh->lp_array)[i];
4928 : 2171774 : if (lp)
4929 : 949312 : changed |= cleanup_empty_eh (lp);
4930 : : }
4931 : :
4932 : : /* Now do the post-order traversal to eliminate outer empty LPs. */
4933 : 2517684 : for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i)
4934 : 2172656 : if (lp)
4935 : 413626 : changed |= cleanup_empty_eh (lp);
4936 : :
4937 : 345028 : return changed;
4938 : : }
4939 : :
4940 : : /* Perform cleanups and lowering of exception handling
4941 : : 1) cleanups regions with handlers doing nothing are optimized out
4942 : : 2) MUST_NOT_THROW regions that became dead because of 1) are optimized out
4943 : : 3) Info about regions that are containing instructions, and regions
4944 : : reachable via local EH edges is collected
4945 : : 4) Eh tree is pruned for regions no longer necessary.
4946 : :
4947 : : TODO: Push MUST_NOT_THROW regions to the root of the EH tree.
4948 : : Unify those that have the same failure decl and locus.
4949 : : */
4950 : :
4951 : : static unsigned int
4952 : 1171970 : execute_cleanup_eh_1 (void)
4953 : : {
4954 : : /* Do this first: unsplit_all_eh and cleanup_all_empty_eh can die
4955 : : looking up unreachable landing pads. */
4956 : 1171970 : remove_unreachable_handlers ();
4957 : :
4958 : : /* Watch out for the region tree vanishing due to all unreachable. */
4959 : 1171970 : if (cfun->eh->region_tree)
4960 : : {
4961 : 345028 : bool changed = false;
4962 : :
4963 : 345028 : if (optimize)
4964 : 317287 : changed |= unsplit_all_eh ();
4965 : 345028 : changed |= cleanup_all_empty_eh ();
4966 : :
4967 : 345028 : if (changed)
4968 : : {
4969 : 286805 : free_dominance_info (CDI_DOMINATORS);
4970 : 286805 : free_dominance_info (CDI_POST_DOMINATORS);
4971 : :
4972 : : /* We delayed all basic block deletion, as we may have performed
4973 : : cleanups on EH edges while non-EH edges were still present. */
4974 : 286805 : delete_unreachable_blocks ();
4975 : :
4976 : : /* We manipulated the landing pads. Remove any region that no
4977 : : longer has a landing pad. */
4978 : 286805 : remove_unreachable_handlers_no_lp ();
4979 : :
4980 : 286805 : return TODO_cleanup_cfg | TODO_update_ssa_only_virtuals;
4981 : : }
4982 : : }
4983 : :
4984 : : return 0;
4985 : : }
4986 : :
4987 : : namespace {
4988 : :
4989 : : const pass_data pass_data_cleanup_eh =
4990 : : {
4991 : : GIMPLE_PASS, /* type */
4992 : : "ehcleanup", /* name */
4993 : : OPTGROUP_NONE, /* optinfo_flags */
4994 : : TV_TREE_EH, /* tv_id */
4995 : : PROP_gimple_lcf, /* properties_required */
4996 : : 0, /* properties_provided */
4997 : : 0, /* properties_destroyed */
4998 : : 0, /* todo_flags_start */
4999 : : 0, /* todo_flags_finish */
5000 : : };
5001 : :
5002 : : class pass_cleanup_eh : public gimple_opt_pass
5003 : : {
5004 : : public:
5005 : 580066 : pass_cleanup_eh (gcc::context *ctxt)
5006 : 1160132 : : gimple_opt_pass (pass_data_cleanup_eh, ctxt)
5007 : : {}
5008 : :
5009 : : /* opt_pass methods: */
5010 : 290033 : opt_pass * clone () final override { return new pass_cleanup_eh (m_ctxt); }
5011 : 3977418 : bool gate (function *fun) final override
5012 : : {
5013 : 3977418 : return fun->eh != NULL && fun->eh->region_tree != NULL;
5014 : : }
5015 : :
5016 : : unsigned int execute (function *) final override;
5017 : :
5018 : : }; // class pass_cleanup_eh
5019 : :
5020 : : unsigned int
5021 : 1171970 : pass_cleanup_eh::execute (function *fun)
5022 : : {
5023 : 1171970 : int ret = execute_cleanup_eh_1 ();
5024 : :
5025 : : /* If the function no longer needs an EH personality routine
5026 : : clear it. This exposes cross-language inlining opportunities
5027 : : and avoids references to a never defined personality routine. */
5028 : 1171970 : if (DECL_FUNCTION_PERSONALITY (current_function_decl)
5029 : 1171970 : && function_needs_eh_personality (fun) != eh_personality_lang)
5030 : 781449 : DECL_FUNCTION_PERSONALITY (current_function_decl) = NULL_TREE;
5031 : :
5032 : 1171970 : return ret;
5033 : : }
5034 : :
5035 : : } // anon namespace
5036 : :
5037 : : gimple_opt_pass *
5038 : 290033 : make_pass_cleanup_eh (gcc::context *ctxt)
5039 : : {
5040 : 290033 : return new pass_cleanup_eh (ctxt);
5041 : : }
5042 : :
5043 : : /* Disable warnings about missing quoting in GCC diagnostics for
5044 : : the verification errors. Their format strings don't follow GCC
5045 : : diagnostic conventions but are only used for debugging. */
5046 : : #if __GNUC__ >= 10
5047 : : # pragma GCC diagnostic push
5048 : : # pragma GCC diagnostic ignored "-Wformat-diag"
5049 : : #endif
5050 : :
5051 : : /* Verify that BB containing STMT as the last statement, has precisely the
5052 : : edge that make_eh_edge would create. */
5053 : :
5054 : : DEBUG_FUNCTION bool
5055 : 1836270331 : verify_eh_edges (gimple *stmt)
5056 : : {
5057 : 1836270331 : basic_block bb = gimple_bb (stmt);
5058 : 1836270331 : eh_landing_pad lp = NULL;
5059 : 1836270331 : int lp_nr;
5060 : 1836270331 : edge_iterator ei;
5061 : 1836270331 : edge e, eh_edge;
5062 : :
5063 : 1836270331 : lp_nr = lookup_stmt_eh_lp (stmt);
5064 : 1836270331 : if (lp_nr > 0)
5065 : 203308276 : lp = get_eh_landing_pad_from_number (lp_nr);
5066 : :
5067 : 1836270331 : eh_edge = NULL;
5068 : 4475573158 : FOR_EACH_EDGE (e, ei, bb->succs)
5069 : : {
5070 : 2639302827 : if (e->flags & EDGE_EH)
5071 : : {
5072 : 203308276 : if (eh_edge)
5073 : : {
5074 : 0 : error ("BB %i has multiple EH edges", bb->index);
5075 : 0 : return true;
5076 : : }
5077 : : else
5078 : : eh_edge = e;
5079 : : }
5080 : : }
5081 : :
5082 : 1836270331 : if (lp == NULL)
5083 : : {
5084 : 1632962055 : if (eh_edge)
5085 : : {
5086 : 0 : error ("BB %i cannot throw but has an EH edge", bb->index);
5087 : 0 : return true;
5088 : : }
5089 : : return false;
5090 : : }
5091 : :
5092 : 203308276 : if (!stmt_could_throw_p (cfun, stmt))
5093 : : {
5094 : 0 : error ("BB %i last statement has incorrectly set lp", bb->index);
5095 : 0 : return true;
5096 : : }
5097 : :
5098 : 203308276 : if (eh_edge == NULL)
5099 : : {
5100 : 0 : error ("BB %i is missing an EH edge", bb->index);
5101 : 0 : return true;
5102 : : }
5103 : :
5104 : 203308276 : if (eh_edge->dest != label_to_block (cfun, lp->post_landing_pad))
5105 : : {
5106 : 0 : error ("Incorrect EH edge %i->%i", bb->index, eh_edge->dest->index);
5107 : 0 : return true;
5108 : : }
5109 : :
5110 : : return false;
5111 : : }
5112 : :
5113 : : /* Similarly, but handle GIMPLE_EH_DISPATCH specifically. */
5114 : :
5115 : : DEBUG_FUNCTION bool
5116 : 1883496 : verify_eh_dispatch_edge (geh_dispatch *stmt)
5117 : : {
5118 : 1883496 : eh_region r;
5119 : 1883496 : eh_catch c;
5120 : 1883496 : basic_block src, dst;
5121 : 1883496 : bool want_fallthru = true;
5122 : 1883496 : edge_iterator ei;
5123 : 1883496 : edge e, fall_edge;
5124 : :
5125 : 1883496 : r = get_eh_region_from_number (gimple_eh_dispatch_region (stmt));
5126 : 1883496 : src = gimple_bb (stmt);
5127 : :
5128 : 4014685 : FOR_EACH_EDGE (e, ei, src->succs)
5129 : 2131189 : gcc_assert (e->aux == NULL);
5130 : :
5131 : 1883496 : switch (r->type)
5132 : : {
5133 : 1874876 : case ERT_TRY:
5134 : 2113949 : for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
5135 : : {
5136 : 1984163 : dst = label_to_block (cfun, c->label);
5137 : 1984163 : e = find_edge (src, dst);
5138 : 1984163 : if (e == NULL)
5139 : : {
5140 : 0 : error ("BB %i is missing an edge", src->index);
5141 : 0 : return true;
5142 : : }
5143 : 1984163 : e->aux = (void *)e;
5144 : :
5145 : : /* A catch-all handler doesn't have a fallthru. */
5146 : 1984163 : if (c->type_list == NULL)
5147 : : {
5148 : : want_fallthru = false;
5149 : : break;
5150 : : }
5151 : : }
5152 : : break;
5153 : :
5154 : 8620 : case ERT_ALLOWED_EXCEPTIONS:
5155 : 8620 : dst = label_to_block (cfun, r->u.allowed.label);
5156 : 8620 : e = find_edge (src, dst);
5157 : 8620 : if (e == NULL)
5158 : : {
5159 : 0 : error ("BB %i is missing an edge", src->index);
5160 : 0 : return true;
5161 : : }
5162 : 8620 : e->aux = (void *)e;
5163 : 8620 : break;
5164 : :
5165 : 0 : default:
5166 : 0 : gcc_unreachable ();
5167 : : }
5168 : :
5169 : 1883496 : fall_edge = NULL;
5170 : 4014685 : FOR_EACH_EDGE (e, ei, src->succs)
5171 : : {
5172 : 2131189 : if (e->flags & EDGE_FALLTHRU)
5173 : : {
5174 : 138406 : if (fall_edge != NULL)
5175 : : {
5176 : 0 : error ("BB %i too many fallthru edges", src->index);
5177 : 0 : return true;
5178 : : }
5179 : : fall_edge = e;
5180 : : }
5181 : 1992783 : else if (e->aux)
5182 : 1992783 : e->aux = NULL;
5183 : : else
5184 : : {
5185 : 0 : error ("BB %i has incorrect edge", src->index);
5186 : 0 : return true;
5187 : : }
5188 : : }
5189 : 1883496 : if ((fall_edge != NULL) ^ want_fallthru)
5190 : : {
5191 : 0 : error ("BB %i has incorrect fallthru edge", src->index);
5192 : 0 : return true;
5193 : : }
5194 : :
5195 : : return false;
5196 : : }
5197 : :
5198 : : #if __GNUC__ >= 10
5199 : : # pragma GCC diagnostic pop
5200 : : #endif
|