aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorSteven Bosscher <stevenb@suse.de>2005-03-16 09:01:20 +0000
committerSteven Bosscher <steven@gcc.gnu.org>2005-03-16 09:01:20 +0000
commitb8c4a565c9b541d9568c1cba2e8266fc5c37113f (patch)
tree7d0846344b21a0fe0edc3c81ec37ab803a4731fc /gcc/tree.c
parenta1286ef574be4a388b14de74a406dc60391a8b91 (diff)
downloadgcc-b8c4a565c9b541d9568c1cba2e8266fc5c37113f.zip
gcc-b8c4a565c9b541d9568c1cba2e8266fc5c37113f.tar.gz
gcc-b8c4a565c9b541d9568c1cba2e8266fc5c37113f.tar.bz2
tree-inline.c (walk_type_fields, [...]): Move from here...
* tree-inline.c (walk_type_fields, walk_tree, walk_tree_without_duplicates): Move from here... * tree.c: ...to here. From-SVN: r96550
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index b1c2458..1500349 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -49,6 +49,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "basic-block.h"
#include "tree-flow.h"
#include "params.h"
+#include "pointer-set.h"
/* Each tree code class has an associated string representation.
These must correspond to the tree_code_class entries. */
@@ -6406,4 +6407,355 @@ num_ending_zeros (tree x)
return build_int_cst_type (type, num);
}
+
+#define WALK_SUBTREE(NODE) \
+ do \
+ { \
+ result = walk_tree (&(NODE), func, data, pset); \
+ if (result) \
+ return result; \
+ } \
+ while (0)
+
+/* This is a subroutine of walk_tree that walks field of TYPE that are to
+ be walked whenever a type is seen in the tree. Rest of operands and return
+ value are as for walk_tree. */
+
+static tree
+walk_type_fields (tree type, walk_tree_fn func, void *data,
+ struct pointer_set_t *pset)
+{
+ tree result = NULL_TREE;
+
+ switch (TREE_CODE (type))
+ {
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* We have to worry about mutually recursive pointers. These can't
+ be written in C. They can in Ada. It's pathological, but
+ there's an ACATS test (c38102a) that checks it. Deal with this
+ by checking if we're pointing to another pointer, that one
+ points to another pointer, that one does too, and we have no htab.
+ If so, get a hash table. We check three levels deep to avoid
+ the cost of the hash table if we don't need one. */
+ if (POINTER_TYPE_P (TREE_TYPE (type))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (type)))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (type))))
+ && !pset)
+ {
+ result = walk_tree_without_duplicates (&TREE_TYPE (type),
+ func, data);
+ if (result)
+ return result;
+
+ break;
+ }
+
+ /* ... fall through ... */
+
+ case COMPLEX_TYPE:
+ WALK_SUBTREE (TREE_TYPE (type));
+ break;
+
+ case METHOD_TYPE:
+ WALK_SUBTREE (TYPE_METHOD_BASETYPE (type));
+
+ /* Fall through. */
+
+ case FUNCTION_TYPE:
+ WALK_SUBTREE (TREE_TYPE (type));
+ {
+ tree arg;
+
+ /* We never want to walk into default arguments. */
+ for (arg = TYPE_ARG_TYPES (type); arg; arg = TREE_CHAIN (arg))
+ WALK_SUBTREE (TREE_VALUE (arg));
+ }
+ break;
+
+ case ARRAY_TYPE:
+ /* Don't follow this nodes's type if a pointer for fear that we'll
+ have infinite recursion. Those types are uninteresting anyway. */
+ if (!POINTER_TYPE_P (TREE_TYPE (type))
+ && TREE_CODE (TREE_TYPE (type)) != OFFSET_TYPE)
+ WALK_SUBTREE (TREE_TYPE (type));
+ WALK_SUBTREE (TYPE_DOMAIN (type));
+ break;
+
+ case BOOLEAN_TYPE:
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case CHAR_TYPE:
+ case REAL_TYPE:
+ WALK_SUBTREE (TYPE_MIN_VALUE (type));
+ WALK_SUBTREE (TYPE_MAX_VALUE (type));
+ break;
+
+ case OFFSET_TYPE:
+ WALK_SUBTREE (TREE_TYPE (type));
+ WALK_SUBTREE (TYPE_OFFSET_BASETYPE (type));
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+/* Apply FUNC to all the sub-trees of TP in a pre-order traversal. FUNC is
+ called with the DATA and the address of each sub-tree. If FUNC returns a
+ non-NULL value, the traversal is aborted, and the value returned by FUNC
+ is returned. If PSET is non-NULL it is used to record the nodes visited,
+ and to avoid visiting a node more than once. */
+
+tree
+walk_tree (tree *tp, walk_tree_fn func, void *data, struct pointer_set_t *pset)
+{
+ enum tree_code code;
+ int walk_subtrees;
+ tree result;
+
+#define WALK_SUBTREE_TAIL(NODE) \
+ do \
+ { \
+ tp = & (NODE); \
+ goto tail_recurse; \
+ } \
+ while (0)
+
+ tail_recurse:
+ /* Skip empty subtrees. */
+ if (!*tp)
+ return NULL_TREE;
+
+ /* Don't walk the same tree twice, if the user has requested
+ that we avoid doing so. */
+ if (pset && pointer_set_insert (pset, *tp))
+ return NULL_TREE;
+
+ /* Call the function. */
+ walk_subtrees = 1;
+ result = (*func) (tp, &walk_subtrees, data);
+
+ /* If we found something, return it. */
+ if (result)
+ return result;
+
+ code = TREE_CODE (*tp);
+
+ /* Even if we didn't, FUNC may have decided that there was nothing
+ interesting below this point in the tree. */
+ if (!walk_subtrees)
+ {
+ if (code == TREE_LIST)
+ /* But we still need to check our siblings. */
+ WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
+ else
+ return NULL_TREE;
+ }
+
+ result = lang_hooks.tree_inlining.walk_subtrees (tp, &walk_subtrees, func,
+ data, pset);
+ if (result || ! walk_subtrees)
+ return result;
+
+ /* If this is a DECL_EXPR, walk into various fields of the type that it's
+ defining. We only want to walk into these fields of a type in this
+ case. Note that decls get walked as part of the processing of a
+ BIND_EXPR.
+
+ ??? Precisely which fields of types that we are supposed to walk in
+ this case vs. the normal case aren't well defined. */
+ if (code == DECL_EXPR
+ && TREE_CODE (DECL_EXPR_DECL (*tp)) == TYPE_DECL
+ && TREE_CODE (TREE_TYPE (DECL_EXPR_DECL (*tp))) != ERROR_MARK)
+ {
+ tree *type_p = &TREE_TYPE (DECL_EXPR_DECL (*tp));
+
+ /* Call the function for the type. See if it returns anything or
+ doesn't want us to continue. If we are to continue, walk both
+ the normal fields and those for the declaration case. */
+ result = (*func) (type_p, &walk_subtrees, data);
+ if (result || !walk_subtrees)
+ return NULL_TREE;
+
+ result = walk_type_fields (*type_p, func, data, pset);
+ if (result)
+ return result;
+
+ WALK_SUBTREE (TYPE_SIZE (*type_p));
+ WALK_SUBTREE (TYPE_SIZE_UNIT (*type_p));
+
+ /* If this is a record type, also walk the fields. */
+ if (TREE_CODE (*type_p) == RECORD_TYPE
+ || TREE_CODE (*type_p) == UNION_TYPE
+ || TREE_CODE (*type_p) == QUAL_UNION_TYPE)
+ {
+ tree field;
+
+ for (field = TYPE_FIELDS (*type_p); field;
+ field = TREE_CHAIN (field))
+ {
+ /* We'd like to look at the type of the field, but we can easily
+ get infinite recursion. So assume it's pointed to elsewhere
+ in the tree. Also, ignore things that aren't fields. */
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ WALK_SUBTREE (DECL_FIELD_OFFSET (field));
+ WALK_SUBTREE (DECL_SIZE (field));
+ WALK_SUBTREE (DECL_SIZE_UNIT (field));
+ if (TREE_CODE (*type_p) == QUAL_UNION_TYPE)
+ WALK_SUBTREE (DECL_QUALIFIER (field));
+ }
+ }
+ }
+
+ else if (code != SAVE_EXPR
+ && code != BIND_EXPR
+ && IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+ {
+ int i, len;
+
+ /* Walk over all the sub-trees of this operand. */
+ len = TREE_CODE_LENGTH (code);
+ /* TARGET_EXPRs are peculiar: operands 1 and 3 can be the same.
+ But, we only want to walk once. */
+ if (code == TARGET_EXPR
+ && TREE_OPERAND (*tp, 3) == TREE_OPERAND (*tp, 1))
+ --len;
+
+ /* Go through the subtrees. We need to do this in forward order so
+ that the scope of a FOR_EXPR is handled properly. */
+#ifdef DEBUG_WALK_TREE
+ for (i = 0; i < len; ++i)
+ WALK_SUBTREE (TREE_OPERAND (*tp, i));
+#else
+ for (i = 0; i < len - 1; ++i)
+ WALK_SUBTREE (TREE_OPERAND (*tp, i));
+
+ if (len)
+ {
+ /* The common case is that we may tail recurse here. */
+ if (code != BIND_EXPR
+ && !TREE_CHAIN (*tp))
+ WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, len - 1));
+ else
+ WALK_SUBTREE (TREE_OPERAND (*tp, len - 1));
+ }
+#endif
+ }
+
+ /* If this is a type, walk the needed fields in the type. */
+ else if (TYPE_P (*tp))
+ {
+ result = walk_type_fields (*tp, func, data, pset);
+ if (result)
+ return result;
+ }
+ else
+ {
+ /* Not one of the easy cases. We must explicitly go through the
+ children. */
+ switch (code)
+ {
+ case ERROR_MARK:
+ case IDENTIFIER_NODE:
+ case INTEGER_CST:
+ case REAL_CST:
+ case VECTOR_CST:
+ case STRING_CST:
+ case BLOCK:
+ case PLACEHOLDER_EXPR:
+ case SSA_NAME:
+ case FIELD_DECL:
+ case RESULT_DECL:
+ /* None of thse have subtrees other than those already walked
+ above. */
+ break;
+
+ case TREE_LIST:
+ WALK_SUBTREE (TREE_VALUE (*tp));
+ WALK_SUBTREE_TAIL (TREE_CHAIN (*tp));
+ break;
+
+ case TREE_VEC:
+ {
+ int len = TREE_VEC_LENGTH (*tp);
+
+ if (len == 0)
+ break;
+
+ /* Walk all elements but the first. */
+ while (--len)
+ WALK_SUBTREE (TREE_VEC_ELT (*tp, len));
+
+ /* Now walk the first one as a tail call. */
+ WALK_SUBTREE_TAIL (TREE_VEC_ELT (*tp, 0));
+ }
+
+ case COMPLEX_CST:
+ WALK_SUBTREE (TREE_REALPART (*tp));
+ WALK_SUBTREE_TAIL (TREE_IMAGPART (*tp));
+
+ case CONSTRUCTOR:
+ WALK_SUBTREE_TAIL (CONSTRUCTOR_ELTS (*tp));
+
+ case SAVE_EXPR:
+ WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
+
+ case BIND_EXPR:
+ {
+ tree decl;
+ for (decl = BIND_EXPR_VARS (*tp); decl; decl = TREE_CHAIN (decl))
+ {
+ /* Walk the DECL_INITIAL and DECL_SIZE. We don't want to walk
+ into declarations that are just mentioned, rather than
+ declared; they don't really belong to this part of the tree.
+ And, we can see cycles: the initializer for a declaration
+ can refer to the declaration itself. */
+ WALK_SUBTREE (DECL_INITIAL (decl));
+ WALK_SUBTREE (DECL_SIZE (decl));
+ WALK_SUBTREE (DECL_SIZE_UNIT (decl));
+ }
+ WALK_SUBTREE_TAIL (BIND_EXPR_BODY (*tp));
+ }
+
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator i;
+ for (i = tsi_start (*tp); !tsi_end_p (i); tsi_next (&i))
+ WALK_SUBTREE (*tsi_stmt_ptr (i));
+ }
+ break;
+
+ default:
+ /* ??? This could be a language-defined node. We really should make
+ a hook for it, but right now just ignore it. */
+ break;
+ }
+ }
+
+ /* We didn't find what we were looking for. */
+ return NULL_TREE;
+
+#undef WALK_SUBTREE_TAIL
+}
+#undef WALK_SUBTREE
+
+/* Like walk_tree, but does not walk duplicate nodes more than once. */
+
+tree
+walk_tree_without_duplicates (tree *tp, walk_tree_fn func, void *data)
+{
+ tree result;
+ struct pointer_set_t *pset;
+
+ pset = pointer_set_create ();
+ result = walk_tree (tp, func, data, pset);
+ pointer_set_destroy (pset);
+ return result;
+}
+
#include "gt-tree.h"