OSDN Git Service

2004-05-21 Frank Ch. Eigler <fche@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-iterator.c
1 /* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
2    Copyright (C) 2003, 2004 Free Software Foundation, Inc.
3    Contributed by Andrew MacLeod  <amacleod@redhat.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License 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
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "tree-gimple.h"
27 #include "tree-iterator.h"
28 #include "ggc.h"
29
30
31 /* This is a cache of STATEMENT_LIST nodes.  We create and destroy them
32    fairly often during gimplification.  */
33
34 static GTY ((deletable (""))) tree stmt_list_cache;
35
36 tree
37 alloc_stmt_list (void)
38 {
39   tree list = stmt_list_cache;
40   if (list)
41     {
42       stmt_list_cache = TREE_CHAIN (list);
43       TREE_CHAIN (list) = NULL;
44       TREE_SIDE_EFFECTS (list) = 0;
45     }
46   else
47     {
48       list = make_node (STATEMENT_LIST);
49       TREE_TYPE (list) = void_type_node;
50     }
51   return list;
52 }
53
54 void
55 free_stmt_list (tree t)
56 {
57 #ifdef ENABLE_CHECKING
58   if (STATEMENT_LIST_HEAD (t) || STATEMENT_LIST_TAIL (t))
59     abort ();
60 #endif
61   TREE_CHAIN (t) = stmt_list_cache;
62   stmt_list_cache = t;
63 }
64
65 /* Links a statement, or a chain of statements, before the current stmt.  */
66
67 void
68 tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
69 {
70   struct tree_statement_list_node *head, *tail, *cur;
71
72   /* Die on looping.  */
73   if (t == i->container)
74     abort ();
75
76   TREE_SIDE_EFFECTS (i->container) = 1;
77
78   if (TREE_CODE (t) == STATEMENT_LIST)
79     {
80       head = STATEMENT_LIST_HEAD (t);
81       tail = STATEMENT_LIST_TAIL (t);
82       STATEMENT_LIST_HEAD (t) = NULL;
83       STATEMENT_LIST_TAIL (t) = NULL;
84
85       free_stmt_list (t);
86
87       /* Empty statement lists need no work.  */
88       if (!head || !tail)
89         {
90           if (head != tail)
91             abort ();
92           return;
93         }
94     }
95   else
96     {
97       head = ggc_alloc (sizeof (*head));
98       head->prev = NULL;
99       head->next = NULL;
100       head->stmt = t;
101       tail = head;
102     }
103
104   cur = i->ptr;
105
106   /* Link it into the list.  */
107   if (cur)
108     {
109       head->prev = cur->prev;
110       if (head->prev)
111         head->prev->next = head;
112       else
113         STATEMENT_LIST_HEAD (i->container) = head;
114       tail->next = cur;
115       cur->prev = tail;
116     }
117   else
118     {
119       if (STATEMENT_LIST_TAIL (i->container))
120         abort ();
121       STATEMENT_LIST_HEAD (i->container) = head;
122       STATEMENT_LIST_TAIL (i->container) = tail;
123     }
124
125   /* Update the iterator, if requested.  */
126   switch (mode)
127     {
128     case TSI_NEW_STMT:
129     case TSI_CONTINUE_LINKING:
130     case TSI_CHAIN_START:
131       i->ptr = head;
132       break;
133     case TSI_CHAIN_END:
134       i->ptr = tail;
135       break;
136     case TSI_SAME_STMT:
137       if (!cur)
138         abort ();
139       break;
140     }
141 }
142
143 /* Links a statement, or a chain of statements, after the current stmt.  */
144
145 void
146 tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
147 {
148   struct tree_statement_list_node *head, *tail, *cur;
149
150   /* Die on looping.  */
151   if (t == i->container)
152     abort ();
153
154   TREE_SIDE_EFFECTS (i->container) = 1;
155
156   if (TREE_CODE (t) == STATEMENT_LIST)
157     {
158       head = STATEMENT_LIST_HEAD (t);
159       tail = STATEMENT_LIST_TAIL (t);
160       STATEMENT_LIST_HEAD (t) = NULL;
161       STATEMENT_LIST_TAIL (t) = NULL;
162
163       free_stmt_list (t);
164
165       /* Empty statement lists need no work.  */
166       if (!head || !tail)
167         {
168           if (head != tail)
169             abort ();
170           return;
171         }
172     }
173   else
174     {
175       head = ggc_alloc (sizeof (*head));
176       head->prev = NULL;
177       head->next = NULL;
178       head->stmt = t;
179       tail = head;
180     }
181
182   cur = i->ptr;
183
184   /* Link it into the list.  */
185   if (cur)
186     {
187       tail->next = cur->next;
188       if (tail->next)
189         tail->next->prev = tail;
190       else
191         STATEMENT_LIST_TAIL (i->container) = tail;
192       head->prev = cur;
193       cur->next = head;
194     }
195   else
196     {
197       if (STATEMENT_LIST_TAIL (i->container))
198         abort ();
199       STATEMENT_LIST_HEAD (i->container) = head;
200       STATEMENT_LIST_TAIL (i->container) = tail;
201     }
202
203   /* Update the iterator, if requested.  */
204   switch (mode)
205     {
206     case TSI_NEW_STMT:
207     case TSI_CHAIN_START:
208       i->ptr = head;
209       break;
210     case TSI_CONTINUE_LINKING:
211     case TSI_CHAIN_END:
212       i->ptr = tail;
213       break;
214     case TSI_SAME_STMT:
215       if (!cur)
216         abort ();
217       break;
218     }
219 }
220
221 /* Remove a stmt from the tree list.  The iterator is updated to point to
222    the next stmt.  */
223
224 void
225 tsi_delink (tree_stmt_iterator *i)
226 {
227   struct tree_statement_list_node *cur, *next, *prev;
228
229   cur = i->ptr;
230   next = cur->next;
231   prev = cur->prev;
232
233   if (prev)
234     prev->next = next;
235   else
236     STATEMENT_LIST_HEAD (i->container) = next;
237   if (next)
238     next->prev = prev;
239   else
240     STATEMENT_LIST_TAIL (i->container) = prev;
241
242   if (!next && !prev)
243     TREE_SIDE_EFFECTS (i->container) = 0;
244
245   i->ptr = next;
246 }
247
248 /* Move all statements in the statement list after I to a new
249    statement list.  I itself is unchanged.  */
250
251 tree
252 tsi_split_statement_list_after (const tree_stmt_iterator *i)
253 {
254   struct tree_statement_list_node *cur, *next;
255   tree old_sl, new_sl;
256
257   cur = i->ptr;
258   /* How can we possibly split after the end, or before the beginning?  */
259   if (cur == NULL)
260     abort ();
261   next = cur->next;
262
263   old_sl = i->container;
264   new_sl = alloc_stmt_list ();
265   TREE_SIDE_EFFECTS (new_sl) = 1;
266
267   STATEMENT_LIST_HEAD (new_sl) = next;
268   STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl);
269   STATEMENT_LIST_TAIL (old_sl) = cur;
270   cur->next = NULL;
271   next->prev = NULL;
272
273   return new_sl;
274 }
275
276 /* Move all statements in the statement list before I to a new
277    statement list.  I is set to the head of the new list.  */
278
279 tree
280 tsi_split_statement_list_before (tree_stmt_iterator *i)
281 {
282   struct tree_statement_list_node *cur, *prev;
283   tree old_sl, new_sl;
284
285   cur = i->ptr;
286   /* How can we possibly split after the end, or before the beginning?  */
287   if (cur == NULL)
288     abort ();
289   prev = cur->prev;
290
291   old_sl = i->container;
292   new_sl = alloc_stmt_list ();
293   TREE_SIDE_EFFECTS (new_sl) = 1;
294   i->container = new_sl;
295
296   STATEMENT_LIST_HEAD (new_sl) = cur;
297   STATEMENT_LIST_TAIL (new_sl) = STATEMENT_LIST_TAIL (old_sl);
298   STATEMENT_LIST_TAIL (old_sl) = prev;
299   cur->prev = NULL;
300   prev->next = NULL;
301
302   return new_sl;
303 }
304
305 /* Return the first expression in a sequence of COMPOUND_EXPRs,
306    or in a STATEMENT_LIST.  */
307
308 tree
309 expr_first (tree expr)
310 {
311   if (expr == NULL_TREE)
312     return expr;
313
314   if (TREE_CODE (expr) == STATEMENT_LIST)
315     {
316       struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
317       return n ? n->stmt : NULL_TREE;
318     }
319
320   while (TREE_CODE (expr) == COMPOUND_EXPR)
321     expr = TREE_OPERAND (expr, 0);
322   return expr;
323 }
324
325 /* Return the last expression in a sequence of COMPOUND_EXPRs,
326    or in a STATEMENT_LIST.  */
327
328 tree
329 expr_last (tree expr)
330 {
331   if (expr == NULL_TREE)
332     return expr;
333
334   if (TREE_CODE (expr) == STATEMENT_LIST)
335     {
336       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
337       return n ? n->stmt : NULL_TREE;
338     }
339
340   while (TREE_CODE (expr) == COMPOUND_EXPR)
341     expr = TREE_OPERAND (expr, 1);
342   return expr;
343 }
344
345 /* If EXPR is a single statement, naked or in a STATEMENT_LIST, then
346    return it.  Otherwise return NULL.  */
347
348 tree 
349 expr_only (tree expr)
350 {
351   if (expr == NULL_TREE)
352     return NULL_TREE;
353
354   if (TREE_CODE (expr) == STATEMENT_LIST)
355     {
356       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
357       if (n && STATEMENT_LIST_HEAD (expr) == n)
358         return n->stmt;
359       else
360         return NULL_TREE;
361     }
362
363   if (TREE_CODE (expr) == COMPOUND_EXPR)
364     return NULL_TREE;
365
366   return expr;
367 }
368
369 #include "gt-tree-iterator.h"