Line data Source code
1 : /* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
2 : Copyright (C) 2003-2026 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 942347847 : alloc_stmt_list (void)
35 : {
36 942347847 : tree list;
37 942347847 : if (!vec_safe_is_empty (stmt_list_cache))
38 : {
39 567704354 : list = stmt_list_cache->pop ();
40 567704354 : memset (list, 0, sizeof (struct tree_base));
41 567704354 : TREE_SET_CODE (list, STATEMENT_LIST);
42 : }
43 : else
44 : {
45 374643493 : list = make_node (STATEMENT_LIST);
46 374643493 : TREE_SIDE_EFFECTS (list) = 0;
47 : }
48 942347847 : TREE_TYPE (list) = void_type_node;
49 942347847 : return list;
50 : }
51 :
52 : void
53 568582787 : free_stmt_list (tree t)
54 : {
55 568582787 : gcc_assert (!STATEMENT_LIST_HEAD (t));
56 568582787 : gcc_assert (!STATEMENT_LIST_TAIL (t));
57 568582787 : vec_safe_push (stmt_list_cache, t);
58 568582787 : }
59 :
60 : /* A subroutine of append_to_statement_list{,_force}. T is not NULL. */
61 :
62 : static void
63 1506739682 : append_to_statement_list_1 (tree t, tree *list_p)
64 : {
65 1506739682 : tree list = *list_p;
66 1506739682 : tree_stmt_iterator i;
67 :
68 1506739682 : if (!list)
69 : {
70 13306488 : if (t && TREE_CODE (t) == STATEMENT_LIST)
71 : {
72 3448002 : *list_p = t;
73 3448002 : return;
74 : }
75 9858486 : *list_p = list = alloc_stmt_list ();
76 : }
77 1493433194 : else if (TREE_CODE (list) != STATEMENT_LIST)
78 : {
79 19820196 : tree first = list;
80 19820196 : *list_p = list = alloc_stmt_list ();
81 19820196 : i = tsi_last (list);
82 19820196 : tsi_link_after (&i, first, TSI_CONTINUE_LINKING);
83 : }
84 :
85 1503291680 : i = tsi_last (list);
86 1503291680 : tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
87 : }
88 :
89 : /* Add T to the end of the list container pointed to by LIST_P.
90 : If T is an expression with no effects, it is ignored. */
91 :
92 : void
93 74032690 : append_to_statement_list (tree t, tree *list_p)
94 : {
95 74032690 : if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
96 69723219 : append_to_statement_list_1 (t, list_p);
97 74032690 : }
98 :
99 : /* Similar, but the statement is always added, regardless of side effects. */
100 :
101 : void
102 1437016463 : append_to_statement_list_force (tree t, tree *list_p)
103 : {
104 1437016463 : if (t != NULL_TREE)
105 1437016463 : append_to_statement_list_1 (t, list_p);
106 1437016463 : }
107 :
108 : /* Links a statement, or a chain of statements, before the current stmt. */
109 :
110 : void
111 162445 : tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
112 : {
113 162445 : struct tree_statement_list_node *head, *tail, *cur;
114 :
115 : /* Die on looping. */
116 162445 : gcc_assert (t != i->container);
117 :
118 162445 : if (TREE_CODE (t) == STATEMENT_LIST)
119 : {
120 11871 : head = STATEMENT_LIST_HEAD (t);
121 11871 : tail = STATEMENT_LIST_TAIL (t);
122 11871 : STATEMENT_LIST_HEAD (t) = NULL;
123 11871 : STATEMENT_LIST_TAIL (t) = NULL;
124 :
125 11871 : free_stmt_list (t);
126 :
127 : /* Empty statement lists need no work. */
128 11871 : if (!head || !tail)
129 : {
130 15 : gcc_assert (head == tail);
131 : return;
132 : }
133 : }
134 : else
135 : {
136 150574 : head = ggc_alloc<tree_statement_list_node> ();
137 150574 : head->prev = NULL;
138 150574 : head->next = NULL;
139 150574 : head->stmt = t;
140 150574 : tail = head;
141 : }
142 :
143 162430 : if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
144 162430 : TREE_SIDE_EFFECTS (i->container) = 1;
145 :
146 162430 : cur = i->ptr;
147 :
148 : /* Link it into the list. */
149 162430 : if (cur)
150 : {
151 162427 : head->prev = cur->prev;
152 162427 : if (head->prev)
153 129 : head->prev->next = head;
154 : else
155 162298 : STATEMENT_LIST_HEAD (i->container) = head;
156 162427 : tail->next = cur;
157 162427 : cur->prev = tail;
158 : }
159 : else
160 : {
161 3 : head->prev = STATEMENT_LIST_TAIL (i->container);
162 3 : if (head->prev)
163 0 : head->prev->next = head;
164 : else
165 3 : STATEMENT_LIST_HEAD (i->container) = head;
166 3 : STATEMENT_LIST_TAIL (i->container) = tail;
167 : }
168 :
169 : /* Update the iterator, if requested. */
170 162430 : switch (mode)
171 : {
172 27965 : case TSI_NEW_STMT:
173 27965 : case TSI_CONTINUE_LINKING:
174 27965 : case TSI_CHAIN_START:
175 27965 : i->ptr = head;
176 27965 : break;
177 0 : case TSI_CHAIN_END:
178 0 : i->ptr = tail;
179 0 : break;
180 : case TSI_SAME_STMT:
181 : break;
182 : }
183 : }
184 :
185 : /* Links a statement, or a chain of statements, after the current stmt. */
186 :
187 : void
188 1617464927 : tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
189 : {
190 1617464927 : struct tree_statement_list_node *head, *tail, *cur;
191 :
192 : /* Die on looping. */
193 1617464927 : gcc_assert (t != i->container);
194 :
195 1617464927 : if (TREE_CODE (t) == STATEMENT_LIST)
196 : {
197 51870594 : head = STATEMENT_LIST_HEAD (t);
198 51870594 : tail = STATEMENT_LIST_TAIL (t);
199 51870594 : STATEMENT_LIST_HEAD (t) = NULL;
200 51870594 : STATEMENT_LIST_TAIL (t) = NULL;
201 :
202 51870594 : free_stmt_list (t);
203 :
204 : /* Empty statement lists need no work. */
205 51870594 : if (!head || !tail)
206 : {
207 16301713 : gcc_assert (head == tail);
208 : return;
209 : }
210 : }
211 : else
212 : {
213 1565594333 : head = ggc_alloc<tree_statement_list_node> ();
214 1565594333 : head->prev = NULL;
215 1565594333 : head->next = NULL;
216 1565594333 : head->stmt = t;
217 1565594333 : tail = head;
218 : }
219 :
220 1601163214 : if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
221 1227851937 : TREE_SIDE_EFFECTS (i->container) = 1;
222 :
223 1601163214 : cur = i->ptr;
224 :
225 : /* Link it into the list. */
226 1601163214 : if (cur)
227 : {
228 758385091 : tail->next = cur->next;
229 758385091 : if (tail->next)
230 35 : tail->next->prev = tail;
231 : else
232 758385056 : STATEMENT_LIST_TAIL (i->container) = tail;
233 758385091 : head->prev = cur;
234 758385091 : cur->next = head;
235 : }
236 : else
237 : {
238 842778123 : gcc_assert (!STATEMENT_LIST_TAIL (i->container));
239 842778123 : STATEMENT_LIST_HEAD (i->container) = head;
240 842778123 : STATEMENT_LIST_TAIL (i->container) = tail;
241 : }
242 :
243 : /* Update the iterator, if requested. */
244 1601163214 : switch (mode)
245 : {
246 0 : case TSI_NEW_STMT:
247 0 : case TSI_CHAIN_START:
248 0 : i->ptr = head;
249 0 : break;
250 1601163010 : case TSI_CONTINUE_LINKING:
251 1601163010 : case TSI_CHAIN_END:
252 1601163010 : i->ptr = tail;
253 1601163010 : break;
254 204 : case TSI_SAME_STMT:
255 204 : gcc_assert (cur);
256 : break;
257 : }
258 : }
259 :
260 : /* Remove a stmt from the tree list. The iterator is updated to point to
261 : the next stmt. */
262 :
263 : void
264 554444954 : tsi_delink (tree_stmt_iterator *i)
265 : {
266 554444954 : struct tree_statement_list_node *cur, *next, *prev;
267 :
268 554444954 : cur = i->ptr;
269 554444954 : next = cur->next;
270 554444954 : prev = cur->prev;
271 :
272 554444954 : if (prev)
273 73557 : prev->next = next;
274 : else
275 554371397 : STATEMENT_LIST_HEAD (i->container) = next;
276 554444954 : if (next)
277 29538379 : next->prev = prev;
278 : else
279 524906575 : STATEMENT_LIST_TAIL (i->container) = prev;
280 :
281 554444954 : if (!next && !prev)
282 524896642 : TREE_SIDE_EFFECTS (i->container) = 0;
283 :
284 554444954 : i->ptr = next;
285 554444954 : }
286 :
287 : /* Split a STATEMENT_LIST in I.contrainer into two, all statements
288 : from the start until I.ptr inclusive will remain in the original
289 : one, all statements after I.ptr are removed from that STATEMENT_LIST
290 : and returned as a new STATEMENT_LIST. If I is the last statement,
291 : an empty statement with LOC location is returned. */
292 :
293 : tree
294 9247 : tsi_split_stmt_list (location_t loc, tree_stmt_iterator i)
295 : {
296 9247 : if (tsi_one_before_end_p (i))
297 57 : return build_empty_stmt (loc);
298 9190 : tsi_next (&i);
299 9190 : tree ret = NULL_TREE;
300 81411 : while (!tsi_end_p (i))
301 : {
302 72221 : tree t = tsi_stmt (i);
303 72221 : tsi_delink (&i);
304 72221 : append_to_statement_list_force (t, &ret);
305 : }
306 9190 : return ret;
307 : }
308 :
309 : /* Return the first expression in a sequence of COMPOUND_EXPRs, or in
310 : a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
311 : STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */
312 :
313 : tree
314 12893972 : expr_first (tree expr)
315 : {
316 12895252 : if (expr == NULL_TREE)
317 : return expr;
318 :
319 12895222 : if (TREE_CODE (expr) == STATEMENT_LIST)
320 : {
321 4401422 : struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
322 4401422 : if (!n)
323 : return NULL_TREE;
324 8299321 : while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
325 : {
326 3993574 : n = n->next;
327 3993574 : if (!n)
328 : return NULL_TREE;
329 : }
330 : /* If the first non-debug stmt is not a statement list, we
331 : already know it's what we're looking for. */
332 4305747 : if (TREE_CODE (n->stmt) != STATEMENT_LIST)
333 : return n->stmt;
334 :
335 : return expr_first (n->stmt);
336 : }
337 :
338 8493801 : while (TREE_CODE (expr) == COMPOUND_EXPR)
339 1 : expr = TREE_OPERAND (expr, 0);
340 :
341 : return expr;
342 : }
343 :
344 : /* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
345 : STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
346 : STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */
347 :
348 : tree
349 13969551 : expr_last (tree expr)
350 : {
351 13971006 : if (expr == NULL_TREE)
352 : return expr;
353 :
354 13794649 : if (TREE_CODE (expr) == STATEMENT_LIST)
355 : {
356 7075501 : struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
357 7075501 : if (!n)
358 : return NULL_TREE;
359 8923879 : while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
360 : {
361 3603817 : n = n->prev;
362 3603817 : if (!n)
363 : return NULL_TREE;
364 : }
365 : /* If the last non-debug stmt is not a statement list, we
366 : already know it's what we're looking for. */
367 5320062 : if (TREE_CODE (n->stmt) != STATEMENT_LIST)
368 : return n->stmt;
369 :
370 : return expr_last (n->stmt);
371 : }
372 :
373 6730284 : while (TREE_CODE (expr) == COMPOUND_EXPR)
374 11136 : expr = TREE_OPERAND (expr, 1);
375 :
376 : return expr;
377 : }
378 :
379 : /* If EXPR is a STATEMENT_LIST containing just DEBUG_BEGIN_STMTs and
380 : a single other stmt, return that other stmt (recursively).
381 : If it is a STATEMENT_LIST containing no non-DEBUG_BEGIN_STMTs or
382 : multiple, return NULL_TREE.
383 : Otherwise return EXPR. */
384 :
385 : tree
386 36002368 : expr_single (tree expr)
387 : {
388 36048055 : if (expr == NULL_TREE)
389 : return expr;
390 :
391 33386433 : if (TREE_CODE (expr) == STATEMENT_LIST)
392 : {
393 : /* With -gstatement-frontiers we could have a STATEMENT_LIST with
394 : DEBUG_BEGIN_STMT(s) and only a single other stmt, which with
395 : -g wouldn't be present and we'd have that single other stmt
396 : directly instead. */
397 176045 : struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
398 176045 : if (!n)
399 : return NULL_TREE;
400 221964 : while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
401 : {
402 52130 : n = n->next;
403 52130 : if (!n)
404 : return NULL_TREE;
405 : }
406 176598 : expr = n->stmt;
407 176598 : do
408 : {
409 176598 : n = n->next;
410 176598 : if (!n)
411 : return expr_single (expr);
412 : }
413 130911 : while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT);
414 : return NULL_TREE;
415 : }
416 :
417 : return expr;
418 : }
419 :
420 : #include "gt-tree-iterator.h"
|