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