1/* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
2   Copyright (C) 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
3   Contributed by Andrew MacLeod  <amacleod@redhat.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along 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 "gimple.h"
26#include "tree-iterator.h"
27#include "ggc.h"
28
29
30/* This is a cache of STATEMENT_LIST nodes.  We create and destroy them
31   fairly often during gimplification.  */
32
33static GTY ((deletable (""))) tree stmt_list_cache;
34
35tree
36alloc_stmt_list (void)
37{
38  tree list = stmt_list_cache;
39  if (list)
40    {
41      stmt_list_cache = TREE_CHAIN (list);
42      gcc_assert (stmt_list_cache != list);
43      memset (list, 0, sizeof(struct tree_common));
44      TREE_SET_CODE (list, STATEMENT_LIST);
45    }
46  else
47    list = make_node (STATEMENT_LIST);
48  TREE_TYPE (list) = void_type_node;
49  return list;
50}
51
52void
53free_stmt_list (tree t)
54{
55  gcc_assert (!STATEMENT_LIST_HEAD (t));
56  gcc_assert (!STATEMENT_LIST_TAIL (t));
57  /* If this triggers, it's a sign that the same list is being freed
58     twice.  */
59  gcc_assert (t != stmt_list_cache || stmt_list_cache == NULL);
60  TREE_CHAIN (t) = stmt_list_cache;
61  stmt_list_cache = t;
62}
63
64/* Links a statement, or a chain of statements, before the current stmt.  */
65
66void
67tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
68{
69  struct tree_statement_list_node *head, *tail, *cur;
70
71  /* Die on looping.  */
72  gcc_assert (t != i->container);
73
74  if (TREE_CODE (t) == STATEMENT_LIST)
75    {
76      head = STATEMENT_LIST_HEAD (t);
77      tail = STATEMENT_LIST_TAIL (t);
78      STATEMENT_LIST_HEAD (t) = NULL;
79      STATEMENT_LIST_TAIL (t) = NULL;
80
81      free_stmt_list (t);
82
83      /* Empty statement lists need no work.  */
84      if (!head || !tail)
85	{
86	  gcc_assert (head == tail);
87	  return;
88	}
89    }
90  else
91    {
92      head = GGC_NEW (struct tree_statement_list_node);
93      head->prev = NULL;
94      head->next = NULL;
95      head->stmt = t;
96      tail = head;
97    }
98
99  TREE_SIDE_EFFECTS (i->container) = 1;
100
101  cur = i->ptr;
102
103  /* Link it into the list.  */
104  if (cur)
105    {
106      head->prev = cur->prev;
107      if (head->prev)
108	head->prev->next = head;
109      else
110	STATEMENT_LIST_HEAD (i->container) = head;
111      tail->next = cur;
112      cur->prev = tail;
113    }
114  else
115    {
116      head->prev = STATEMENT_LIST_TAIL (i->container);
117      if (head->prev)
118       head->prev->next = head;
119      else
120       STATEMENT_LIST_HEAD (i->container) = head;
121      STATEMENT_LIST_TAIL (i->container) = tail;
122    }
123
124  /* Update the iterator, if requested.  */
125  switch (mode)
126    {
127    case TSI_NEW_STMT:
128    case TSI_CONTINUE_LINKING:
129    case TSI_CHAIN_START:
130      i->ptr = head;
131      break;
132    case TSI_CHAIN_END:
133      i->ptr = tail;
134      break;
135    case TSI_SAME_STMT:
136      break;
137    }
138}
139
140/* Links a statement, or a chain of statements, after the current stmt.  */
141
142void
143tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
144{
145  struct tree_statement_list_node *head, *tail, *cur;
146
147  /* Die on looping.  */
148  gcc_assert (t != i->container);
149
150  if (TREE_CODE (t) == STATEMENT_LIST)
151    {
152      head = STATEMENT_LIST_HEAD (t);
153      tail = STATEMENT_LIST_TAIL (t);
154      STATEMENT_LIST_HEAD (t) = NULL;
155      STATEMENT_LIST_TAIL (t) = NULL;
156
157      free_stmt_list (t);
158
159      /* Empty statement lists need no work.  */
160      if (!head || !tail)
161	{
162	  gcc_assert (head == tail);
163	  return;
164	}
165    }
166  else
167    {
168      head = GGC_NEW (struct tree_statement_list_node);
169      head->prev = NULL;
170      head->next = NULL;
171      head->stmt = t;
172      tail = head;
173    }
174
175  TREE_SIDE_EFFECTS (i->container) = 1;
176
177  cur = i->ptr;
178
179  /* Link it into the list.  */
180  if (cur)
181    {
182      tail->next = cur->next;
183      if (tail->next)
184	tail->next->prev = tail;
185      else
186	STATEMENT_LIST_TAIL (i->container) = tail;
187      head->prev = cur;
188      cur->next = head;
189    }
190  else
191    {
192      gcc_assert (!STATEMENT_LIST_TAIL (i->container));
193      STATEMENT_LIST_HEAD (i->container) = head;
194      STATEMENT_LIST_TAIL (i->container) = tail;
195    }
196
197  /* Update the iterator, if requested.  */
198  switch (mode)
199    {
200    case TSI_NEW_STMT:
201    case TSI_CHAIN_START:
202      i->ptr = head;
203      break;
204    case TSI_CONTINUE_LINKING:
205    case TSI_CHAIN_END:
206      i->ptr = tail;
207      break;
208    case TSI_SAME_STMT:
209      gcc_assert (cur);
210      break;
211    }
212}
213
214/* Remove a stmt from the tree list.  The iterator is updated to point to
215   the next stmt.  */
216
217void
218tsi_delink (tree_stmt_iterator *i)
219{
220  struct tree_statement_list_node *cur, *next, *prev;
221
222  cur = i->ptr;
223  next = cur->next;
224  prev = cur->prev;
225
226  if (prev)
227    prev->next = next;
228  else
229    STATEMENT_LIST_HEAD (i->container) = next;
230  if (next)
231    next->prev = prev;
232  else
233    STATEMENT_LIST_TAIL (i->container) = prev;
234
235  if (!next && !prev)
236    TREE_SIDE_EFFECTS (i->container) = 0;
237
238  i->ptr = next;
239}
240
241/* Return the first expression in a sequence of COMPOUND_EXPRs,
242   or in a STATEMENT_LIST.  */
243
244tree
245expr_first (tree expr)
246{
247  if (expr == NULL_TREE)
248    return expr;
249
250  if (TREE_CODE (expr) == STATEMENT_LIST)
251    {
252      struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
253      return n ? n->stmt : NULL_TREE;
254    }
255
256  while (TREE_CODE (expr) == COMPOUND_EXPR)
257    expr = TREE_OPERAND (expr, 0);
258
259  return expr;
260}
261
262/* Return the last expression in a sequence of COMPOUND_EXPRs,
263   or in a STATEMENT_LIST.  */
264
265tree
266expr_last (tree expr)
267{
268  if (expr == NULL_TREE)
269    return expr;
270
271  if (TREE_CODE (expr) == STATEMENT_LIST)
272    {
273      struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
274      return n ? n->stmt : NULL_TREE;
275    }
276
277  while (TREE_CODE (expr) == COMPOUND_EXPR)
278    expr = TREE_OPERAND (expr, 1);
279
280  return expr;
281}
282
283#include "gt-tree-iterator.h"
284