11debfc3dSmrg /* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
2*8feb0f0bSmrg Copyright (C) 2003-2020 Free Software Foundation, Inc.
31debfc3dSmrg Contributed by Andrew MacLeod <amacleod@redhat.com>
41debfc3dSmrg
51debfc3dSmrg This file is part of GCC.
61debfc3dSmrg
71debfc3dSmrg GCC is free software; you can redistribute it and/or modify
81debfc3dSmrg it under the terms of the GNU General Public License as published by
91debfc3dSmrg the Free Software Foundation; either version 3, or (at your option)
101debfc3dSmrg any later version.
111debfc3dSmrg
121debfc3dSmrg GCC is distributed in the hope that it will be useful,
131debfc3dSmrg but WITHOUT ANY WARRANTY; without even the implied warranty of
141debfc3dSmrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
151debfc3dSmrg GNU General Public License for more details.
161debfc3dSmrg
171debfc3dSmrg You should have received a copy of the GNU General Public License
181debfc3dSmrg along with GCC; see the file COPYING3. If not see
191debfc3dSmrg <http://www.gnu.org/licenses/>. */
201debfc3dSmrg
211debfc3dSmrg #include "config.h"
221debfc3dSmrg #include "system.h"
231debfc3dSmrg #include "coretypes.h"
241debfc3dSmrg #include "tree.h"
251debfc3dSmrg #include "tree-iterator.h"
261debfc3dSmrg
271debfc3dSmrg
281debfc3dSmrg /* This is a cache of STATEMENT_LIST nodes. We create and destroy them
291debfc3dSmrg fairly often during gimplification. */
301debfc3dSmrg
311debfc3dSmrg static GTY ((deletable (""))) vec<tree, va_gc> *stmt_list_cache;
321debfc3dSmrg
331debfc3dSmrg tree
alloc_stmt_list(void)341debfc3dSmrg alloc_stmt_list (void)
351debfc3dSmrg {
361debfc3dSmrg tree list;
371debfc3dSmrg if (!vec_safe_is_empty (stmt_list_cache))
381debfc3dSmrg {
391debfc3dSmrg list = stmt_list_cache->pop ();
401debfc3dSmrg memset (list, 0, sizeof (struct tree_base));
411debfc3dSmrg TREE_SET_CODE (list, STATEMENT_LIST);
421debfc3dSmrg }
431debfc3dSmrg else
44a2dc1f3fSmrg {
451debfc3dSmrg list = make_node (STATEMENT_LIST);
46a2dc1f3fSmrg TREE_SIDE_EFFECTS (list) = 0;
47a2dc1f3fSmrg }
481debfc3dSmrg TREE_TYPE (list) = void_type_node;
491debfc3dSmrg return list;
501debfc3dSmrg }
511debfc3dSmrg
521debfc3dSmrg void
free_stmt_list(tree t)531debfc3dSmrg free_stmt_list (tree t)
541debfc3dSmrg {
551debfc3dSmrg gcc_assert (!STATEMENT_LIST_HEAD (t));
561debfc3dSmrg gcc_assert (!STATEMENT_LIST_TAIL (t));
571debfc3dSmrg vec_safe_push (stmt_list_cache, t);
581debfc3dSmrg }
591debfc3dSmrg
601debfc3dSmrg /* A subroutine of append_to_statement_list{,_force}. T is not NULL. */
611debfc3dSmrg
621debfc3dSmrg static void
append_to_statement_list_1(tree t,tree * list_p)631debfc3dSmrg append_to_statement_list_1 (tree t, tree *list_p)
641debfc3dSmrg {
651debfc3dSmrg tree list = *list_p;
661debfc3dSmrg tree_stmt_iterator i;
671debfc3dSmrg
681debfc3dSmrg if (!list)
691debfc3dSmrg {
701debfc3dSmrg if (t && TREE_CODE (t) == STATEMENT_LIST)
711debfc3dSmrg {
721debfc3dSmrg *list_p = t;
731debfc3dSmrg return;
741debfc3dSmrg }
751debfc3dSmrg *list_p = list = alloc_stmt_list ();
761debfc3dSmrg }
771debfc3dSmrg else if (TREE_CODE (list) != STATEMENT_LIST)
781debfc3dSmrg {
791debfc3dSmrg tree first = list;
801debfc3dSmrg *list_p = list = alloc_stmt_list ();
811debfc3dSmrg i = tsi_last (list);
821debfc3dSmrg tsi_link_after (&i, first, TSI_CONTINUE_LINKING);
831debfc3dSmrg }
841debfc3dSmrg
851debfc3dSmrg i = tsi_last (list);
861debfc3dSmrg tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
871debfc3dSmrg }
881debfc3dSmrg
891debfc3dSmrg /* Add T to the end of the list container pointed to by LIST_P.
901debfc3dSmrg If T is an expression with no effects, it is ignored. */
911debfc3dSmrg
921debfc3dSmrg void
append_to_statement_list(tree t,tree * list_p)931debfc3dSmrg append_to_statement_list (tree t, tree *list_p)
941debfc3dSmrg {
95a2dc1f3fSmrg if (t && (TREE_SIDE_EFFECTS (t) || TREE_CODE (t) == DEBUG_BEGIN_STMT))
961debfc3dSmrg append_to_statement_list_1 (t, list_p);
971debfc3dSmrg }
981debfc3dSmrg
991debfc3dSmrg /* Similar, but the statement is always added, regardless of side effects. */
1001debfc3dSmrg
1011debfc3dSmrg void
append_to_statement_list_force(tree t,tree * list_p)1021debfc3dSmrg append_to_statement_list_force (tree t, tree *list_p)
1031debfc3dSmrg {
1041debfc3dSmrg if (t != NULL_TREE)
1051debfc3dSmrg append_to_statement_list_1 (t, list_p);
1061debfc3dSmrg }
1071debfc3dSmrg
1081debfc3dSmrg /* Links a statement, or a chain of statements, before the current stmt. */
1091debfc3dSmrg
1101debfc3dSmrg void
tsi_link_before(tree_stmt_iterator * i,tree t,enum tsi_iterator_update mode)1111debfc3dSmrg tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
1121debfc3dSmrg {
1131debfc3dSmrg struct tree_statement_list_node *head, *tail, *cur;
1141debfc3dSmrg
1151debfc3dSmrg /* Die on looping. */
1161debfc3dSmrg gcc_assert (t != i->container);
1171debfc3dSmrg
1181debfc3dSmrg if (TREE_CODE (t) == STATEMENT_LIST)
1191debfc3dSmrg {
1201debfc3dSmrg head = STATEMENT_LIST_HEAD (t);
1211debfc3dSmrg tail = STATEMENT_LIST_TAIL (t);
1221debfc3dSmrg STATEMENT_LIST_HEAD (t) = NULL;
1231debfc3dSmrg STATEMENT_LIST_TAIL (t) = NULL;
1241debfc3dSmrg
1251debfc3dSmrg free_stmt_list (t);
1261debfc3dSmrg
1271debfc3dSmrg /* Empty statement lists need no work. */
1281debfc3dSmrg if (!head || !tail)
1291debfc3dSmrg {
1301debfc3dSmrg gcc_assert (head == tail);
1311debfc3dSmrg return;
1321debfc3dSmrg }
1331debfc3dSmrg }
1341debfc3dSmrg else
1351debfc3dSmrg {
1361debfc3dSmrg head = ggc_alloc<tree_statement_list_node> ();
1371debfc3dSmrg head->prev = NULL;
1381debfc3dSmrg head->next = NULL;
1391debfc3dSmrg head->stmt = t;
1401debfc3dSmrg tail = head;
1411debfc3dSmrg }
1421debfc3dSmrg
143a2dc1f3fSmrg if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
1441debfc3dSmrg TREE_SIDE_EFFECTS (i->container) = 1;
1451debfc3dSmrg
1461debfc3dSmrg cur = i->ptr;
1471debfc3dSmrg
1481debfc3dSmrg /* Link it into the list. */
1491debfc3dSmrg if (cur)
1501debfc3dSmrg {
1511debfc3dSmrg head->prev = cur->prev;
1521debfc3dSmrg if (head->prev)
1531debfc3dSmrg head->prev->next = head;
1541debfc3dSmrg else
1551debfc3dSmrg STATEMENT_LIST_HEAD (i->container) = head;
1561debfc3dSmrg tail->next = cur;
1571debfc3dSmrg cur->prev = tail;
1581debfc3dSmrg }
1591debfc3dSmrg else
1601debfc3dSmrg {
1611debfc3dSmrg head->prev = STATEMENT_LIST_TAIL (i->container);
1621debfc3dSmrg if (head->prev)
1631debfc3dSmrg head->prev->next = head;
1641debfc3dSmrg else
1651debfc3dSmrg STATEMENT_LIST_HEAD (i->container) = head;
1661debfc3dSmrg STATEMENT_LIST_TAIL (i->container) = tail;
1671debfc3dSmrg }
1681debfc3dSmrg
1691debfc3dSmrg /* Update the iterator, if requested. */
1701debfc3dSmrg switch (mode)
1711debfc3dSmrg {
1721debfc3dSmrg case TSI_NEW_STMT:
1731debfc3dSmrg case TSI_CONTINUE_LINKING:
1741debfc3dSmrg case TSI_CHAIN_START:
1751debfc3dSmrg i->ptr = head;
1761debfc3dSmrg break;
1771debfc3dSmrg case TSI_CHAIN_END:
1781debfc3dSmrg i->ptr = tail;
1791debfc3dSmrg break;
1801debfc3dSmrg case TSI_SAME_STMT:
1811debfc3dSmrg break;
1821debfc3dSmrg }
1831debfc3dSmrg }
1841debfc3dSmrg
1851debfc3dSmrg /* Links a statement, or a chain of statements, after the current stmt. */
1861debfc3dSmrg
1871debfc3dSmrg void
tsi_link_after(tree_stmt_iterator * i,tree t,enum tsi_iterator_update mode)1881debfc3dSmrg tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
1891debfc3dSmrg {
1901debfc3dSmrg struct tree_statement_list_node *head, *tail, *cur;
1911debfc3dSmrg
1921debfc3dSmrg /* Die on looping. */
1931debfc3dSmrg gcc_assert (t != i->container);
1941debfc3dSmrg
1951debfc3dSmrg if (TREE_CODE (t) == STATEMENT_LIST)
1961debfc3dSmrg {
1971debfc3dSmrg head = STATEMENT_LIST_HEAD (t);
1981debfc3dSmrg tail = STATEMENT_LIST_TAIL (t);
1991debfc3dSmrg STATEMENT_LIST_HEAD (t) = NULL;
2001debfc3dSmrg STATEMENT_LIST_TAIL (t) = NULL;
2011debfc3dSmrg
2021debfc3dSmrg free_stmt_list (t);
2031debfc3dSmrg
2041debfc3dSmrg /* Empty statement lists need no work. */
2051debfc3dSmrg if (!head || !tail)
2061debfc3dSmrg {
2071debfc3dSmrg gcc_assert (head == tail);
2081debfc3dSmrg return;
2091debfc3dSmrg }
2101debfc3dSmrg }
2111debfc3dSmrg else
2121debfc3dSmrg {
2131debfc3dSmrg head = ggc_alloc<tree_statement_list_node> ();
2141debfc3dSmrg head->prev = NULL;
2151debfc3dSmrg head->next = NULL;
2161debfc3dSmrg head->stmt = t;
2171debfc3dSmrg tail = head;
2181debfc3dSmrg }
2191debfc3dSmrg
220a2dc1f3fSmrg if (TREE_CODE (t) != DEBUG_BEGIN_STMT)
2211debfc3dSmrg TREE_SIDE_EFFECTS (i->container) = 1;
2221debfc3dSmrg
2231debfc3dSmrg cur = i->ptr;
2241debfc3dSmrg
2251debfc3dSmrg /* Link it into the list. */
2261debfc3dSmrg if (cur)
2271debfc3dSmrg {
2281debfc3dSmrg tail->next = cur->next;
2291debfc3dSmrg if (tail->next)
2301debfc3dSmrg tail->next->prev = tail;
2311debfc3dSmrg else
2321debfc3dSmrg STATEMENT_LIST_TAIL (i->container) = tail;
2331debfc3dSmrg head->prev = cur;
2341debfc3dSmrg cur->next = head;
2351debfc3dSmrg }
2361debfc3dSmrg else
2371debfc3dSmrg {
2381debfc3dSmrg gcc_assert (!STATEMENT_LIST_TAIL (i->container));
2391debfc3dSmrg STATEMENT_LIST_HEAD (i->container) = head;
2401debfc3dSmrg STATEMENT_LIST_TAIL (i->container) = tail;
2411debfc3dSmrg }
2421debfc3dSmrg
2431debfc3dSmrg /* Update the iterator, if requested. */
2441debfc3dSmrg switch (mode)
2451debfc3dSmrg {
2461debfc3dSmrg case TSI_NEW_STMT:
2471debfc3dSmrg case TSI_CHAIN_START:
2481debfc3dSmrg i->ptr = head;
2491debfc3dSmrg break;
2501debfc3dSmrg case TSI_CONTINUE_LINKING:
2511debfc3dSmrg case TSI_CHAIN_END:
2521debfc3dSmrg i->ptr = tail;
2531debfc3dSmrg break;
2541debfc3dSmrg case TSI_SAME_STMT:
2551debfc3dSmrg gcc_assert (cur);
2561debfc3dSmrg break;
2571debfc3dSmrg }
2581debfc3dSmrg }
2591debfc3dSmrg
2601debfc3dSmrg /* Remove a stmt from the tree list. The iterator is updated to point to
2611debfc3dSmrg the next stmt. */
2621debfc3dSmrg
2631debfc3dSmrg void
tsi_delink(tree_stmt_iterator * i)2641debfc3dSmrg tsi_delink (tree_stmt_iterator *i)
2651debfc3dSmrg {
2661debfc3dSmrg struct tree_statement_list_node *cur, *next, *prev;
2671debfc3dSmrg
2681debfc3dSmrg cur = i->ptr;
2691debfc3dSmrg next = cur->next;
2701debfc3dSmrg prev = cur->prev;
2711debfc3dSmrg
2721debfc3dSmrg if (prev)
2731debfc3dSmrg prev->next = next;
2741debfc3dSmrg else
2751debfc3dSmrg STATEMENT_LIST_HEAD (i->container) = next;
2761debfc3dSmrg if (next)
2771debfc3dSmrg next->prev = prev;
2781debfc3dSmrg else
2791debfc3dSmrg STATEMENT_LIST_TAIL (i->container) = prev;
2801debfc3dSmrg
2811debfc3dSmrg if (!next && !prev)
2821debfc3dSmrg TREE_SIDE_EFFECTS (i->container) = 0;
2831debfc3dSmrg
2841debfc3dSmrg i->ptr = next;
2851debfc3dSmrg }
2861debfc3dSmrg
287a2dc1f3fSmrg /* Return the first expression in a sequence of COMPOUND_EXPRs, or in
288a2dc1f3fSmrg a STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
289a2dc1f3fSmrg STATEMENT_LIST if that's the first non-DEBUG_BEGIN_STMT. */
2901debfc3dSmrg
2911debfc3dSmrg tree
expr_first(tree expr)2921debfc3dSmrg expr_first (tree expr)
2931debfc3dSmrg {
2941debfc3dSmrg if (expr == NULL_TREE)
2951debfc3dSmrg return expr;
2961debfc3dSmrg
2971debfc3dSmrg if (TREE_CODE (expr) == STATEMENT_LIST)
2981debfc3dSmrg {
2991debfc3dSmrg struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
300a2dc1f3fSmrg if (!n)
301a2dc1f3fSmrg return NULL_TREE;
302a2dc1f3fSmrg while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
303a2dc1f3fSmrg {
304a2dc1f3fSmrg n = n->next;
305a2dc1f3fSmrg if (!n)
306a2dc1f3fSmrg return NULL_TREE;
307a2dc1f3fSmrg }
308a2dc1f3fSmrg /* If the first non-debug stmt is not a statement list, we
309a2dc1f3fSmrg already know it's what we're looking for. */
310a2dc1f3fSmrg if (TREE_CODE (n->stmt) != STATEMENT_LIST)
311a2dc1f3fSmrg return n->stmt;
312a2dc1f3fSmrg
313a2dc1f3fSmrg return expr_first (n->stmt);
3141debfc3dSmrg }
3151debfc3dSmrg
3161debfc3dSmrg while (TREE_CODE (expr) == COMPOUND_EXPR)
3171debfc3dSmrg expr = TREE_OPERAND (expr, 0);
3181debfc3dSmrg
3191debfc3dSmrg return expr;
3201debfc3dSmrg }
3211debfc3dSmrg
322a2dc1f3fSmrg /* Return the last expression in a sequence of COMPOUND_EXPRs, or in a
323a2dc1f3fSmrg STATEMENT_LIST, disregarding DEBUG_BEGIN_STMTs, recursing into a
324a2dc1f3fSmrg STATEMENT_LIST if that's the last non-DEBUG_BEGIN_STMT. */
3251debfc3dSmrg
3261debfc3dSmrg tree
expr_last(tree expr)3271debfc3dSmrg expr_last (tree expr)
3281debfc3dSmrg {
3291debfc3dSmrg if (expr == NULL_TREE)
3301debfc3dSmrg return expr;
3311debfc3dSmrg
3321debfc3dSmrg if (TREE_CODE (expr) == STATEMENT_LIST)
3331debfc3dSmrg {
3341debfc3dSmrg struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
335a2dc1f3fSmrg if (!n)
336a2dc1f3fSmrg return NULL_TREE;
337a2dc1f3fSmrg while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
338a2dc1f3fSmrg {
339a2dc1f3fSmrg n = n->prev;
340a2dc1f3fSmrg if (!n)
341a2dc1f3fSmrg return NULL_TREE;
342a2dc1f3fSmrg }
343a2dc1f3fSmrg /* If the last non-debug stmt is not a statement list, we
344a2dc1f3fSmrg already know it's what we're looking for. */
345a2dc1f3fSmrg if (TREE_CODE (n->stmt) != STATEMENT_LIST)
346a2dc1f3fSmrg return n->stmt;
347a2dc1f3fSmrg
348a2dc1f3fSmrg return expr_last (n->stmt);
3491debfc3dSmrg }
3501debfc3dSmrg
3511debfc3dSmrg while (TREE_CODE (expr) == COMPOUND_EXPR)
3521debfc3dSmrg expr = TREE_OPERAND (expr, 1);
3531debfc3dSmrg
3541debfc3dSmrg return expr;
3551debfc3dSmrg }
3561debfc3dSmrg
357*8feb0f0bSmrg /* If EXPR is a STATEMENT_LIST containing just DEBUG_BEGIN_STMTs and
358*8feb0f0bSmrg a single other stmt, return that other stmt (recursively).
359*8feb0f0bSmrg If it is a STATEMENT_LIST containing no non-DEBUG_BEGIN_STMTs or
360*8feb0f0bSmrg multiple, return NULL_TREE.
361*8feb0f0bSmrg Otherwise return EXPR. */
362*8feb0f0bSmrg
363*8feb0f0bSmrg tree
expr_single(tree expr)364*8feb0f0bSmrg expr_single (tree expr)
365*8feb0f0bSmrg {
366*8feb0f0bSmrg if (expr == NULL_TREE)
367*8feb0f0bSmrg return expr;
368*8feb0f0bSmrg
369*8feb0f0bSmrg if (TREE_CODE (expr) == STATEMENT_LIST)
370*8feb0f0bSmrg {
371*8feb0f0bSmrg /* With -gstatement-frontiers we could have a STATEMENT_LIST with
372*8feb0f0bSmrg DEBUG_BEGIN_STMT(s) and only a single other stmt, which with
373*8feb0f0bSmrg -g wouldn't be present and we'd have that single other stmt
374*8feb0f0bSmrg directly instead. */
375*8feb0f0bSmrg struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
376*8feb0f0bSmrg if (!n)
377*8feb0f0bSmrg return NULL_TREE;
378*8feb0f0bSmrg while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT)
379*8feb0f0bSmrg {
380*8feb0f0bSmrg n = n->next;
381*8feb0f0bSmrg if (!n)
382*8feb0f0bSmrg return NULL_TREE;
383*8feb0f0bSmrg }
384*8feb0f0bSmrg expr = n->stmt;
385*8feb0f0bSmrg do
386*8feb0f0bSmrg {
387*8feb0f0bSmrg n = n->next;
388*8feb0f0bSmrg if (!n)
389*8feb0f0bSmrg return expr_single (expr);
390*8feb0f0bSmrg }
391*8feb0f0bSmrg while (TREE_CODE (n->stmt) == DEBUG_BEGIN_STMT);
392*8feb0f0bSmrg return NULL_TREE;
393*8feb0f0bSmrg }
394*8feb0f0bSmrg
395*8feb0f0bSmrg return expr;
396*8feb0f0bSmrg }
397*8feb0f0bSmrg
3981debfc3dSmrg #include "gt-tree-iterator.h"
399