xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/tree-iterator.c (revision 404ee5b9334f618040b6cdef96a0ff35a6fc4636)
1 /* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
2    Copyright (C) 2003-2017 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 3, 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 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 "tree.h"
25 #include "tree-iterator.h"
26 
27 
28 /* This is a cache of STATEMENT_LIST nodes.  We create and destroy them
29    fairly often during gimplification.  */
30 
31 static GTY ((deletable (""))) vec<tree, va_gc> *stmt_list_cache;
32 
33 tree
34 alloc_stmt_list (void)
35 {
36   tree list;
37   if (!vec_safe_is_empty (stmt_list_cache))
38     {
39       list = stmt_list_cache->pop ();
40       memset (list, 0, sizeof (struct tree_base));
41       TREE_SET_CODE (list, STATEMENT_LIST);
42     }
43   else
44     list = make_node (STATEMENT_LIST);
45   TREE_TYPE (list) = void_type_node;
46   return list;
47 }
48 
49 void
50 free_stmt_list (tree t)
51 {
52   gcc_assert (!STATEMENT_LIST_HEAD (t));
53   gcc_assert (!STATEMENT_LIST_TAIL (t));
54   vec_safe_push (stmt_list_cache, t);
55 }
56 
57 /* A subroutine of append_to_statement_list{,_force}.  T is not NULL.  */
58 
59 static void
60 append_to_statement_list_1 (tree t, tree *list_p)
61 {
62   tree list = *list_p;
63   tree_stmt_iterator i;
64 
65   if (!list)
66     {
67       if (t && TREE_CODE (t) == STATEMENT_LIST)
68 	{
69 	  *list_p = t;
70 	  return;
71 	}
72       *list_p = list = alloc_stmt_list ();
73     }
74   else if (TREE_CODE (list) != STATEMENT_LIST)
75     {
76       tree first = list;
77       *list_p = list = alloc_stmt_list ();
78       i = tsi_last (list);
79       tsi_link_after (&i, first, TSI_CONTINUE_LINKING);
80     }
81 
82   i = tsi_last (list);
83   tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
84 }
85 
86 /* Add T to the end of the list container pointed to by LIST_P.
87    If T is an expression with no effects, it is ignored.  */
88 
89 void
90 append_to_statement_list (tree t, tree *list_p)
91 {
92   if (t && TREE_SIDE_EFFECTS (t))
93     append_to_statement_list_1 (t, list_p);
94 }
95 
96 /* Similar, but the statement is always added, regardless of side effects.  */
97 
98 void
99 append_to_statement_list_force (tree t, tree *list_p)
100 {
101   if (t != NULL_TREE)
102     append_to_statement_list_1 (t, list_p);
103 }
104 
105 /* Links a statement, or a chain of statements, before the current stmt.  */
106 
107 void
108 tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
109 {
110   struct tree_statement_list_node *head, *tail, *cur;
111 
112   /* Die on looping.  */
113   gcc_assert (t != i->container);
114 
115   if (TREE_CODE (t) == STATEMENT_LIST)
116     {
117       head = STATEMENT_LIST_HEAD (t);
118       tail = STATEMENT_LIST_TAIL (t);
119       STATEMENT_LIST_HEAD (t) = NULL;
120       STATEMENT_LIST_TAIL (t) = NULL;
121 
122       free_stmt_list (t);
123 
124       /* Empty statement lists need no work.  */
125       if (!head || !tail)
126 	{
127 	  gcc_assert (head == tail);
128 	  return;
129 	}
130     }
131   else
132     {
133       head = ggc_alloc<tree_statement_list_node> ();
134       head->prev = NULL;
135       head->next = NULL;
136       head->stmt = t;
137       tail = head;
138     }
139 
140   TREE_SIDE_EFFECTS (i->container) = 1;
141 
142   cur = i->ptr;
143 
144   /* Link it into the list.  */
145   if (cur)
146     {
147       head->prev = cur->prev;
148       if (head->prev)
149 	head->prev->next = head;
150       else
151 	STATEMENT_LIST_HEAD (i->container) = head;
152       tail->next = cur;
153       cur->prev = tail;
154     }
155   else
156     {
157       head->prev = STATEMENT_LIST_TAIL (i->container);
158       if (head->prev)
159        head->prev->next = head;
160       else
161        STATEMENT_LIST_HEAD (i->container) = head;
162       STATEMENT_LIST_TAIL (i->container) = tail;
163     }
164 
165   /* Update the iterator, if requested.  */
166   switch (mode)
167     {
168     case TSI_NEW_STMT:
169     case TSI_CONTINUE_LINKING:
170     case TSI_CHAIN_START:
171       i->ptr = head;
172       break;
173     case TSI_CHAIN_END:
174       i->ptr = tail;
175       break;
176     case TSI_SAME_STMT:
177       break;
178     }
179 }
180 
181 /* Links a statement, or a chain of statements, after the current stmt.  */
182 
183 void
184 tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
185 {
186   struct tree_statement_list_node *head, *tail, *cur;
187 
188   /* Die on looping.  */
189   gcc_assert (t != i->container);
190 
191   if (TREE_CODE (t) == STATEMENT_LIST)
192     {
193       head = STATEMENT_LIST_HEAD (t);
194       tail = STATEMENT_LIST_TAIL (t);
195       STATEMENT_LIST_HEAD (t) = NULL;
196       STATEMENT_LIST_TAIL (t) = NULL;
197 
198       free_stmt_list (t);
199 
200       /* Empty statement lists need no work.  */
201       if (!head || !tail)
202 	{
203 	  gcc_assert (head == tail);
204 	  return;
205 	}
206     }
207   else
208     {
209       head = ggc_alloc<tree_statement_list_node> ();
210       head->prev = NULL;
211       head->next = NULL;
212       head->stmt = t;
213       tail = head;
214     }
215 
216   TREE_SIDE_EFFECTS (i->container) = 1;
217 
218   cur = i->ptr;
219 
220   /* Link it into the list.  */
221   if (cur)
222     {
223       tail->next = cur->next;
224       if (tail->next)
225 	tail->next->prev = tail;
226       else
227 	STATEMENT_LIST_TAIL (i->container) = tail;
228       head->prev = cur;
229       cur->next = head;
230     }
231   else
232     {
233       gcc_assert (!STATEMENT_LIST_TAIL (i->container));
234       STATEMENT_LIST_HEAD (i->container) = head;
235       STATEMENT_LIST_TAIL (i->container) = tail;
236     }
237 
238   /* Update the iterator, if requested.  */
239   switch (mode)
240     {
241     case TSI_NEW_STMT:
242     case TSI_CHAIN_START:
243       i->ptr = head;
244       break;
245     case TSI_CONTINUE_LINKING:
246     case TSI_CHAIN_END:
247       i->ptr = tail;
248       break;
249     case TSI_SAME_STMT:
250       gcc_assert (cur);
251       break;
252     }
253 }
254 
255 /* Remove a stmt from the tree list.  The iterator is updated to point to
256    the next stmt.  */
257 
258 void
259 tsi_delink (tree_stmt_iterator *i)
260 {
261   struct tree_statement_list_node *cur, *next, *prev;
262 
263   cur = i->ptr;
264   next = cur->next;
265   prev = cur->prev;
266 
267   if (prev)
268     prev->next = next;
269   else
270     STATEMENT_LIST_HEAD (i->container) = next;
271   if (next)
272     next->prev = prev;
273   else
274     STATEMENT_LIST_TAIL (i->container) = prev;
275 
276   if (!next && !prev)
277     TREE_SIDE_EFFECTS (i->container) = 0;
278 
279   i->ptr = next;
280 }
281 
282 /* Return the first expression in a sequence of COMPOUND_EXPRs,
283    or in a STATEMENT_LIST.  */
284 
285 tree
286 expr_first (tree expr)
287 {
288   if (expr == NULL_TREE)
289     return expr;
290 
291   if (TREE_CODE (expr) == STATEMENT_LIST)
292     {
293       struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
294       return n ? n->stmt : NULL_TREE;
295     }
296 
297   while (TREE_CODE (expr) == COMPOUND_EXPR)
298     expr = TREE_OPERAND (expr, 0);
299 
300   return expr;
301 }
302 
303 /* Return the last expression in a sequence of COMPOUND_EXPRs,
304    or in a STATEMENT_LIST.  */
305 
306 tree
307 expr_last (tree expr)
308 {
309   if (expr == NULL_TREE)
310     return expr;
311 
312   if (TREE_CODE (expr) == STATEMENT_LIST)
313     {
314       struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
315       return n ? n->stmt : NULL_TREE;
316     }
317 
318   while (TREE_CODE (expr) == COMPOUND_EXPR)
319     expr = TREE_OPERAND (expr, 1);
320 
321   return expr;
322 }
323 
324 #include "gt-tree-iterator.h"
325