OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [gimple-low.c] - Blame information for rev 868

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.