📄 tree.c
字号:
don't use it. */intchain_member_purpose (elem, chain) tree elem, chain;{ while (chain) { if (elem == TREE_PURPOSE (chain)) return 1; chain = TREE_CHAIN (chain); } return 0;}/* Return the length of a chain of nodes chained through TREE_CHAIN. We expect a null pointer to mark the end of the chain. This is the Lisp primitive `length'. */intlist_length (t) tree t;{ register tree tail; register int len = 0; for (tail = t; tail; tail = TREE_CHAIN (tail)) len++; return len;}/* Concatenate two chains of nodes (chained through TREE_CHAIN) by modifying the last node in chain 1 to point to chain 2. This is the Lisp primitive `nconc'. */treechainon (op1, op2) tree op1, op2;{ if (op1) { register tree t1; register tree t2; for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1)) ; TREE_CHAIN (t1) = op2; for (t2 = op2; t2; t2 = TREE_CHAIN (t2)) if (t2 == t1) abort (); /* Circularity created. */ return op1; } else return op2;}/* Return the last node in a chain of nodes (chained through TREE_CHAIN). */treetree_last (chain) register tree chain;{ register tree next; if (chain) while (next = TREE_CHAIN (chain)) chain = next; return chain;}/* Reverse the order of elements in the chain T, and return the new head of the chain (old last element). */treenreverse (t) tree t;{ register tree prev = 0, decl, next; for (decl = t; decl; decl = next) { next = TREE_CHAIN (decl); TREE_CHAIN (decl) = prev; prev = decl; } return prev;}/* Given a chain CHAIN of tree nodes, construct and return a list of those nodes. */treelistify (chain) tree chain;{ tree result = NULL_TREE; tree in_tail = chain; tree out_tail = NULL_TREE; while (in_tail) { tree next = tree_cons (NULL_TREE, in_tail, NULL_TREE); if (out_tail) TREE_CHAIN (out_tail) = next; else result = next; out_tail = next; in_tail = TREE_CHAIN (in_tail); } return result;}/* Return a newly created TREE_LIST node whose purpose and value fields are PARM and VALUE. */treebuild_tree_list (parm, value) tree parm, value;{ register tree t = make_node (TREE_LIST); TREE_PURPOSE (t) = parm; TREE_VALUE (t) = value; return t;}/* Similar, but build on the temp_decl_obstack. */treebuild_decl_list (parm, value) tree parm, value;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = &temp_decl_obstack; node = build_tree_list (parm, value); current_obstack = ambient_obstack; return node;}/* Similar, but build on the expression_obstack. */treebuild_expr_list (parm, value) tree parm, value;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = expression_obstack; node = build_tree_list (parm, value); current_obstack = ambient_obstack; return node;}/* Return a newly created TREE_LIST node whose purpose and value fields are PARM and VALUE and whose TREE_CHAIN is CHAIN. */treetree_cons (purpose, value, chain) tree purpose, value, chain;{#if 0 register tree node = make_node (TREE_LIST);#else register int i; register tree node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));#ifdef GATHER_STATISTICS tree_node_counts[(int)x_kind]++; tree_node_sizes[(int)x_kind] += sizeof (struct tree_list);#endif for (i = (sizeof (struct tree_common) / sizeof (int)) - 1; i >= 0; i--) ((int *) node)[i] = 0; TREE_SET_CODE (node, TREE_LIST); if (current_obstack == &permanent_obstack) TREE_PERMANENT (node) = 1;#endif TREE_CHAIN (node) = chain; TREE_PURPOSE (node) = purpose; TREE_VALUE (node) = value; return node;}/* Similar, but build on the temp_decl_obstack. */treedecl_tree_cons (purpose, value, chain) tree purpose, value, chain;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = &temp_decl_obstack; node = tree_cons (purpose, value, chain); current_obstack = ambient_obstack; return node;}/* Similar, but build on the expression_obstack. */treeexpr_tree_cons (purpose, value, chain) tree purpose, value, chain;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = expression_obstack; node = tree_cons (purpose, value, chain); current_obstack = ambient_obstack; return node;}/* Same as `tree_cons' but make a permanent object. */treeperm_tree_cons (purpose, value, chain) tree purpose, value, chain;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = &permanent_obstack; node = tree_cons (purpose, value, chain); current_obstack = ambient_obstack; return node;}/* Same as `tree_cons', but make this node temporary, regardless. */treetemp_tree_cons (purpose, value, chain) tree purpose, value, chain;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = &temporary_obstack; node = tree_cons (purpose, value, chain); current_obstack = ambient_obstack; return node;}/* Same as `tree_cons', but save this node if the function's RTL is saved. */treesaveable_tree_cons (purpose, value, chain) tree purpose, value, chain;{ register tree node; register struct obstack *ambient_obstack = current_obstack; current_obstack = saveable_obstack; node = tree_cons (purpose, value, chain); current_obstack = ambient_obstack; return node;}/* Return the size nominally occupied by an object of type TYPE when it resides in memory. The value is measured in units of bytes, and its data type is that normally used for type sizes (which is the first type created by make_signed_type or make_unsigned_type). */treesize_in_bytes (type) tree type;{ tree t; if (type == error_mark_node) return integer_zero_node; type = TYPE_MAIN_VARIANT (type); if (TYPE_SIZE (type) == 0) { incomplete_type_error (NULL_TREE, type); return integer_zero_node; } t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (BITS_PER_UNIT)); if (TREE_CODE (t) == INTEGER_CST) force_fit_type (t, 0); return t;}/* Return the size of TYPE (in bytes) as an integer, or return -1 if the size can vary. */intint_size_in_bytes (type) tree type;{ unsigned int size; if (type == error_mark_node) return 0; type = TYPE_MAIN_VARIANT (type); if (TYPE_SIZE (type) == 0) return -1; if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) return -1; if (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0) { tree t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (BITS_PER_UNIT)); return TREE_INT_CST_LOW (t); } size = TREE_INT_CST_LOW (TYPE_SIZE (type)); return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;}/* Return, as a tree node, the number of elements for TYPE (which is an ARRAY_TYPE) minus one. This counts only elements of the top array. Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup action, they would get unsaved. */treearray_type_nelts (type) tree type;{ tree index_type, min, max; /* If they did it with unspecified bounds, then we should have already given an error about it before we got here. */ if (! TYPE_DOMAIN (type)) return error_mark_node; index_type = TYPE_DOMAIN (type); min = TYPE_MIN_VALUE (index_type); max = TYPE_MAX_VALUE (index_type); if (! TREE_CONSTANT (min)) { STRIP_NOPS (min); if (TREE_CODE (min) == SAVE_EXPR) min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0, SAVE_EXPR_RTL (min)); else min = TYPE_MIN_VALUE (index_type); } if (! TREE_CONSTANT (max)) { STRIP_NOPS (max); if (TREE_CODE (max) == SAVE_EXPR) max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0, SAVE_EXPR_RTL (max)); else max = TYPE_MAX_VALUE (index_type); } return (integer_zerop (min) ? max : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));}/* Return nonzero if arg is static -- a reference to an object in static storage. This is not the same as the C meaning of `static'. */intstaticp (arg) tree arg;{ switch (TREE_CODE (arg)) { case FUNCTION_DECL: /* Nested functions aren't static, since taking their address involves a trampoline. */ return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg); case VAR_DECL: return TREE_STATIC (arg) || DECL_EXTERNAL (arg); case CONSTRUCTOR: return TREE_STATIC (arg); case STRING_CST: return 1; /* If we are referencing a bitfield, we can't evaluate an ADDR_EXPR at compile time and so it isn't a constant. */ case COMPONENT_REF: return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1)) && staticp (TREE_OPERAND (arg, 0))); case BIT_FIELD_REF: return 0;#if 0 /* This case is technically correct, but results in setting TREE_CONSTANT on ADDR_EXPRs that cannot be evaluated at compile time. */ case INDIRECT_REF: return TREE_CONSTANT (TREE_OPERAND (arg, 0));#endif case ARRAY_REF: if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST && TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST) return staticp (TREE_OPERAND (arg, 0)); default: return 0; }}/* Wrap a SAVE_EXPR around EXPR, if appropriate. Do this to any expression which may be used in more than one place, but must be evaluated only once. Normally, expand_expr would reevaluate the expression each time. Calling save_expr produces something that is evaluated and recorded the first time expand_expr is called on it. Subsequent calls to expand_expr just reuse the recorded value. The call to expand_expr that generates code that actually computes the value is the first call *at compile time*. Subsequent calls *at compile time* generate code to use the saved value. This produces correct result provided that *at run time* control always flows through the insns made by the first expand_expr before reaching the other places where the save_expr was evaluated. You, the caller of save_expr, must make sure this is so. Constants, and certain read-only nodes, are returned with no SAVE_EXPR because that is safe. Expressions containing placeholders are not touched; see tree.def for an explanation of what these are used for. */treesave_expr (expr) tree expr;{ register tree t = fold (expr); /* We don't care about whether this can be used as an lvalue in this context. */ while (TREE_CODE (t) == NON_LVALUE_EXPR) t = TREE_OPERAND (t, 0); /* If the tree evaluates to a constant, then we don't want to hide that fact (i.e. this allows further folding, and direct checks for constants). However, a read-only object that has side effects cannot be bypassed. Since it is no problem to reevaluate literals, we just return the literal node. */ if (TREE_CONSTANT (t) || (TREE_READONLY (t) && ! TREE_SIDE_EFFECTS (t)) || TREE_CODE (t) == SAVE_EXPR || TREE_CODE (t) == ERROR_MARK) return t; /* If T contains a PLACEHOLDER_EXPR, we must evaluate it each time, since it means that the size or offset of some field of an object depends on the value within another field. Note that it must not be the case that T contains both a PLACEHOLDER_EXPR and some variable since it would then need to be both evaluated once and evaluated more than once. Front-ends must assure this case cannot happen by surrounding any such subexpressions in their own SAVE_EXPR and forcing evaluation at the proper time. */ if (contains_placeholder_p (t)) return t; t = build (SAVE_EXPR, TREE_TYPE (expr), t, current_function_decl, NULL_TREE); /* This expression might be placed ahead of a jump to ensure that the value was computed on both sides of the jump. So make sure it isn't eliminated as dead. */ TREE_SIDE_EFFECTS (t) = 1; return t;}/* Arrange for an expression to be expanded multiple independent times. This is useful for cleanup actions, as the backend can e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -