Newer
Older
/* Tree lowering pass. This pass converts the GENERIC functions-as-trees
tree representation into the GIMPLE form.
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "errors.h"
#include "varray.h"
#include "tree-inline.h"
#include "diagnostic.h"
#include "langhooks.h"
#include "langhooks-def.h"
#include "tree-flow.h"
#include "cgraph.h"
#include "timevar.h"
#include "except.h"
#include "hashtab.h"
#include "flags.h"
#include "real.h"
#include "function.h"
#include "output.h"
#include "expr.h"
#include "ggc.h"
static struct gimplify_ctx
{
tree current_bind_expr;
bool save_stack;
tree temps;
tree conditional_cleanups;
int conditions;
tree exit_label;
Richard Henderson
committed
tree return_temp;
varray_type case_labels;
/* The formal temporary table. Should this be persistent? */
htab_t temp_htab;
} *gimplify_ctxp;
/* Formal (expression) temporary table handling: Multiple occurrences of
the same scalar expression are evaluated into the same temporary. */
typedef struct gimple_temp_hash_elt
{
tree val; /* Key */
tree temp; /* Value */
} elt_t;
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* Forward declarations. */
static hashval_t gimple_tree_hash (const void *);
static int gimple_tree_eq (const void *, const void *);
static bool gimple_conditional_context (void);
static void gimple_push_condition (void);
static void gimple_pop_condition (tree *);
static void append_to_statement_list_1 (tree, tree *, bool);
static inline void remove_suffix (char *, int);
static inline tree create_tmp_from_val (tree);
static tree lookup_tmp_var (tree, bool);
static tree internal_get_tmp_var (tree, tree *, tree *, bool);
static bool should_carry_locus_p (tree);
static tree mostly_copy_tree_r (tree *, int *, void *);
static tree mark_decls_volatile_r (tree *, int *, void *);
static tree copy_if_shared_r (tree *, int *, void *);
static tree unmark_visited_r (tree *, int *, void *);
static void unshare_body (tree *, tree);
static void unvisit_body (tree *, tree);
static void build_stack_save_restore (tree *, tree *);
static enum gimplify_status gimplify_bind_expr (tree *, tree, tree *);
static enum gimplify_status gimplify_return_expr (tree, tree *);
static enum gimplify_status gimplify_loop_expr (tree *, tree *);
static int compare_case_labels (const void *, const void *);
static enum gimplify_status gimplify_switch_expr (tree *, tree *);
static enum gimplify_status gimplify_case_label_expr (tree *);
static enum gimplify_status gimplify_labeled_block_expr (tree *);
static enum gimplify_status gimplify_exit_block_expr (tree *);
static enum gimplify_status gimplify_exit_expr (tree *);
static enum gimplify_status gimplify_init_constructor (tree *, tree *, tree *,
bool);
static void canonicalize_component_ref (tree *);
static void canonicalize_addr_expr (tree *);
static enum gimplify_status gimplify_conversion (tree *);
static enum gimplify_status gimplify_minimax_expr (tree *, tree *, tree *);
static enum gimplify_status gimplify_array_ref_to_plus (tree *, tree *,
tree *);
static tree build_addr_expr_with_type (tree, tree);
static tree build_addr_expr (tree);
static enum gimplify_status gimplify_compound_lval (tree *, tree *, tree *,
bool);
static enum gimplify_status gimplify_self_mod_expr (tree *, tree *, tree *,
bool);
static enum gimplify_status gimplify_call_expr (tree *, tree *,
bool (*) (tree));
static tree shortcut_cond_r (tree, tree *, tree *);
static tree shortcut_cond_expr (tree);
static tree gimple_boolify (tree);
static enum gimplify_status gimplify_cond_expr (tree *, tree *, tree);
static enum gimplify_status gimplify_modify_expr (tree *, tree *, tree *,
bool);
static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
tree *, tree *, bool);
static enum gimplify_status gimplify_variable_sized_compare (tree *);
static enum gimplify_status gimplify_boolean_expr (tree *);
static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
static enum gimplify_status gimplify_statement_list (tree *);
static enum gimplify_status gimplify_save_expr (tree *, tree *, tree *);
static enum gimplify_status gimplify_addr_expr (tree *, tree *, tree *);
static enum gimplify_status gimplify_asm_expr (tree *, tree *, tree *);
static enum gimplify_status gimplify_cleanup_point_expr (tree *, tree *);
static void gimple_push_cleanup (tree, tree, tree *);
static enum gimplify_status gimplify_target_expr (tree *, tree *, tree *);
#ifdef ENABLE_CHECKING
static bool cpt_same_type (tree, tree);
static tree check_pointer_types_r (tree *, int *, void *);
#endif
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
/* Return a hash value for a formal temporary table entry. */
static hashval_t
gimple_tree_hash (const void *p)
{
tree t = ((const elt_t *)p)->val;
return iterative_hash_expr (t, 0);
}
/* Compare two formal temporary table entries. */
static int
gimple_tree_eq (const void *p1, const void *p2)
{
tree t1 = ((const elt_t *)p1)->val;
tree t2 = ((const elt_t *)p2)->val;
enum tree_code code = TREE_CODE (t1);
if (TREE_CODE (t2) != code
|| TREE_TYPE (t1) != TREE_TYPE (t2))
return 0;
if (!operand_equal_p (t1, t2, 0))
return 0;
/* Only allow them to compare equal if they also hash equal; otherwise
results are nondeterminate, and we fail bootstrap comparison. */
if (gimple_tree_hash (p1) != gimple_tree_hash (p2))
abort ();
return 1;
}
/* Set up a context for the gimplifier. */
void
push_gimplify_context (void)
{
if (gimplify_ctxp)
abort ();
gimplify_ctxp
= (struct gimplify_ctx *) xcalloc (1, sizeof (struct gimplify_ctx));
gimplify_ctxp->temp_htab
= htab_create (1000, gimple_tree_hash, gimple_tree_eq, free);
}
/* Tear down a context for the gimplifier. If BODY is non-null, then
put the temporaries into the outer BIND_EXPR. Otherwise, put them
in the unexpanded_var_list. */
void
pop_gimplify_context (tree body)
{
if (!gimplify_ctxp || gimplify_ctxp->current_bind_expr)
abort ();
if (body)
declare_tmp_vars (gimplify_ctxp->temps, body);
else
record_vars (gimplify_ctxp->temps);
#if 0
if (!quiet_flag)
fprintf (stderr, " collisions: %f ",
htab_collisions (gimplify_ctxp->temp_htab));
#endif
htab_delete (gimplify_ctxp->temp_htab);
free (gimplify_ctxp);
gimplify_ctxp = NULL;
}
void
gimple_push_bind_expr (tree bind)
{
TREE_CHAIN (bind) = gimplify_ctxp->current_bind_expr;
gimplify_ctxp->current_bind_expr = bind;
}
void
gimple_pop_bind_expr (void)
{
gimplify_ctxp->current_bind_expr
= TREE_CHAIN (gimplify_ctxp->current_bind_expr);
}
tree
gimple_current_bind_expr (void)
{
return gimplify_ctxp->current_bind_expr;
}
/* Returns true iff there is a COND_EXPR between us and the innermost
CLEANUP_POINT_EXPR. This info is used by gimple_push_cleanup. */
static bool
gimple_conditional_context (void)
{
return gimplify_ctxp->conditions > 0;
}
/* Note that we've entered a COND_EXPR. */
static void
gimple_push_condition (void)
{
++(gimplify_ctxp->conditions);
}
/* Note that we've left a COND_EXPR. If we're back at unconditional scope
now, add any conditional cleanups we've seen to the prequeue. */
static void
gimple_pop_condition (tree *pre_p)
{
int conds = --(gimplify_ctxp->conditions);
if (conds == 0)
{
append_to_statement_list (gimplify_ctxp->conditional_cleanups, pre_p);
gimplify_ctxp->conditional_cleanups = NULL_TREE;
}
else if (conds < 0)
abort ();
}
/* A subroutine of append_to_statement_list{,_force}. */
static void
append_to_statement_list_1 (tree t, tree *list_p, bool side_effects)
{
tree list = *list_p;
tree_stmt_iterator i;
Jason Merrill
committed
if (!side_effects)
return;
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
if (!list)
{
if (t && TREE_CODE (t) == STATEMENT_LIST)
{
*list_p = t;
return;
}
*list_p = list = alloc_stmt_list ();
}
i = tsi_last (list);
tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
}
/* Add T to the end of the list container pointed by LIST_P.
If T is an expression with no effects, it is ignored. */
void
append_to_statement_list (tree t, tree *list_p)
{
append_to_statement_list_1 (t, list_p, t ? TREE_SIDE_EFFECTS (t) : false);
}
/* Similar, but the statement is always added, regardless of side effects. */
void
append_to_statement_list_force (tree t, tree *list_p)
{
append_to_statement_list_1 (t, list_p, t != NULL);
}
/* Both gimplify the statement T and append it to LIST_P. */
void
gimplify_and_add (tree t, tree *list_p)
{
gimplify_stmt (&t);
append_to_statement_list (t, list_p);
}
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/* Strip off a legitimate source ending from the input string NAME of
length LEN. Rather than having to know the names used by all of
our front ends, we strip off an ending of a period followed by
up to five characters. (Java uses ".class".) */
static inline void
remove_suffix (char *name, int len)
{
int i;
for (i = 2; i < 8 && len > i; i++)
{
if (name[len - i] == '.')
{
name[len - i] = '\0';
break;
}
}
}
/* Create a nameless artificial label and put it in the current function
context. Returns the newly created label. */
tree
create_artificial_label (void)
{
tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
DECL_ARTIFICIAL (lab) = 1;
DECL_CONTEXT (lab) = current_function_decl;
return lab;
}
/* Create a new temporary name with PREFIX. Returns an identifier. */
static GTY(()) unsigned int tmp_var_id_num;
Richard Henderson
committed
tree
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
create_tmp_var_name (const char *prefix)
{
char *tmp_name;
if (prefix)
{
char *preftmp = ASTRDUP (prefix);
remove_suffix (preftmp, strlen (preftmp));
prefix = preftmp;
}
ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix ? prefix : "T", tmp_var_id_num++);
return get_identifier (tmp_name);
}
/* Create a new temporary variable declaration of type TYPE.
Does NOT push it into the current binding. */
tree
create_tmp_var_raw (tree type, const char *prefix)
{
tree tmp_var;
tree new_type;
/* Make the type of the variable writable. */
new_type = build_type_variant (type, 0, 0);
TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
tmp_var = build_decl (VAR_DECL, create_tmp_var_name (prefix), type);
/* The variable was declared by the compiler. */
DECL_ARTIFICIAL (tmp_var) = 1;
/* And we don't want debug info for it. */
DECL_IGNORED_P (tmp_var) = 1;
/* Make the variable writable. */
TREE_READONLY (tmp_var) = 0;
DECL_EXTERNAL (tmp_var) = 0;
TREE_STATIC (tmp_var) = 0;
TREE_USED (tmp_var) = 1;
return tmp_var;
}
/* Create a new temporary variable declaration of type TYPE. DOES push the
variable into the current binding. Further, assume that this is called
only from gimplification or optimization, at which point the creation of
certain types are bugs. */
tree
create_tmp_var (tree type, const char *prefix)
{
tree tmp_var;
#if defined ENABLE_CHECKING
/* We don't allow types that are addressable (meaning we can't make copies),
incomplete, or of variable size. */
if (TREE_ADDRESSABLE (type)
|| !COMPLETE_TYPE_P (type)
|| TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
abort ();
#endif
tmp_var = create_tmp_var_raw (type, prefix);
gimple_add_tmp_var (tmp_var);
return tmp_var;
}
/* Given a tree, try to return a useful variable name that we can use
to prefix a temporary that is being assigned the value of the tree.
I.E. given <temp> = &A, return A. */
const char *
get_name (tree t)
{
tree stripped_decl;
stripped_decl = t;
STRIP_NOPS (stripped_decl);
if (DECL_P (stripped_decl) && DECL_NAME (stripped_decl))
return IDENTIFIER_POINTER (DECL_NAME (stripped_decl));
else
{
switch (TREE_CODE (stripped_decl))
{
case ADDR_EXPR:
return get_name (TREE_OPERAND (stripped_decl, 0));
break;
default:
return NULL;
}
}
}
/* Create a temporary with a name derived from VAL. Subroutine of
lookup_tmp_var; nobody else should call this function. */
static inline tree
create_tmp_from_val (tree val)
{
return create_tmp_var (TREE_TYPE (val), get_name (val));
}
/* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse
an existing expression temporary. */
static tree
lookup_tmp_var (tree val, bool is_formal)
{
if (!is_formal || TREE_SIDE_EFFECTS (val))
return create_tmp_from_val (val);
else
{
elt_t elt, *elt_p;
void **slot;
elt.val = val;
slot = htab_find_slot (gimplify_ctxp->temp_htab, (void *)&elt, INSERT);
if (*slot == NULL)
{
elt_p = xmalloc (sizeof (*elt_p));
elt_p->val = val;
elt_p->temp = create_tmp_from_val (val);
*slot = (void *)elt_p;
}
else
elt_p = (elt_t *) *slot;
return elt_p->temp;
}
}
/* Returns a formal temporary variable initialized with VAL. PRE_P is as
in gimplify_expr. Only use this function if:
1) The value of the unfactored expression represented by VAL will not
change between the initialization and use of the temporary, and
2) The temporary will not be otherwise modified.
For instance, #1 means that this is inappropriate for SAVE_EXPR temps,
and #2 means it is inappropriate for && temps.
For other cases, use get_initialized_tmp_var instead. */
static tree
internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
{
tree t, mod;
char class;
gimplify_expr (&val, pre_p, post_p, is_gimple_rhs, fb_rvalue);
t = lookup_tmp_var (val, is_formal);
mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val);
class = TREE_CODE_CLASS (TREE_CODE (val));
if (EXPR_LOCUS (val))
SET_EXPR_LOCUS (mod, EXPR_LOCUS (val));
else
annotate_with_locus (mod, input_location);
/* gimplify_modify_expr might want to reduce this further. */
gimplify_stmt (&mod);
append_to_statement_list (mod, pre_p);
return t;
}
tree
get_formal_tmp_var (tree val, tree *pre_p)
{
return internal_get_tmp_var (val, pre_p, NULL, true);
}
/* Returns a temporary variable initialized with VAL. PRE_P and POST_P
are as in gimplify_expr. */
tree
get_initialized_tmp_var (tree val, tree *pre_p, tree *post_p)
{
return internal_get_tmp_var (val, pre_p, post_p, false);
}
/* Returns true if T is a GIMPLE temporary variable, false otherwise. */
bool
is_gimple_tmp_var (tree t)
{
/* FIXME this could trigger for other local artificials, too. */
return (TREE_CODE (t) == VAR_DECL && DECL_ARTIFICIAL (t)
&& !TREE_STATIC (t) && !DECL_EXTERNAL (t));
}
/* Declares all the variables in VARS in SCOPE. Returns the last
DECL_STMT emitted. */
void
declare_tmp_vars (tree vars, tree scope)
{
tree last = vars;
if (last)
{
tree temps;
/* C99 mode puts the default 'return 0;' for main() outside the outer
braces. So drill down until we find an actual scope. */
while (TREE_CODE (scope) == COMPOUND_EXPR)
scope = TREE_OPERAND (scope, 0);
if (TREE_CODE (scope) != BIND_EXPR)
abort ();
temps = nreverse (last);
TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
BIND_EXPR_VARS (scope) = temps;
/* We don't add the temps to the block for this BIND_EXPR, as we're
not interested in debugging info for them. */
}
}
void
gimple_add_tmp_var (tree tmp)
{
if (TREE_CHAIN (tmp) || tmp->decl.seen_in_bind_expr)
abort ();
DECL_CONTEXT (tmp) = current_function_decl;
tmp->decl.seen_in_bind_expr = 1;
if (gimplify_ctxp)
{
TREE_CHAIN (tmp) = gimplify_ctxp->temps;
gimplify_ctxp->temps = tmp;
}
else if (cfun)
record_vars (tmp);
else
declare_tmp_vars (tmp, DECL_SAVED_TREE (current_function_decl));
}
/* Determines whether to assign a locus to the statement STMT. */
static bool
should_carry_locus_p (tree stmt)
{
/* Don't emit a line note for a label. We particularly don't want to
emit one for the break label, since it doesn't actually correspond
to the beginning of the loop/switch. */
if (TREE_CODE (stmt) == LABEL_EXPR)
return false;
/* Do not annotate empty statements, since it confuses gcov. */
if (!TREE_SIDE_EFFECTS (stmt))
return false;
return true;
}
static void
annotate_one_with_locus (tree t, location_t locus)
{
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t)))
&& ! EXPR_HAS_LOCATION (t)
&& should_carry_locus_p (t))
annotate_with_locus (t, locus);
}
void
annotate_all_with_locus (tree *stmt_p, location_t locus)
{
tree_stmt_iterator i;
if (!*stmt_p)
return;
for (i = tsi_start (*stmt_p); !tsi_end_p (i); tsi_next (&i))
{
tree t = tsi_stmt (i);
#ifdef ENABLE_CHECKING
/* Assuming we've already been gimplified, we shouldn't
see nested chaining constructs anymore. */
if (TREE_CODE (t) == STATEMENT_LIST
|| TREE_CODE (t) == COMPOUND_EXPR)
abort ();
#endif
annotate_one_with_locus (t, locus);
}
}
/* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes.
These nodes model computations that should only be done once. If we
were to unshare something like SAVE_EXPR(i++), the gimplification
process would create wrong code. */
static tree
mostly_copy_tree_r (tree *tp, int *walk_subtrees, void *data)
{
enum tree_code code = TREE_CODE (*tp);
/* Don't unshare types, decls, constants and SAVE_EXPR nodes. */
if (TREE_CODE_CLASS (code) == 't'
|| TREE_CODE_CLASS (code) == 'd'
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
|| TREE_CODE_CLASS (code) == 'c'
|| code == SAVE_EXPR || code == TARGET_EXPR
/* We can't do anything sensible with a BLOCK used as an expression,
but we also can't abort when we see it because of non-expression
uses. So just avert our eyes and cross our fingers. Silly Java. */
|| code == BLOCK)
*walk_subtrees = 0;
else if (code == BIND_EXPR)
abort ();
else
copy_tree_r (tp, walk_subtrees, data);
return NULL_TREE;
}
/* Mark all the _DECL nodes under *TP as volatile. FIXME: This must die
after VA_ARG_EXPRs are properly lowered. */
static tree
mark_decls_volatile_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
if (SSA_VAR_P (*tp))
TREE_THIS_VOLATILE (*tp) = 1;
return NULL_TREE;
}
/* Callback for walk_tree to unshare most of the shared trees rooted at
*TP. If *TP has been visited already (i.e., TREE_VISITED (*TP) == 1),
then *TP is deep copied by calling copy_tree_r.
This unshares the same trees as copy_tree_r with the exception of
SAVE_EXPR nodes. These nodes model computations that should only be
done once. If we were to unshare something like SAVE_EXPR(i++), the
gimplification process would create wrong code. */
static tree
copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
tree t = *tp;
enum tree_code code = TREE_CODE (t);
/* Skip types, decls, and constants. But we do want to look at their
types and the bounds of types. Mark them as visited so we properly
unmark their subtrees on the unmark pass. If we've already seen them,
don't look down further. */
if (TREE_CODE_CLASS (code) == 't'
|| TREE_CODE_CLASS (code) == 'd'
|| TREE_CODE_CLASS (code) == 'c')
{
if (TREE_VISITED (t))
*walk_subtrees = 0;
else
TREE_VISITED (t) = 1;
}
/* Special-case BIND_EXPR. We should never be copying these, therefore
we can omit examining BIND_EXPR_VARS. Which also avoids problems with
double processing of the DECL_INITIAL, which could be seen via both
the BIND_EXPR_VARS and a DECL_STMT. */
else if (code == BIND_EXPR)
{
if (TREE_VISITED (t))
abort ();
TREE_VISITED (t) = 1;
*walk_subtrees = 0;
walk_tree (&BIND_EXPR_BODY (t), copy_if_shared_r, NULL, NULL);
}
/* If this node has been visited already, unshare it and don't look
any deeper. */
else if (TREE_VISITED (t))
{
walk_tree (tp, mostly_copy_tree_r, NULL, NULL);
*walk_subtrees = 0;
}
/* Otherwise, mark the tree as visited and keep looking. */
Alexandre Oliva
committed
{
TREE_VISITED (t) = 1;
if (TREE_CODE (*tp) == VA_ARG_EXPR
&& targetm.calls.gimplify_va_arg_expr == NULL)
Alexandre Oliva
committed
{
/* Mark any _DECL inside the operand as volatile to avoid
the optimizers messing around with it. We have to do this
early, otherwise we might mark a variable as volatile
after we gimplify other statements that use the variable
assuming it's not volatile. */
/* FIXME once most targets define the above hook, this should
go away (perhaps along with the #include "target.h"). */
Alexandre Oliva
committed
walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r,
NULL, NULL);
}
}
return NULL_TREE;
}
static tree
unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
if (TREE_VISITED (*tp))
TREE_VISITED (*tp) = 0;
else
*walk_subtrees = 0;
return NULL_TREE;
}
/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
bodies of any nested functions. */
static void
unshare_body (tree *body_p, tree fndecl)
{
struct cgraph_node *cgn = cgraph_node (fndecl);
walk_tree (body_p, copy_if_shared_r, NULL, NULL);
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
}
/* Likewise, but mark all trees as not visited. */
static void
unvisit_body (tree *body_p, tree fndecl)
{
struct cgraph_node *cgn = cgraph_node (fndecl);
walk_tree (body_p, unmark_visited_r, NULL, NULL);
for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
}
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
/* Unshare T and all the trees reached from T via TREE_CHAIN. */
void
unshare_all_trees (tree t)
{
walk_tree (&t, copy_if_shared_r, NULL, NULL);
walk_tree (&t, unmark_visited_r, NULL, NULL);
}
/* Unconditionally make an unshared copy of EXPR. This is used when using
stored expressions which span multiple functions, such as BINFO_VTABLE,
as the normal unsharing process can't tell that they're shared. */
tree
unshare_expr (tree expr)
{
walk_tree (&expr, mostly_copy_tree_r, NULL, NULL);
return expr;
}
/* A terser interface for building a representation of a exception
specification. */
tree
gimple_build_eh_filter (tree body, tree allowed, tree failure)
{
tree t;
/* FIXME should the allowed types go in TREE_TYPE? */
t = build (EH_FILTER_EXPR, void_type_node, allowed, NULL_TREE);
append_to_statement_list (failure, &EH_FILTER_FAILURE (t));
t = build (TRY_CATCH_EXPR, void_type_node, NULL_TREE, t);
append_to_statement_list (body, &TREE_OPERAND (t, 0));
return t;
}
/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
contain statements and have a value. Assign its value to a temporary
and give it void_type_node. Returns the temporary, or NULL_TREE if
WRAPPER was already void. */
tree
voidify_wrapper_expr (tree wrapper, tree temp)
{
if (!VOID_TYPE_P (TREE_TYPE (wrapper)))
{
tree *p, sub = wrapper;
/* Set p to point to the body of the wrapper. */
switch (TREE_CODE (sub))
{
case BIND_EXPR:
/* For a BIND_EXPR, the body is operand 1. */
p = &BIND_EXPR_BODY (sub);
p = &TREE_OPERAND (sub, 0);
break;
}
/* Advance to the last statement. Set all container types to void. */
if (TREE_CODE (*p) == STATEMENT_LIST)
{
tree_stmt_iterator i = tsi_last (*p);
p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
}
else
{
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
{
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
}
}
if (p == NULL || IS_EMPTY_STMT (*p))
;
/* Look through exception handling. */
else if (TREE_CODE (*p) == TRY_FINALLY_EXPR
|| TREE_CODE (*p) == TRY_CATCH_EXPR)
sub = *p;
goto restart;
/* The C++ frontend already did this for us. */
else if (TREE_CODE (*p) == INIT_EXPR)
temp = TREE_OPERAND (*p, 0);
/* If we're returning a dereference, move the dereference
outside the wrapper. */
else if (TREE_CODE (*p) == INDIRECT_REF)
{
tree ptr = TREE_OPERAND (*p, 0);
temp = create_tmp_var (TREE_TYPE (ptr), "retval");
*p = build (MODIFY_EXPR, TREE_TYPE (ptr), temp, ptr);
temp = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (temp)), temp);
/* If this is a BIND_EXPR for a const inline function, it might not
have TREE_SIDE_EFFECTS set. That is no longer accurate. */
TREE_SIDE_EFFECTS (wrapper) = 1;
}
else
{
if (!temp)
temp = create_tmp_var (TREE_TYPE (wrapper), "retval");
*p = build (MODIFY_EXPR, TREE_TYPE (temp), temp, *p);
TREE_SIDE_EFFECTS (wrapper) = 1;
}
TREE_TYPE (wrapper) = void_type_node;
return temp;
}
return NULL_TREE;
}
/* Prepare calls to builtins to SAVE and RESTORE the stack as well as
a temporary through which they communicate. */
static void
build_stack_save_restore (tree *save, tree *restore)
{
tree save_call, tmp_var;
save_call =
build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_SAVE],
NULL_TREE);
tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
*save = build (MODIFY_EXPR, ptr_type_node, tmp_var, save_call);
*restore =
build_function_call_expr (implicit_built_in_decls[BUILT_IN_STACK_RESTORE],
tree_cons (NULL_TREE, tmp_var, NULL_TREE));
}
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
static enum gimplify_status
gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
{
tree bind_expr = *expr_p;
bool old_save_stack = gimplify_ctxp->save_stack;
tree t;
temp = voidify_wrapper_expr (bind_expr, temp);
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
/* Mark variables seen in this bind expr. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
t->decl.seen_in_bind_expr = 1;
gimple_push_bind_expr (bind_expr);
gimplify_ctxp->save_stack = false;
gimplify_to_stmt_list (&BIND_EXPR_BODY (bind_expr));
if (gimplify_ctxp->save_stack)
{
tree stack_save, stack_restore;
/* Save stack on entry and restore it on exit. Add a try_finally
block to achieve this. Note that mudflap depends on the
format of the emitted code: see mx_register_decls(). */
build_stack_save_restore (&stack_save, &stack_restore);
t = build (TRY_FINALLY_EXPR, void_type_node,
BIND_EXPR_BODY (bind_expr), NULL_TREE);
append_to_statement_list (stack_restore, &TREE_OPERAND (t, 1));
BIND_EXPR_BODY (bind_expr) = NULL_TREE;
append_to_statement_list (stack_save, &BIND_EXPR_BODY (bind_expr));
append_to_statement_list (t, &BIND_EXPR_BODY (bind_expr));
}
gimplify_ctxp->save_stack = old_save_stack;
gimple_pop_bind_expr ();
if (temp)
{
*expr_p = temp;
append_to_statement_list (bind_expr, pre_p);
return GS_OK;
}
else
return GS_ALL_DONE;
}
/* Gimplify a RETURN_EXPR. If the expression to be returned is not a
GIMPLE value, it is assigned to a new temporary and the statement is
re-written to return the temporary.
PRE_P points to the list where side effects that must happen before
STMT should be stored. */
static enum gimplify_status
gimplify_return_expr (tree stmt, tree *pre_p)
{
tree ret_expr = TREE_OPERAND (stmt, 0);
Richard Henderson
committed
tree result_decl, result;