📄 tree.c
字号:
/* 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. */treearray_type_nelts (type) tree type;{ tree index_type = TYPE_DOMAIN (type); return (integer_zerop (TYPE_MIN_VALUE (index_type)) ? TYPE_MAX_VALUE (index_type) : fold (build (MINUS_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), TYPE_MAX_VALUE (index_type), TYPE_MIN_VALUE (index_type))));}/* 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; case VAR_DECL: return TREE_STATIC (arg) || DECL_EXTERNAL (arg); case CONSTRUCTOR: return TREE_STATIC (arg); case STRING_CST: return 1; case COMPONENT_REF: case BIT_FIELD_REF: return staticp (TREE_OPERAND (arg, 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)); } 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;}/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size or offset that depends on a field within a record. Note that we only allow such expressions within simple arithmetic or a COND_EXPR. */intcontains_placeholder_p (exp) tree exp;{ register enum tree_code code = TREE_CODE (exp); tree inner; /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR in it since it is supplying a value for it. */ if (code == WITH_RECORD_EXPR) return 0; switch (TREE_CODE_CLASS (code)) { case 'r': for (inner = TREE_OPERAND (exp, 0); TREE_CODE_CLASS (TREE_CODE (inner)) == 'r'; inner = TREE_OPERAND (inner, 0)) ; return TREE_CODE (inner) == PLACEHOLDER_EXPR; case '1': case '2': case '<': case 'e': switch (tree_code_length[(int) code]) { case 1: return contains_placeholder_p (TREE_OPERAND (exp, 0)); case 2: return (code != RTL_EXPR && code != CONSTRUCTOR && ! (code == SAVE_EXPR && SAVE_EXPR_RTL (exp) != 0) && code != WITH_RECORD_EXPR && (contains_placeholder_p (TREE_OPERAND (exp, 0)) || contains_placeholder_p (TREE_OPERAND (exp, 1)))); case 3: return (code == COND_EXPR && (contains_placeholder_p (TREE_OPERAND (exp, 0)) || contains_placeholder_p (TREE_OPERAND (exp, 1)) || contains_placeholder_p (TREE_OPERAND (exp, 2)))); } } return 0;}/* Given a tree EXP, a FIELD_DECL F, and a replacement value R, return a tree with all occurrences of references to F in a PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP contains only arithmetic expressions. */treesubstitute_in_expr (exp, f, r) tree exp; tree f; tree r;{ enum tree_code code = TREE_CODE (exp); tree new = 0; tree inner; switch (TREE_CODE_CLASS (code)) { case 'c': case 'd': return exp; case 'x': if (code == PLACEHOLDER_EXPR) return exp; break; case '1': case '2': case '<': case 'e': switch (tree_code_length[(int) code]) { case 1: new = fold (build1 (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r))); break; case 2: /* An RTL_EXPR cannot contain a PLACEHOLDER_EXPR; a CONSTRUCTOR could, but we don't support it. */ if (code == RTL_EXPR) return exp; else if (code == CONSTRUCTOR) abort (); new = fold (build (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r), substitute_in_expr (TREE_OPERAND (exp, 1), f, r))); break; case 3: /* It cannot be that anything inside a SAVE_EXPR contains a PLACEHOLDER_EXPR. */ if (code == SAVE_EXPR) return exp; if (code != COND_EXPR) abort (); new = fold (build (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r), substitute_in_expr (TREE_OPERAND (exp, 1), f, r), substitute_in_expr (TREE_OPERAND (exp, 2), f, r))); } break; case 'r': switch (code) { case COMPONENT_REF: /* If this expression is getting a value from a PLACEHOLDER_EXPR and it is the right field, replace it with R. */ for (inner = TREE_OPERAND (exp, 0); TREE_CODE_CLASS (TREE_CODE (inner)) == 'r'; inner = TREE_OPERAND (inner, 0)) ; if (TREE_CODE (inner) == PLACEHOLDER_EXPR && TREE_OPERAND (exp, 1) == f) return r; new = fold (build (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r), TREE_OPERAND (exp, 1))); break; case BIT_FIELD_REF: new = fold (build (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r), substitute_in_expr (TREE_OPERAND (exp, 1), f, r), substitute_in_expr (TREE_OPERAND (exp, 2), f, r))); break; case INDIRECT_REF: case BUFFER_REF: new = fold (build1 (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r))); break; case OFFSET_REF: new = fold (build (code, TREE_TYPE (exp), substitute_in_expr (TREE_OPERAND (exp, 0), f, r), substitute_in_expr (TREE_OPERAND (exp, 1), f, r))); break; } } /* If it wasn't one of the cases we handle, give up. */ if (new == 0) abort (); TREE_READONLY (new) = TREE_READONLY (exp); return new;}/* Given a type T, a FIELD_DECL F, and a replacement value R, return a new type with all size expressions that contain F updated by replacing F with R. */treesubstitute_in_type (t, f, r) tree t, f, r;{ switch (TREE_CODE (t)) { case POINTER_TYPE: case VOID_TYPE: return t; case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case CHAR_TYPE: if ((TREE_CODE (TYPE_MIN_VALUE (t)) != INTEGER_CST && contains_placeholder_p (TYPE_MIN_VALUE (t))) || (TREE_CODE (TYPE_MAX_VALUE (t)) != INTEGER_CST && contains_placeholder_p (TYPE_MAX_VALUE (t)))) return build_range_type (t, substitute_in_expr (TYPE_MIN_VALUE (t), f, r), substitute_in_expr (TYPE_MAX_VALUE (t), f, r)); return t; case REAL_TYPE: if ((TYPE_MIN_VALUE (t) != 0 && TREE_CODE (TYPE_MIN_VALUE (t)) != REAL_CST && contains_placeholder_p (TYPE_MIN_VALUE (t))) || (TYPE_MAX_VALUE (t) != 0 && TREE_CODE (TYPE_MAX_VALUE (t)) != REAL_CST && contains_placeholder_p (TYPE_MAX_VALUE (t)))) { t = build_type_copy (t); if (TYPE_MIN_VALUE (t)) TYPE_MIN_VALUE (t) = substitute_in_expr (TYPE_MIN_VALUE (t), f, r); if (TYPE_MAX_VALUE (t)) TYPE_MAX_VALUE (t) = substitute_in_expr (TYPE_MAX_VALUE (t), f, r); } return t; case COMPLEX_TYPE: return build_complex_type (substitute_in_type (TREE_TYPE (t), f, r)); case OFFSET_TYPE: case METHOD_TYPE: case REFERENCE_TYPE: case FILE_TYPE: case SET_TYPE: case FUNCTION_TYPE: case LANG_TYPE: /* Don't know how to do these yet. */ abort (); case ARRAY_TYPE: t = build_array_type (substitute_in_type (TREE_TYPE (t), f, r), substitute_in_type (TYPE_DOMAIN (t), f, r)); TYPE_SIZE (t) = 0; layout_type (t); return t; case RECORD_TYPE: case UNION_TYPE: case QUAL_UNION_TYPE: { tree new = copy_node (t); tree field; tree last_field = 0; /* Start out with no fields, make new fields, and chain them in. */ TYPE_FIELDS (new) = 0; TYPE_SIZE (new) = 0; for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field)) { tree new_field = copy_node (field); TREE_TYPE (new_field) = substitute_in_type (TREE_TYPE (new_field), f, r); /* If this is an ano
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -