]>
Commit | Line | Data |
---|---|---|
6de9cd9a DN |
1 | /* Tree lowering pass. Lowers GIMPLE into unstructured form. |
2 | ||
3 | Copyright (C) 2003 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 2, or (at your option) any later | |
10 | version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING. If not, write to the Free | |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
20 | 02111-1307, USA. */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "tm.h" | |
26 | #include "tree.h" | |
27 | #include "rtl.h" | |
28 | #include "errors.h" | |
29 | #include "varray.h" | |
eadf906f | 30 | #include "tree-gimple.h" |
6de9cd9a DN |
31 | #include "tree-inline.h" |
32 | #include "diagnostic.h" | |
33 | #include "langhooks.h" | |
34 | #include "langhooks-def.h" | |
35 | #include "tree-flow.h" | |
36 | #include "timevar.h" | |
37 | #include "except.h" | |
38 | #include "hashtab.h" | |
39 | #include "flags.h" | |
40 | #include "function.h" | |
41 | #include "expr.h" | |
42 | #include "toplev.h" | |
43 | #include "tree-pass.h" | |
44 | ||
45 | struct lower_data | |
46 | { | |
47 | /* Block the current statement belongs to. */ | |
48 | tree block; | |
f5a76aea | 49 | |
71877985 RH |
50 | /* A TREE_LIST of label and return statements to be moved to the end |
51 | of the function. */ | |
52 | tree return_statements; | |
6de9cd9a DN |
53 | }; |
54 | ||
55 | static void lower_stmt (tree_stmt_iterator *, struct lower_data *); | |
56 | static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); | |
57 | static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); | |
f5a76aea | 58 | static void lower_return_expr (tree_stmt_iterator *, struct lower_data *); |
6de9cd9a DN |
59 | static bool expand_var_p (tree); |
60 | ||
61 | /* Lowers the body of current_function_decl. */ | |
62 | ||
63 | static void | |
64 | lower_function_body (void) | |
65 | { | |
66 | struct lower_data data; | |
67 | tree *body_p = &DECL_SAVED_TREE (current_function_decl); | |
68 | tree bind = *body_p; | |
69 | tree_stmt_iterator i; | |
70 | ||
71 | if (TREE_CODE (bind) != BIND_EXPR) | |
72 | abort (); | |
73 | ||
74 | data.block = DECL_INITIAL (current_function_decl); | |
75 | BLOCK_SUBBLOCKS (data.block) = NULL_TREE; | |
76 | BLOCK_CHAIN (data.block) = NULL_TREE; | |
77 | TREE_ASM_WRITTEN (data.block) = 1; | |
78 | ||
71877985 | 79 | data.return_statements = NULL_TREE; |
f5a76aea | 80 | |
6de9cd9a DN |
81 | *body_p = alloc_stmt_list (); |
82 | i = tsi_start (*body_p); | |
83 | tsi_link_after (&i, bind, TSI_NEW_STMT); | |
84 | lower_bind_expr (&i, &data); | |
85 | ||
f5a76aea RH |
86 | /* If we lowered any return statements, emit the representative at the |
87 | end of the function. */ | |
71877985 | 88 | if (data.return_statements) |
f5a76aea | 89 | { |
71877985 | 90 | tree t, x; |
f5a76aea | 91 | i = tsi_last (*body_p); |
71877985 RH |
92 | |
93 | for (t = data.return_statements; t ; t = TREE_CHAIN (t)) | |
94 | { | |
95 | x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t)); | |
96 | tsi_link_after (&i, x, TSI_CONTINUE_LINKING); | |
97 | ||
98 | /* Remove the line number from the representative return statement. | |
99 | It now fills in for many such returns. Failure to remove this | |
100 | will result in incorrect results for coverage analysis. */ | |
101 | x = TREE_VALUE (t); | |
102 | SET_EXPR_LOCUS (x, NULL); | |
103 | tsi_link_after (&i, x, TSI_CONTINUE_LINKING); | |
104 | } | |
f5a76aea RH |
105 | } |
106 | ||
6de9cd9a DN |
107 | if (data.block != DECL_INITIAL (current_function_decl)) |
108 | abort (); | |
109 | BLOCK_SUBBLOCKS (data.block) | |
110 | = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); | |
111 | ||
112 | clear_block_marks (data.block); | |
113 | ||
114 | /* Avoid producing notes for blocks. */ | |
115 | cfun->dont_emit_block_notes = 1; | |
116 | reset_block_changes (); | |
117 | } | |
118 | ||
119 | struct tree_opt_pass pass_lower_cf = | |
120 | { | |
121 | "lower", /* name */ | |
122 | NULL, /* gate */ | |
123 | lower_function_body, /* execute */ | |
124 | NULL, /* sub */ | |
125 | NULL, /* next */ | |
126 | 0, /* static_pass_number */ | |
127 | 0, /* tv_id */ | |
128 | PROP_gimple_any, /* properties_required */ | |
129 | PROP_gimple_lcf, /* properties_provided */ | |
130 | PROP_gimple_any, /* properties_destroyed */ | |
131 | 0, /* todo_flags_start */ | |
132 | TODO_dump_func /* todo_flags_finish */ | |
133 | }; | |
134 | ||
135 | ||
136 | /* Lowers the EXPR. Unlike gimplification the statements are not relowered | |
137 | when they are changed -- if this has to be done, the lowering routine must | |
138 | do it explicitly. DATA is passed through the recursion. */ | |
139 | ||
140 | void | |
141 | lower_stmt_body (tree expr, struct lower_data *data) | |
142 | { | |
143 | tree_stmt_iterator tsi; | |
144 | ||
145 | for (tsi = tsi_start (expr); !tsi_end_p (tsi); ) | |
146 | lower_stmt (&tsi, data); | |
147 | } | |
148 | ||
149 | /* Lowers statement TSI. DATA is passed through the recursion. */ | |
150 | ||
151 | static void | |
152 | lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) | |
153 | { | |
154 | tree stmt = tsi_stmt (*tsi); | |
155 | ||
156 | if (EXPR_HAS_LOCATION (stmt) && data) | |
157 | TREE_BLOCK (stmt) = data->block; | |
158 | ||
159 | switch (TREE_CODE (stmt)) | |
160 | { | |
161 | case BIND_EXPR: | |
162 | lower_bind_expr (tsi, data); | |
163 | return; | |
164 | case COND_EXPR: | |
165 | lower_cond_expr (tsi, data); | |
166 | return; | |
f5a76aea RH |
167 | case RETURN_EXPR: |
168 | lower_return_expr (tsi, data); | |
169 | return; | |
6de9cd9a DN |
170 | |
171 | case TRY_FINALLY_EXPR: | |
172 | case TRY_CATCH_EXPR: | |
173 | lower_stmt_body (TREE_OPERAND (stmt, 0), data); | |
174 | lower_stmt_body (TREE_OPERAND (stmt, 1), data); | |
175 | break; | |
176 | case CATCH_EXPR: | |
177 | lower_stmt_body (CATCH_BODY (stmt), data); | |
178 | break; | |
179 | case EH_FILTER_EXPR: | |
180 | lower_stmt_body (EH_FILTER_FAILURE (stmt), data); | |
181 | break; | |
182 | ||
183 | case NOP_EXPR: | |
184 | case ASM_EXPR: | |
6de9cd9a DN |
185 | case MODIFY_EXPR: |
186 | case CALL_EXPR: | |
187 | case GOTO_EXPR: | |
188 | case LABEL_EXPR: | |
189 | case VA_ARG_EXPR: | |
190 | case SWITCH_EXPR: | |
191 | break; | |
192 | ||
193 | default: | |
194 | print_node_brief (stderr, "", stmt, 0); | |
195 | case COMPOUND_EXPR: | |
196 | abort (); | |
197 | } | |
198 | ||
199 | tsi_next (tsi); | |
200 | } | |
201 | ||
202 | /* Lowers a bind_expr TSI. DATA is passed through the recursion. */ | |
203 | ||
204 | static void | |
205 | lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) | |
206 | { | |
207 | tree old_block = data->block; | |
208 | tree stmt = tsi_stmt (*tsi); | |
209 | tree new_block = BIND_EXPR_BLOCK (stmt); | |
210 | ||
211 | if (new_block) | |
212 | { | |
213 | if (new_block == old_block) | |
214 | { | |
215 | /* The outermost block of the original function may not be the | |
216 | outermost statement chain of the gimplified function. So we | |
217 | may see the outermost block just inside the function. */ | |
218 | if (new_block != DECL_INITIAL (current_function_decl)) | |
219 | abort (); | |
220 | new_block = NULL; | |
221 | } | |
222 | else | |
223 | { | |
224 | /* We do not expect to handle duplicate blocks. */ | |
225 | if (TREE_ASM_WRITTEN (new_block)) | |
226 | abort (); | |
227 | TREE_ASM_WRITTEN (new_block) = 1; | |
228 | ||
229 | /* Block tree may get clobbered by inlining. Normally this would | |
230 | be fixed in rest_of_decl_compilation using block notes, but | |
231 | since we are not going to emit them, it is up to us. */ | |
232 | BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block); | |
233 | BLOCK_SUBBLOCKS (old_block) = new_block; | |
234 | BLOCK_SUBBLOCKS (new_block) = NULL_TREE; | |
235 | BLOCK_SUPERCONTEXT (new_block) = old_block; | |
236 | ||
237 | data->block = new_block; | |
238 | } | |
239 | } | |
240 | ||
241 | record_vars (BIND_EXPR_VARS (stmt)); | |
242 | lower_stmt_body (BIND_EXPR_BODY (stmt), data); | |
243 | ||
244 | if (new_block) | |
245 | { | |
246 | if (data->block != new_block) | |
247 | abort (); | |
248 | ||
249 | BLOCK_SUBBLOCKS (new_block) | |
250 | = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); | |
251 | data->block = old_block; | |
252 | } | |
253 | ||
254 | /* The BIND_EXPR no longer carries any useful information -- kill it. */ | |
255 | tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT); | |
256 | tsi_delink (tsi); | |
257 | } | |
258 | ||
259 | /* Try to determine if we can fall out of the bottom of BLOCK. This guess | |
260 | need not be 100% accurate; simply be conservative and return true if we | |
261 | don't know. This is used only to avoid stupidly generating extra code. | |
262 | If we're wrong, we'll just delete the extra code later. */ | |
263 | ||
264 | bool | |
265 | block_may_fallthru (tree block) | |
266 | { | |
267 | tree stmt = expr_last (block); | |
268 | ||
269 | switch (stmt ? TREE_CODE (stmt) : ERROR_MARK) | |
270 | { | |
271 | case GOTO_EXPR: | |
272 | case RETURN_EXPR: | |
273 | case RESX_EXPR: | |
274 | case SWITCH_EXPR: | |
275 | /* Easy cases. If the last statement of the block implies | |
276 | control transfer, then we can't fall through. */ | |
277 | return false; | |
278 | ||
279 | case COND_EXPR: | |
280 | if (block_may_fallthru (COND_EXPR_THEN (stmt))) | |
281 | return true; | |
282 | return block_may_fallthru (COND_EXPR_ELSE (stmt)); | |
283 | ||
284 | case BIND_EXPR: | |
285 | return block_may_fallthru (BIND_EXPR_BODY (stmt)); | |
286 | ||
287 | case TRY_FINALLY_EXPR: | |
288 | return block_may_fallthru (TREE_OPERAND (stmt, 1)); | |
289 | ||
290 | case MODIFY_EXPR: | |
291 | if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) | |
292 | stmt = TREE_OPERAND (stmt, 1); | |
293 | else | |
294 | return true; | |
295 | /* FALLTHRU */ | |
296 | ||
297 | case CALL_EXPR: | |
298 | /* Functions that do not return do not fall through. */ | |
299 | return (call_expr_flags (stmt) & ECF_NORETURN) == 0; | |
300 | ||
301 | default: | |
302 | return true; | |
303 | } | |
304 | } | |
305 | ||
306 | /* Lowers a cond_expr TSI. DATA is passed through the recursion. */ | |
307 | ||
308 | static void | |
309 | lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data) | |
310 | { | |
311 | tree stmt = tsi_stmt (*tsi); | |
312 | bool then_is_goto, else_is_goto; | |
313 | tree then_branch, else_branch; | |
314 | tree then_goto, else_goto; | |
315 | ||
316 | then_branch = COND_EXPR_THEN (stmt); | |
317 | else_branch = COND_EXPR_ELSE (stmt); | |
318 | ||
319 | lower_stmt_body (then_branch, data); | |
320 | lower_stmt_body (else_branch, data); | |
321 | ||
322 | then_goto = expr_only (then_branch); | |
323 | then_is_goto = then_goto && simple_goto_p (then_goto); | |
324 | ||
325 | else_goto = expr_only (else_branch); | |
326 | else_is_goto = else_goto && simple_goto_p (else_goto); | |
327 | ||
328 | if (!then_is_goto || !else_is_goto) | |
329 | { | |
330 | tree then_label, else_label, end_label, t; | |
331 | ||
332 | then_label = NULL_TREE; | |
333 | else_label = NULL_TREE; | |
334 | end_label = NULL_TREE; | |
335 | ||
336 | /* Replace the cond_expr with explicit gotos. */ | |
337 | if (!then_is_goto) | |
338 | { | |
339 | t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); | |
340 | if (TREE_SIDE_EFFECTS (then_branch)) | |
341 | then_label = t; | |
342 | else | |
343 | end_label = t; | |
344 | then_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); | |
345 | } | |
346 | ||
347 | if (!else_is_goto) | |
348 | { | |
349 | t = build1 (LABEL_EXPR, void_type_node, NULL_TREE); | |
350 | if (TREE_SIDE_EFFECTS (else_branch)) | |
351 | else_label = t; | |
352 | else | |
353 | { | |
354 | /* Both THEN and ELSE can be no-ops if one or both contained an | |
355 | empty BIND_EXPR that was associated with the toplevel block | |
356 | of an inlined function. In that case remove_useless_stmts | |
357 | can't have cleaned things up for us; kill the whole | |
358 | conditional now. */ | |
359 | if (end_label) | |
360 | { | |
361 | tsi_delink (tsi); | |
362 | return; | |
363 | } | |
364 | else | |
365 | end_label = t; | |
366 | } | |
367 | else_goto = build_and_jump (&LABEL_EXPR_LABEL (t)); | |
368 | } | |
369 | ||
370 | if (then_label) | |
371 | { | |
372 | bool may_fallthru = block_may_fallthru (then_branch); | |
373 | ||
374 | tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING); | |
375 | tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING); | |
376 | ||
377 | if (else_label && may_fallthru) | |
378 | { | |
379 | end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE); | |
380 | t = build_and_jump (&LABEL_EXPR_LABEL (end_label)); | |
381 | tsi_link_after (tsi, t, TSI_CONTINUE_LINKING); | |
382 | } | |
383 | } | |
384 | ||
385 | if (else_label) | |
386 | { | |
387 | tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING); | |
388 | tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING); | |
389 | } | |
390 | ||
391 | if (end_label) | |
392 | tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING); | |
393 | } | |
394 | ||
395 | COND_EXPR_THEN (stmt) = then_goto; | |
396 | COND_EXPR_ELSE (stmt) = else_goto; | |
397 | ||
398 | tsi_next (tsi); | |
399 | } | |
f5a76aea RH |
400 | |
401 | static void | |
402 | lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) | |
403 | { | |
71877985 RH |
404 | tree stmt = tsi_stmt (*tsi); |
405 | tree value, t, label; | |
406 | ||
407 | /* Extract the value being returned. */ | |
408 | value = TREE_OPERAND (stmt, 0); | |
409 | if (value && TREE_CODE (value) == MODIFY_EXPR) | |
410 | value = TREE_OPERAND (value, 1); | |
f5a76aea | 411 | |
71877985 RH |
412 | /* Match this up with an existing return statement that's been created. */ |
413 | for (t = data->return_statements; t ; t = TREE_CHAIN (t)) | |
f5a76aea | 414 | { |
71877985 RH |
415 | tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0); |
416 | if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR) | |
417 | tvalue = TREE_OPERAND (tvalue, 1); | |
418 | ||
419 | if (value == tvalue) | |
420 | { | |
421 | label = TREE_PURPOSE (t); | |
422 | goto found; | |
423 | } | |
f5a76aea RH |
424 | } |
425 | ||
71877985 RH |
426 | /* Not found. Create a new label and record the return statement. */ |
427 | label = create_artificial_label (); | |
428 | data->return_statements = tree_cons (label, stmt, data->return_statements); | |
429 | ||
430 | /* Generate a goto statement and remove the return statement. */ | |
431 | found: | |
432 | t = build (GOTO_EXPR, void_type_node, label); | |
433 | SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); | |
434 | tsi_link_before (tsi, t, TSI_SAME_STMT); | |
f5a76aea RH |
435 | tsi_delink (tsi); |
436 | } | |
6de9cd9a DN |
437 | \f |
438 | ||
439 | /* Record the variables in VARS. */ | |
440 | ||
441 | void | |
442 | record_vars (tree vars) | |
443 | { | |
444 | for (; vars; vars = TREE_CHAIN (vars)) | |
445 | { | |
446 | tree var = vars; | |
447 | ||
448 | /* Nothing to do in this case. */ | |
449 | if (DECL_EXTERNAL (var)) | |
450 | continue; | |
451 | if (TREE_CODE (var) == FUNCTION_DECL) | |
452 | continue; | |
453 | ||
454 | /* Record the variable. */ | |
455 | cfun->unexpanded_var_list = tree_cons (NULL_TREE, var, | |
456 | cfun->unexpanded_var_list); | |
457 | } | |
458 | } | |
459 | ||
460 | /* Check whether to expand a variable VAR. */ | |
461 | ||
462 | static bool | |
463 | expand_var_p (tree var) | |
464 | { | |
465 | struct var_ann_d *ann; | |
466 | ||
467 | if (TREE_CODE (var) != VAR_DECL) | |
468 | return true; | |
469 | ||
470 | ann = var_ann (var); | |
471 | ||
472 | /* Remove all unused, unaliased temporaries. Also remove unused, unaliased | |
473 | local variables during highly optimizing compilations. */ | |
474 | ann = var_ann (var); | |
475 | if (ann | |
476 | && ! ann->may_aliases | |
477 | && ! ann->used | |
478 | && ! ann->has_hidden_use | |
479 | && ! TREE_ADDRESSABLE (var) | |
480 | && ! TREE_THIS_VOLATILE (var) | |
481 | && (DECL_ARTIFICIAL (var) || optimize >= 2)) | |
482 | return false; | |
483 | ||
484 | return true; | |
485 | } | |
486 | ||
487 | /* Throw away variables that are unused. */ | |
488 | ||
489 | static void | |
490 | remove_useless_vars (void) | |
491 | { | |
492 | tree var, *cell; | |
493 | ||
494 | for (cell = &cfun->unexpanded_var_list; *cell; ) | |
495 | { | |
496 | var = TREE_VALUE (*cell); | |
497 | ||
498 | if (!expand_var_p (var)) | |
499 | { | |
500 | *cell = TREE_CHAIN (*cell); | |
501 | continue; | |
502 | } | |
503 | ||
504 | cell = &TREE_CHAIN (*cell); | |
505 | } | |
506 | } | |
507 | ||
508 | /* Expand variables in the unexpanded_var_list. */ | |
509 | ||
510 | void | |
511 | expand_used_vars (void) | |
512 | { | |
513 | tree cell; | |
514 | ||
515 | cfun->unexpanded_var_list = nreverse (cfun->unexpanded_var_list); | |
516 | ||
517 | for (cell = cfun->unexpanded_var_list; cell; cell = TREE_CHAIN (cell)) | |
518 | expand_var (TREE_VALUE (cell)); | |
519 | ||
520 | cfun->unexpanded_var_list = NULL_TREE; | |
521 | } | |
522 | ||
523 | struct tree_opt_pass pass_remove_useless_vars = | |
524 | { | |
525 | "vars", /* name */ | |
526 | NULL, /* gate */ | |
527 | remove_useless_vars, /* execute */ | |
528 | NULL, /* sub */ | |
529 | NULL, /* next */ | |
530 | 0, /* static_pass_number */ | |
531 | 0, /* tv_id */ | |
532 | 0, /* properties_required */ | |
533 | 0, /* properties_provided */ | |
534 | 0, /* properties_destroyed */ | |
535 | 0, /* todo_flags_start */ | |
536 | TODO_dump_func /* todo_flags_finish */ | |
537 | }; |