aboutsummaryrefslogtreecommitdiff
path: root/gcc/ssa-iterators.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ssa-iterators.h')
-rw-r--r--gcc/ssa-iterators.h119
1 files changed, 85 insertions, 34 deletions
diff --git a/gcc/ssa-iterators.h b/gcc/ssa-iterators.h
index 0822a98..24cf6bf 100644
--- a/gcc/ssa-iterators.h
+++ b/gcc/ssa-iterators.h
@@ -42,10 +42,10 @@ along with GCC; see the file COPYING3. If not see
Safe iteration via FOR_EACH_IMM_USE_STMT and FOR_EACH_IMM_USE_ON_STMT
allows insertion, deletion, and modification of SSA operands within
the current stmt iterated. The iterator manages this by re-sorting
- the immediate uses to batch uses on a single stmt after each other
- and inserts a marker node into the list immediately after the node
- ending the current batch. This marker node is uniquely identified by
- having null stmt *and* a null use pointer. */
+ the immediate uses to batch uses on a single stmt after each other.
+ If using an inner FOR_EACH_IMM_USE_ON_STMT iteration only the active
+ use may be manipulated. Safety relies on new immediate uses being
+ inserted at the front of immediate use lists. */
struct imm_use_iterator
{
@@ -53,21 +53,46 @@ struct imm_use_iterator
ssa_use_operand_t *imm_use;
/* This marks the last use in the list (use node from SSA_NAME) */
ssa_use_operand_t *end_p;
- /* This node is inserted and used to mark the end of the uses for a stmt. */
- ssa_use_operand_t iter_node;
+ /* This is the next ssa_name to visit in an outer FOR_EACH_IMM_USE_STMT.
+ Also used for fast imm use iterator checking. */
+ ssa_use_operand_t *next_stmt_use;
/* This is the next ssa_name to visit. IMM_USE may get removed before
the next one is traversed to, so it must be cached early. */
ssa_use_operand_t *next_imm_name;
+ /* This is the SSA name iterated over. */
+ tree name;
};
/* Use this iterator when simply looking at stmts. Adding, deleting or
modifying stmts will cause this iterator to malfunction. */
+#if ! defined ENABLE_GIMPLE_CHECKING
#define FOR_EACH_IMM_USE_FAST(DEST, ITER, SSAVAR) \
for ((DEST) = first_readonly_imm_use (&(ITER), (SSAVAR)); \
!end_readonly_imm_use_p (&(ITER)); \
(void) ((DEST) = next_readonly_imm_use (&(ITER))))
+#else
+
+/* arrange to automatically call, upon descruction, with a given pointer
+ to imm_use_iterator. */
+struct auto_end_imm_use_fast_traverse
+{
+ imm_use_iterator *imm;
+ auto_end_imm_use_fast_traverse (imm_use_iterator *imm)
+ : imm (imm) {}
+ ~auto_end_imm_use_fast_traverse ()
+ { imm->name->ssa_name.fast_iteration_depth--; }
+};
+
+#define FOR_EACH_IMM_USE_FAST(DEST, ITER, SSAVAR) \
+ for (struct auto_end_imm_use_fast_traverse \
+ auto_end_imm_use_fast_traverse \
+ ((((DEST) = first_readonly_imm_use (&(ITER), (SSAVAR))), \
+ &(ITER))); \
+ !end_readonly_imm_use_p (&(ITER)); \
+ (void) ((DEST) = next_readonly_imm_use (&(ITER))))
+#endif
/* Forward declare for use in the class below. */
inline void end_imm_use_stmt_traverse (imm_use_iterator *);
@@ -114,6 +139,11 @@ struct auto_end_imm_use_stmt_traverse
(void) ((DEST) = next_imm_use_on_stmt (&(ITER))))
+/* Use this to get a vector of all gimple stmts using SSAVAR without
+ duplicates. It's cheaper than FOR_EACH_IMM_USE_STMT and has no
+ constraints on what you are allowed to do inside an iteration
+ over the vector. */
+extern auto_vec<gimple *, 2> gather_imm_use_stmts (tree ssavar);
extern bool single_imm_use_1 (const ssa_use_operand_t *head,
use_operand_p *use_p, gimple **stmt);
@@ -245,6 +275,20 @@ delink_imm_use (ssa_use_operand_t *linknode)
if (linknode->prev == NULL)
return;
+#if defined ENABLE_GIMPLE_CHECKING
+ if (linknode->loc.stmt
+ /* update_stmt on constant/removed uses. */
+ && USE_FROM_PTR (linknode)
+ && TREE_CODE (USE_FROM_PTR (linknode)) == SSA_NAME)
+ {
+ tree var = USE_FROM_PTR (linknode);
+ gcc_assert (var->ssa_name.fast_iteration_depth == 0
+ && (var->ssa_name.active_iterated_stmt == NULL
+ || (var->ssa_name.active_iterated_stmt
+ == linknode->loc.stmt)));
+ }
+#endif
+
linknode->prev->next = linknode->next;
linknode->next->prev = linknode->prev;
linknode->prev = NULL;
@@ -343,9 +387,13 @@ end_readonly_imm_use_p (const imm_use_iterator *imm)
inline use_operand_p
first_readonly_imm_use (imm_use_iterator *imm, tree var)
{
+#if defined ENABLE_GIMPLE_CHECKING
+ var->ssa_name.fast_iteration_depth++;
+#endif
imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
imm->imm_use = imm->end_p->next;
- imm->iter_node.next = imm->imm_use->next;
+ imm->next_stmt_use = imm->imm_use->next;
+ imm->name = var;
if (end_readonly_imm_use_p (imm))
return NULL_USE_OPERAND_P;
return imm->imm_use;
@@ -363,8 +411,8 @@ next_readonly_imm_use (imm_use_iterator *imm)
using the SAFE version of the iterator. */
if (flag_checking)
{
- gcc_assert (imm->iter_node.next == old->next);
- imm->iter_node.next = old->next->next;
+ gcc_assert (imm->next_stmt_use == old->next);
+ imm->next_stmt_use = old->next->next;
}
imm->imm_use = old->next;
@@ -840,9 +888,11 @@ end_imm_use_stmt_p (const imm_use_iterator *imm)
placeholder node from the list. */
inline void
-end_imm_use_stmt_traverse (imm_use_iterator *imm)
+end_imm_use_stmt_traverse (imm_use_iterator * ARG_UNUSED (imm))
{
- delink_imm_use (&(imm->iter_node));
+#if defined ENABLE_GIMPLE_CHECKING
+ imm->name->ssa_name.active_iterated_stmt = NULL;
+#endif
}
/* Immediate use traversal of uses within a stmt require that all the
@@ -875,10 +925,11 @@ move_use_after_head (use_operand_p use_p, use_operand_p head,
/* This routine will relink all uses with the same stmt as HEAD into the list
- immediately following HEAD for iterator IMM. */
+ immediately following HEAD for iterator IMM and returns the last use on
+ that stmt. */
-inline void
-link_use_stmts_after (use_operand_p head, imm_use_iterator *imm)
+inline use_operand_p
+link_use_stmts_after (use_operand_p head, imm_use_iterator *)
{
use_operand_p use_p;
use_operand_p last_p = head;
@@ -910,33 +961,34 @@ link_use_stmts_after (use_operand_p head, imm_use_iterator *imm)
last_p = move_use_after_head (use_p, head, last_p);
}
}
- /* Link iter node in after last_p. */
- if (imm->iter_node.prev != NULL)
- delink_imm_use (&imm->iter_node);
- link_imm_use_to_list (&(imm->iter_node), last_p);
+ return last_p;
}
/* Initialize IMM to traverse over uses of VAR. Return the first statement. */
inline gimple *
first_imm_use_stmt (imm_use_iterator *imm, tree var)
{
+#if defined ENABLE_GIMPLE_CHECKING
+ gcc_assert (var->ssa_name.active_iterated_stmt == NULL
+ && var->ssa_name.fast_iteration_depth == 0);
+#endif
imm->end_p = &(SSA_NAME_IMM_USE_NODE (var));
imm->imm_use = imm->end_p->next;
imm->next_imm_name = NULL_USE_OPERAND_P;
- /* iter_node is used as a marker within the immediate use list to indicate
- where the end of the current stmt's uses are. Initialize it to NULL
- stmt and use, which indicates a marker node. */
- imm->iter_node.prev = NULL_USE_OPERAND_P;
- imm->iter_node.next = NULL_USE_OPERAND_P;
- imm->iter_node.loc.stmt = NULL;
- imm->iter_node.use = NULL;
+ /* next_stmt_use is used to point to the immediate use node after
+ the set of uses for the current stmt. */
+ imm->next_stmt_use = NULL_USE_OPERAND_P;
+ imm->name = var;
if (end_imm_use_stmt_p (imm))
return NULL;
- link_use_stmts_after (imm->imm_use, imm);
+ imm->next_stmt_use = link_use_stmts_after (imm->imm_use, imm)->next;
+#if defined ENABLE_GIMPLE_CHECKING
+ var->ssa_name.active_iterated_stmt = USE_STMT (imm->imm_use);
+#endif
return USE_STMT (imm->imm_use);
}
@@ -945,15 +997,14 @@ first_imm_use_stmt (imm_use_iterator *imm, tree var)
inline gimple *
next_imm_use_stmt (imm_use_iterator *imm)
{
- imm->imm_use = imm->iter_node.next;
+ imm->imm_use = imm->next_stmt_use;
if (end_imm_use_stmt_p (imm))
- {
- if (imm->iter_node.prev != NULL)
- delink_imm_use (&imm->iter_node);
- return NULL;
- }
+ return NULL;
- link_use_stmts_after (imm->imm_use, imm);
+#if defined ENABLE_GIMPLE_CHECKING
+ imm->name->ssa_name.active_iterated_stmt = USE_STMT (imm->imm_use);
+#endif
+ imm->next_stmt_use = link_use_stmts_after (imm->imm_use, imm)->next;
return USE_STMT (imm->imm_use);
}
@@ -972,7 +1023,7 @@ first_imm_use_on_stmt (imm_use_iterator *imm)
inline bool
end_imm_use_on_stmt_p (const imm_use_iterator *imm)
{
- return (imm->imm_use == &(imm->iter_node));
+ return (imm->imm_use == imm->next_stmt_use);
}
/* Bump to the next use on the stmt IMM refers to, return NULL if done. */