123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /* Iterator routines for manipulating GENERIC and GIMPLE tree statements.
- Copyright (C) 2003-2015 Free Software Foundation, Inc.
- Contributed by Andrew MacLeod <amacleod@redhat.com>
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- GCC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "config.h"
- #include "system.h"
- #include "coretypes.h"
- #include "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "options.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "tree-iterator.h"
- #include "ggc.h"
- /* This is a cache of STATEMENT_LIST nodes. We create and destroy them
- fairly often during gimplification. */
- static GTY ((deletable (""))) vec<tree, va_gc> *stmt_list_cache;
- tree
- alloc_stmt_list (void)
- {
- tree list;
- if (!vec_safe_is_empty (stmt_list_cache))
- {
- list = stmt_list_cache->pop ();
- memset (list, 0, sizeof (struct tree_base));
- TREE_SET_CODE (list, STATEMENT_LIST);
- }
- else
- list = make_node (STATEMENT_LIST);
- TREE_TYPE (list) = void_type_node;
- return list;
- }
- void
- free_stmt_list (tree t)
- {
- gcc_assert (!STATEMENT_LIST_HEAD (t));
- gcc_assert (!STATEMENT_LIST_TAIL (t));
- vec_safe_push (stmt_list_cache, t);
- }
- /* A subroutine of append_to_statement_list{,_force}. T is not NULL. */
- static void
- append_to_statement_list_1 (tree t, tree *list_p)
- {
- tree list = *list_p;
- tree_stmt_iterator i;
- if (!list)
- {
- if (t && TREE_CODE (t) == STATEMENT_LIST)
- {
- *list_p = t;
- return;
- }
- *list_p = list = alloc_stmt_list ();
- }
- else if (TREE_CODE (list) != STATEMENT_LIST)
- {
- tree first = list;
- *list_p = list = alloc_stmt_list ();
- i = tsi_last (list);
- tsi_link_after (&i, first, TSI_CONTINUE_LINKING);
- }
- i = tsi_last (list);
- tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
- }
- /* Add T to the end of the list container pointed to by LIST_P.
- If T is an expression with no effects, it is ignored. */
- void
- append_to_statement_list (tree t, tree *list_p)
- {
- if (t && TREE_SIDE_EFFECTS (t))
- append_to_statement_list_1 (t, list_p);
- }
- /* Similar, but the statement is always added, regardless of side effects. */
- void
- append_to_statement_list_force (tree t, tree *list_p)
- {
- if (t != NULL_TREE)
- append_to_statement_list_1 (t, list_p);
- }
- /* Links a statement, or a chain of statements, before the current stmt. */
- void
- tsi_link_before (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
- {
- struct tree_statement_list_node *head, *tail, *cur;
- /* Die on looping. */
- gcc_assert (t != i->container);
- if (TREE_CODE (t) == STATEMENT_LIST)
- {
- head = STATEMENT_LIST_HEAD (t);
- tail = STATEMENT_LIST_TAIL (t);
- STATEMENT_LIST_HEAD (t) = NULL;
- STATEMENT_LIST_TAIL (t) = NULL;
- free_stmt_list (t);
- /* Empty statement lists need no work. */
- if (!head || !tail)
- {
- gcc_assert (head == tail);
- return;
- }
- }
- else
- {
- head = ggc_alloc<tree_statement_list_node> ();
- head->prev = NULL;
- head->next = NULL;
- head->stmt = t;
- tail = head;
- }
- TREE_SIDE_EFFECTS (i->container) = 1;
- cur = i->ptr;
- /* Link it into the list. */
- if (cur)
- {
- head->prev = cur->prev;
- if (head->prev)
- head->prev->next = head;
- else
- STATEMENT_LIST_HEAD (i->container) = head;
- tail->next = cur;
- cur->prev = tail;
- }
- else
- {
- head->prev = STATEMENT_LIST_TAIL (i->container);
- if (head->prev)
- head->prev->next = head;
- else
- STATEMENT_LIST_HEAD (i->container) = head;
- STATEMENT_LIST_TAIL (i->container) = tail;
- }
- /* Update the iterator, if requested. */
- switch (mode)
- {
- case TSI_NEW_STMT:
- case TSI_CONTINUE_LINKING:
- case TSI_CHAIN_START:
- i->ptr = head;
- break;
- case TSI_CHAIN_END:
- i->ptr = tail;
- break;
- case TSI_SAME_STMT:
- break;
- }
- }
- /* Links a statement, or a chain of statements, after the current stmt. */
- void
- tsi_link_after (tree_stmt_iterator *i, tree t, enum tsi_iterator_update mode)
- {
- struct tree_statement_list_node *head, *tail, *cur;
- /* Die on looping. */
- gcc_assert (t != i->container);
- if (TREE_CODE (t) == STATEMENT_LIST)
- {
- head = STATEMENT_LIST_HEAD (t);
- tail = STATEMENT_LIST_TAIL (t);
- STATEMENT_LIST_HEAD (t) = NULL;
- STATEMENT_LIST_TAIL (t) = NULL;
- free_stmt_list (t);
- /* Empty statement lists need no work. */
- if (!head || !tail)
- {
- gcc_assert (head == tail);
- return;
- }
- }
- else
- {
- head = ggc_alloc<tree_statement_list_node> ();
- head->prev = NULL;
- head->next = NULL;
- head->stmt = t;
- tail = head;
- }
- TREE_SIDE_EFFECTS (i->container) = 1;
- cur = i->ptr;
- /* Link it into the list. */
- if (cur)
- {
- tail->next = cur->next;
- if (tail->next)
- tail->next->prev = tail;
- else
- STATEMENT_LIST_TAIL (i->container) = tail;
- head->prev = cur;
- cur->next = head;
- }
- else
- {
- gcc_assert (!STATEMENT_LIST_TAIL (i->container));
- STATEMENT_LIST_HEAD (i->container) = head;
- STATEMENT_LIST_TAIL (i->container) = tail;
- }
- /* Update the iterator, if requested. */
- switch (mode)
- {
- case TSI_NEW_STMT:
- case TSI_CHAIN_START:
- i->ptr = head;
- break;
- case TSI_CONTINUE_LINKING:
- case TSI_CHAIN_END:
- i->ptr = tail;
- break;
- case TSI_SAME_STMT:
- gcc_assert (cur);
- break;
- }
- }
- /* Remove a stmt from the tree list. The iterator is updated to point to
- the next stmt. */
- void
- tsi_delink (tree_stmt_iterator *i)
- {
- struct tree_statement_list_node *cur, *next, *prev;
- cur = i->ptr;
- next = cur->next;
- prev = cur->prev;
- if (prev)
- prev->next = next;
- else
- STATEMENT_LIST_HEAD (i->container) = next;
- if (next)
- next->prev = prev;
- else
- STATEMENT_LIST_TAIL (i->container) = prev;
- if (!next && !prev)
- TREE_SIDE_EFFECTS (i->container) = 0;
- i->ptr = next;
- }
- /* Return the first expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
- tree
- expr_first (tree expr)
- {
- if (expr == NULL_TREE)
- return expr;
- if (TREE_CODE (expr) == STATEMENT_LIST)
- {
- struct tree_statement_list_node *n = STATEMENT_LIST_HEAD (expr);
- return n ? n->stmt : NULL_TREE;
- }
- while (TREE_CODE (expr) == COMPOUND_EXPR)
- expr = TREE_OPERAND (expr, 0);
- return expr;
- }
- /* Return the last expression in a sequence of COMPOUND_EXPRs,
- or in a STATEMENT_LIST. */
- tree
- expr_last (tree expr)
- {
- if (expr == NULL_TREE)
- return expr;
- if (TREE_CODE (expr) == STATEMENT_LIST)
- {
- struct tree_statement_list_node *n = STATEMENT_LIST_TAIL (expr);
- return n ? n->stmt : NULL_TREE;
- }
- while (TREE_CODE (expr) == COMPOUND_EXPR)
- expr = TREE_OPERAND (expr, 1);
- return expr;
- }
- #include "gt-tree-iterator.h"
|