OSDN Git Service

2008-01-15 Sebastian Pop <sebastian.pop@amd.com>
[pf3gnuchains/gcc-fork.git] / gcc / gimple-low.c
1 /* Tree lowering pass.  Lowers GIMPLE into unstructured form.
2
3    Copyright (C) 2003, 2004, 2005, 2006, 2007 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 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "rtl.h"
27 #include "varray.h"
28 #include "tree-gimple.h"
29 #include "tree-inline.h"
30 #include "diagnostic.h"
31 #include "langhooks.h"
32 #include "langhooks-def.h"
33 #include "tree-flow.h"
34 #include "timevar.h"
35 #include "except.h"
36 #include "hashtab.h"
37 #include "flags.h"
38 #include "function.h"
39 #include "expr.h"
40 #include "toplev.h"
41 #include "tree-pass.h"
42
43 struct lower_data
44 {
45   /* Block the current statement belongs to.  */
46   tree block;
47
48   /* A TREE_LIST of label and return statements to be moved to the end
49      of the function.  */
50   tree return_statements;
51
52   /* True if the function calls __builtin_setjmp.  */
53   bool calls_builtin_setjmp;
54 };
55
56 static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
57 static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *);
58 static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *);
59 static void lower_return_expr (tree_stmt_iterator *, struct lower_data *);
60 static void lower_builtin_setjmp (tree_stmt_iterator *);
61
62 /* Lower the body of current_function_decl.  */
63
64 static unsigned int
65 lower_function_body (void)
66 {
67   struct lower_data data;
68   tree *body_p = &DECL_SAVED_TREE (current_function_decl);
69   tree bind = *body_p;
70   tree_stmt_iterator i;
71   tree t, x;
72
73   gcc_assert (TREE_CODE (bind) == BIND_EXPR);
74
75   memset (&data, 0, sizeof (data));
76   data.block = DECL_INITIAL (current_function_decl);
77   BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
78   BLOCK_CHAIN (data.block) = NULL_TREE;
79   TREE_ASM_WRITTEN (data.block) = 1;
80
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
86   i = tsi_last (*body_p);
87
88   /* If the function falls off the end, we need a null return statement.
89      If we've already got one in the return_statements list, we don't
90      need to do anything special.  Otherwise build one by hand.  */
91   if (block_may_fallthru (*body_p)
92       && (data.return_statements == NULL
93           || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL))
94     {
95       x = build1 (RETURN_EXPR, void_type_node, NULL);
96       SET_EXPR_LOCATION (x, cfun->function_end_locus);
97       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
98     }
99
100   /* If we lowered any return statements, emit the representative
101      at the end of the function.  */
102   for (t = data.return_statements ; t ; t = TREE_CHAIN (t))
103     {
104       x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
105       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
106
107       /* Remove the line number from the representative return statement.
108          It now fills in for many such returns.  Failure to remove this
109          will result in incorrect results for coverage analysis.  */
110       x = TREE_VALUE (t);
111 #ifdef USE_MAPPED_LOCATION
112       SET_EXPR_LOCATION (x, UNKNOWN_LOCATION);
113 #else
114       SET_EXPR_LOCUS (x, NULL);
115 #endif
116       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
117     }
118
119   /* If the function calls __builtin_setjmp, we need to emit the computed
120      goto that will serve as the unique dispatcher for all the receivers.  */
121   if (data.calls_builtin_setjmp)
122     {
123       tree disp_label, disp_var, arg;
124
125       /* Build 'DISP_LABEL:' and insert.  */
126       disp_label = create_artificial_label ();
127       /* This mark will create forward edges from every call site.  */
128       DECL_NONLOCAL (disp_label) = 1;
129       current_function_has_nonlocal_label = 1;
130       x = build1 (LABEL_EXPR, void_type_node, disp_label);
131       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
132
133       /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);'
134          and insert.  */
135       disp_var = create_tmp_var (ptr_type_node, "setjmpvar");
136       arg = build_addr (disp_label, current_function_decl);
137       t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER];
138       t = build_call_expr (t, 1, arg);
139       x = build_gimple_modify_stmt (disp_var, t);
140
141       /* Build 'goto DISP_VAR;' and insert.  */
142       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
143       x = build1 (GOTO_EXPR, void_type_node, disp_var);
144       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
145     }
146
147   gcc_assert (data.block == DECL_INITIAL (current_function_decl));
148   BLOCK_SUBBLOCKS (data.block)
149     = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
150
151   clear_block_marks (data.block);
152   return 0;
153 }
154
155 struct tree_opt_pass pass_lower_cf = 
156 {
157   "lower",                              /* name */
158   NULL,                                 /* gate */
159   lower_function_body,                  /* execute */
160   NULL,                                 /* sub */
161   NULL,                                 /* next */
162   0,                                    /* static_pass_number */
163   0,                                    /* tv_id */
164   PROP_gimple_any,                      /* properties_required */
165   PROP_gimple_lcf,                      /* properties_provided */
166   0,                                    /* properties_destroyed */
167   0,                                    /* todo_flags_start */
168   TODO_dump_func,                       /* todo_flags_finish */
169   0                                     /* letter */
170 };
171
172
173 /* Lower the EXPR.  Unlike gimplification the statements are not relowered
174    when they are changed -- if this has to be done, the lowering routine must
175    do it explicitly.  DATA is passed through the recursion.  */
176
177 static void
178 lower_stmt_body (tree expr, struct lower_data *data)
179 {
180   tree_stmt_iterator tsi;
181
182   for (tsi = tsi_start (expr); !tsi_end_p (tsi); )
183     lower_stmt (&tsi, data);
184 }
185
186
187 /* Lower the OpenMP directive statement pointed by TSI.  DATA is
188    passed through the recursion.  */
189
190 static void
191 lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data)
192 {
193   tree stmt;
194   
195   stmt = tsi_stmt (*tsi);
196
197   lower_stmt_body (OMP_BODY (stmt), data);
198   tsi_link_before (tsi, stmt, TSI_SAME_STMT);
199   tsi_link_before (tsi, OMP_BODY (stmt), TSI_SAME_STMT);
200   OMP_BODY (stmt) = NULL_TREE;
201   tsi_delink (tsi);
202 }
203
204
205 /* Lower statement TSI.  DATA is passed through the recursion.  */
206
207 static void
208 lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
209 {
210   tree stmt = tsi_stmt (*tsi);
211
212   if (EXPR_HAS_LOCATION (stmt) && data)
213     TREE_BLOCK (stmt) = data->block;
214
215   switch (TREE_CODE (stmt))
216     {
217     case BIND_EXPR:
218       lower_bind_expr (tsi, data);
219       return;
220     case COND_EXPR:
221       lower_cond_expr (tsi, data);
222       return;
223     case RETURN_EXPR:
224       lower_return_expr (tsi, data);
225       return;
226
227     case TRY_FINALLY_EXPR:
228     case TRY_CATCH_EXPR:
229       lower_stmt_body (TREE_OPERAND (stmt, 0), data);
230       lower_stmt_body (TREE_OPERAND (stmt, 1), data);
231       break;
232     case CATCH_EXPR:
233       lower_stmt_body (CATCH_BODY (stmt), data);
234       break;
235     case EH_FILTER_EXPR:
236       lower_stmt_body (EH_FILTER_FAILURE (stmt), data);
237       break;
238       
239     case NOP_EXPR:
240     case ASM_EXPR:
241     case GOTO_EXPR:
242     case LABEL_EXPR:
243     case SWITCH_EXPR:
244     case CHANGE_DYNAMIC_TYPE_EXPR:
245     case OMP_FOR:
246     case OMP_SECTIONS:
247     case OMP_SECTIONS_SWITCH:
248     case OMP_SECTION:
249     case OMP_SINGLE:
250     case OMP_MASTER:
251     case OMP_ORDERED:
252     case OMP_CRITICAL:
253     case OMP_RETURN:
254     case OMP_ATOMIC_LOAD:
255     case OMP_ATOMIC_STORE:
256     case OMP_CONTINUE:
257       break;
258
259     case GIMPLE_MODIFY_STMT:
260       if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR)
261         stmt = GIMPLE_STMT_OPERAND (stmt, 1);
262       else
263         break;
264       /* FALLTHRU */
265
266     case CALL_EXPR:
267       {
268         tree decl = get_callee_fndecl (stmt);
269         if (decl
270             && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
271             && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP)
272           {
273             data->calls_builtin_setjmp = true;
274             lower_builtin_setjmp (tsi);
275             return;
276           }
277       }
278       break;
279
280     case OMP_PARALLEL:
281       lower_omp_directive (tsi, data);
282       return;
283
284     default:
285       gcc_unreachable ();
286     }
287
288   tsi_next (tsi);
289 }
290
291 /* Lower a bind_expr TSI.  DATA is passed through the recursion.  */
292
293 static void
294 lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
295 {
296   tree old_block = data->block;
297   tree stmt = tsi_stmt (*tsi);
298   tree new_block = BIND_EXPR_BLOCK (stmt);
299
300   if (new_block)
301     {
302       if (new_block == old_block)
303         {
304           /* The outermost block of the original function may not be the
305              outermost statement chain of the gimplified function.  So we
306              may see the outermost block just inside the function.  */
307           gcc_assert (new_block == DECL_INITIAL (current_function_decl));
308           new_block = NULL;
309         }
310       else
311         {
312           /* We do not expect to handle duplicate blocks.  */
313           gcc_assert (!TREE_ASM_WRITTEN (new_block));
314           TREE_ASM_WRITTEN (new_block) = 1;
315
316           /* Block tree may get clobbered by inlining.  Normally this would
317              be fixed in rest_of_decl_compilation using block notes, but
318              since we are not going to emit them, it is up to us.  */
319           BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block);
320           BLOCK_SUBBLOCKS (old_block) = new_block;
321           BLOCK_SUBBLOCKS (new_block) = NULL_TREE;
322           BLOCK_SUPERCONTEXT (new_block) = old_block;
323
324           data->block = new_block;
325         }
326     }
327
328   record_vars (BIND_EXPR_VARS (stmt));
329   lower_stmt_body (BIND_EXPR_BODY (stmt), data);
330
331   if (new_block)
332     {
333       gcc_assert (data->block == new_block);
334
335       BLOCK_SUBBLOCKS (new_block)
336         = blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
337       data->block = old_block;
338     }
339
340   /* The BIND_EXPR no longer carries any useful information -- kill it.  */
341   tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT);
342   tsi_delink (tsi);
343 }
344
345 /* Try to determine whether a TRY_CATCH expression can fall through.
346    This is a subroutine of block_may_fallthru.  */
347
348 static bool
349 try_catch_may_fallthru (const_tree stmt)
350 {
351   tree_stmt_iterator i;
352
353   /* If the TRY block can fall through, the whole TRY_CATCH can
354      fall through.  */
355   if (block_may_fallthru (TREE_OPERAND (stmt, 0)))
356     return true;
357
358   i = tsi_start (TREE_OPERAND (stmt, 1));
359   switch (TREE_CODE (tsi_stmt (i)))
360     {
361     case CATCH_EXPR:
362       /* We expect to see a sequence of CATCH_EXPR trees, each with a
363          catch expression and a body.  The whole TRY_CATCH may fall
364          through iff any of the catch bodies falls through.  */
365       for (; !tsi_end_p (i); tsi_next (&i))
366         {
367           if (block_may_fallthru (CATCH_BODY (tsi_stmt (i))))
368             return true;
369         }
370       return false;
371
372     case EH_FILTER_EXPR:
373       /* The exception filter expression only matters if there is an
374          exception.  If the exception does not match EH_FILTER_TYPES,
375          we will execute EH_FILTER_FAILURE, and we will fall through
376          if that falls through.  If the exception does match
377          EH_FILTER_TYPES, the stack unwinder will continue up the
378          stack, so we will not fall through.  We don't know whether we
379          will throw an exception which matches EH_FILTER_TYPES or not,
380          so we just ignore EH_FILTER_TYPES and assume that we might
381          throw an exception which doesn't match.  */
382       return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i)));
383
384     default:
385       /* This case represents statements to be executed when an
386          exception occurs.  Those statements are implicitly followed
387          by a RESX_EXPR to resume execution after the exception.  So
388          in this case the TRY_CATCH never falls through.  */
389       return false;
390     }
391 }
392
393 /* Try to determine if we can fall out of the bottom of BLOCK.  This guess
394    need not be 100% accurate; simply be conservative and return true if we
395    don't know.  This is used only to avoid stupidly generating extra code.
396    If we're wrong, we'll just delete the extra code later.  */
397
398 bool
399 block_may_fallthru (const_tree block)
400 {
401   /* This CONST_CAST is okay because expr_last returns it's argument
402      unmodified and we assign it to a const_tree.  */
403   const_tree stmt = expr_last (CONST_CAST_TREE(block));
404
405   switch (stmt ? TREE_CODE (stmt) : ERROR_MARK)
406     {
407     case GOTO_EXPR:
408     case RETURN_EXPR:
409     case RESX_EXPR:
410       /* Easy cases.  If the last statement of the block implies 
411          control transfer, then we can't fall through.  */
412       return false;
413
414     case SWITCH_EXPR:
415       /* If SWITCH_LABELS is set, this is lowered, and represents a
416          branch to a selected label and hence can not fall through.
417          Otherwise SWITCH_BODY is set, and the switch can fall
418          through.  */
419       return SWITCH_LABELS (stmt) == NULL_TREE;
420
421     case COND_EXPR:
422       if (block_may_fallthru (COND_EXPR_THEN (stmt)))
423         return true;
424       return block_may_fallthru (COND_EXPR_ELSE (stmt));
425
426     case BIND_EXPR:
427       return block_may_fallthru (BIND_EXPR_BODY (stmt));
428
429     case TRY_CATCH_EXPR:
430       return try_catch_may_fallthru (stmt);
431
432     case TRY_FINALLY_EXPR:
433       /* The finally clause is always executed after the try clause,
434          so if it does not fall through, then the try-finally will not
435          fall through.  Otherwise, if the try clause does not fall
436          through, then when the finally clause falls through it will
437          resume execution wherever the try clause was going.  So the
438          whole try-finally will only fall through if both the try
439          clause and the finally clause fall through.  */
440       return (block_may_fallthru (TREE_OPERAND (stmt, 0))
441               && block_may_fallthru (TREE_OPERAND (stmt, 1)));
442
443     case GIMPLE_MODIFY_STMT:
444       if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CALL_EXPR)
445         stmt = GIMPLE_STMT_OPERAND (stmt, 1);
446       else
447         return true;
448       /* FALLTHRU */
449
450     case CALL_EXPR:
451       /* Functions that do not return do not fall through.  */
452       return (call_expr_flags (stmt) & ECF_NORETURN) == 0;
453     
454     case CLEANUP_POINT_EXPR:
455       return block_may_fallthru (TREE_OPERAND (stmt, 0));
456
457     default:
458       return true;
459     }
460 }
461
462 /* Lower a cond_expr TSI.  DATA is passed through the recursion.  */
463
464 static void
465 lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
466 {
467   tree stmt = tsi_stmt (*tsi);
468   bool then_is_goto, else_is_goto;
469   tree then_branch, else_branch;
470   tree then_goto, else_goto;
471   
472   then_branch = COND_EXPR_THEN (stmt);
473   else_branch = COND_EXPR_ELSE (stmt);
474
475   lower_stmt_body (then_branch, data);
476   lower_stmt_body (else_branch, data);
477
478   then_goto = expr_only (then_branch);
479   then_is_goto = then_goto && simple_goto_p (then_goto);
480
481   else_goto = expr_only (else_branch);
482   else_is_goto = else_goto && simple_goto_p (else_goto);
483
484   if (!then_is_goto || !else_is_goto)
485     {
486       tree then_label, else_label, end_label, t;
487
488       then_label = NULL_TREE;
489       else_label = NULL_TREE;
490       end_label = NULL_TREE;
491  
492       /* Replace the cond_expr with explicit gotos.  */
493       if (!then_is_goto)
494         {
495           t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
496           if (TREE_SIDE_EFFECTS (then_branch))
497             then_label = t;
498           else
499             end_label = t;
500           then_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
501         }
502
503       if (!else_is_goto)
504         {
505           t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
506           if (TREE_SIDE_EFFECTS (else_branch))
507             else_label = t;
508           else
509             {
510               /* Both THEN and ELSE can be no-ops if one or both contained an
511                  empty BIND_EXPR that was associated with the toplevel block
512                  of an inlined function.  In that case remove_useless_stmts
513                  can't have cleaned things up for us; kill the whole 
514                  conditional now.  */
515               if (end_label)
516                 {
517                   tsi_delink (tsi);
518                   return;
519                 }
520               else
521                 end_label = t;
522             }
523           else_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
524         }
525
526       if (then_label)
527         {
528           bool may_fallthru = block_may_fallthru (then_branch);
529
530           tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING);
531           tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING);
532   
533           if (else_label && may_fallthru)
534             {
535               end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
536               t = build_and_jump (&LABEL_EXPR_LABEL (end_label));
537               tsi_link_after (tsi, t, TSI_CONTINUE_LINKING);
538             }
539         }
540   
541       if (else_label)
542         {
543           tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING);
544           tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING);
545         }
546
547       if (end_label)
548         tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING);
549     }
550
551   COND_EXPR_THEN (stmt) = then_goto;
552   COND_EXPR_ELSE (stmt) = else_goto;
553
554   tsi_next (tsi);
555 }
556
557 /* Lower a return_expr TSI.  DATA is passed through the recursion.  */
558
559 static void
560 lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
561 {
562   tree stmt = tsi_stmt (*tsi);
563   tree value, t, label;
564
565   /* Extract the value being returned.  */
566   value = TREE_OPERAND (stmt, 0);
567   if (value && TREE_CODE (value) == GIMPLE_MODIFY_STMT)
568     value = GIMPLE_STMT_OPERAND (value, 1);
569
570   /* Match this up with an existing return statement that's been created.  */
571   for (t = data->return_statements; t ; t = TREE_CHAIN (t))
572     {
573       tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
574       if (tvalue && TREE_CODE (tvalue) == GIMPLE_MODIFY_STMT)
575         tvalue = GIMPLE_STMT_OPERAND (tvalue, 1);
576
577       if (value == tvalue)
578         {
579           label = TREE_PURPOSE (t);
580           goto found;
581         }
582     }
583
584   /* Not found.  Create a new label and record the return statement.  */
585   label = create_artificial_label ();
586   data->return_statements = tree_cons (label, stmt, data->return_statements);
587
588   /* Generate a goto statement and remove the return statement.  */
589  found:
590   t = build1 (GOTO_EXPR, void_type_node, label);
591   SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
592   tsi_link_before (tsi, t, TSI_SAME_STMT);
593   tsi_delink (tsi);
594 }
595
596 /* Lower a __builtin_setjmp TSI.
597
598    __builtin_setjmp is passed a pointer to an array of five words (not
599    all will be used on all machines).  It operates similarly to the C
600    library function of the same name, but is more efficient.
601
602    It is lowered into 3 other builtins, namely __builtin_setjmp_setup,
603    __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with
604    __builtin_setjmp_dispatcher shared among all the instances; that's
605    why it is only emitted at the end by lower_function_body.
606
607    After full lowering, the body of the function should look like:
608
609     {
610       void * setjmpvar.0;
611       int D.1844;
612       int D.2844;
613
614       [...]
615
616       __builtin_setjmp_setup (&buf, &<D1847>);
617       D.1844 = 0;
618       goto <D1846>;
619       <D1847>:;
620       __builtin_setjmp_receiver (&<D1847>);
621       D.1844 = 1;
622       <D1846>:;
623       if (D.1844 == 0) goto <D1848>; else goto <D1849>;
624
625       [...]
626
627       __builtin_setjmp_setup (&buf, &<D2847>);
628       D.2844 = 0;
629       goto <D2846>;
630       <D2847>:;
631       __builtin_setjmp_receiver (&<D2847>);
632       D.2844 = 1;
633       <D2846>:;
634       if (D.2844 == 0) goto <D2848>; else goto <D2849>;
635
636       [...]
637
638       <D3850>:;
639       return;
640       <D3853>: [non-local];
641       setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>);
642       goto setjmpvar.0;
643     }
644
645    The dispatcher block will be both the unique destination of all the
646    abnormal call edges and the unique source of all the abnormal edges
647    to the receivers, thus keeping the complexity explosion localized.  */
648
649 static void
650 lower_builtin_setjmp (tree_stmt_iterator *tsi)
651 {
652   tree stmt = tsi_stmt (*tsi);
653   tree cont_label = create_artificial_label ();
654   tree next_label = create_artificial_label ();
655   tree dest, t, arg;
656
657   /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
658      passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
659   FORCED_LABEL (next_label) = 1;
660
661   if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
662     {
663       dest = GIMPLE_STMT_OPERAND (stmt, 0);
664       stmt = GIMPLE_STMT_OPERAND (stmt, 1);
665     }
666   else
667     dest = NULL_TREE;
668
669   /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert.  */
670   arg = build_addr (next_label, current_function_decl);
671   t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP];
672   t = build_call_expr (t, 2, CALL_EXPR_ARG (stmt, 0), arg);
673   SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
674   tsi_link_before (tsi, t, TSI_SAME_STMT);
675
676   /* Build 'DEST = 0' and insert.  */
677   if (dest)
678     {
679       t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (dest),
680                                                         integer_zero_node));
681       SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
682       tsi_link_before (tsi, t, TSI_SAME_STMT);
683     }
684
685   /* Build 'goto CONT_LABEL' and insert.  */
686   t = build1 (GOTO_EXPR, void_type_node, cont_label);
687   tsi_link_before (tsi, t, TSI_SAME_STMT);
688
689   /* Build 'NEXT_LABEL:' and insert.  */
690   t = build1 (LABEL_EXPR, void_type_node, next_label);
691   tsi_link_before (tsi, t, TSI_SAME_STMT);
692
693   /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert.  */
694   arg = build_addr (next_label, current_function_decl);
695   t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER];
696   t = build_call_expr (t, 1, arg);
697   SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
698   tsi_link_before (tsi, t, TSI_SAME_STMT);
699
700   /* Build 'DEST = 1' and insert.  */
701   if (dest)
702     {
703       t = build_gimple_modify_stmt (dest, fold_convert (TREE_TYPE (dest),
704                                                         integer_one_node));
705       SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
706       tsi_link_before (tsi, t, TSI_SAME_STMT);
707     }
708
709   /* Build 'CONT_LABEL:' and insert.  */
710   t = build1 (LABEL_EXPR, void_type_node, cont_label);
711   tsi_link_before (tsi, t, TSI_SAME_STMT);
712
713   /* Remove the call to __builtin_setjmp.  */
714   tsi_delink (tsi);
715 }
716 \f
717
718 /* Record the variables in VARS into function FN.  */
719
720 void
721 record_vars_into (tree vars, tree fn)
722 {
723   if (fn != current_function_decl)
724     push_cfun (DECL_STRUCT_FUNCTION (fn));
725
726   for (; vars; vars = TREE_CHAIN (vars))
727     {
728       tree var = vars;
729
730       /* BIND_EXPRs contains also function/type/constant declarations
731          we don't need to care about.  */
732       if (TREE_CODE (var) != VAR_DECL)
733         continue;
734
735       /* Nothing to do in this case.  */
736       if (DECL_EXTERNAL (var))
737         continue;
738
739       /* Record the variable.  */
740       cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
741                                              cfun->unexpanded_var_list);
742     }
743
744   if (fn != current_function_decl)
745     pop_cfun ();
746 }
747
748
749 /* Record the variables in VARS into current_function_decl.  */
750
751 void
752 record_vars (tree vars)
753 {
754   record_vars_into (vars, current_function_decl);
755 }
756
757
758 /* Mark BLOCK used if it has a used variable in it, then recurse over its
759    subblocks.  */
760
761 static void
762 mark_blocks_with_used_vars (tree block)
763 {
764   tree var;
765   tree subblock;
766
767   if (!TREE_USED (block))
768     {
769       for (var = BLOCK_VARS (block);
770            var;
771            var = TREE_CHAIN (var))
772         {
773           if (TREE_USED (var))
774             {
775               TREE_USED (block) = true;
776               break;
777             }
778         }
779     }
780   for (subblock = BLOCK_SUBBLOCKS (block);
781        subblock;
782        subblock = BLOCK_CHAIN (subblock))
783     mark_blocks_with_used_vars (subblock);
784 }
785
786 /* Mark the used attribute on blocks correctly.  */
787   
788 static unsigned int
789 mark_used_blocks (void)
790 {  
791   mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl));
792   return 0;
793 }
794
795
796 struct tree_opt_pass pass_mark_used_blocks = 
797 {
798   "blocks",                             /* name */
799   NULL,                                 /* gate */
800   mark_used_blocks,                     /* execute */
801   NULL,                                 /* sub */
802   NULL,                                 /* next */
803   0,                                    /* static_pass_number */
804   0,                                    /* tv_id */
805   0,                                    /* properties_required */
806   0,                                    /* properties_provided */
807   0,                                    /* properties_destroyed */
808   0,                                    /* todo_flags_start */
809   TODO_dump_func,                       /* todo_flags_finish */
810   0                                     /* letter */
811 };