📄 tree.c
字号:
if (t1 == t2) return 1; if (t1 == 0 || t2 == 0) return 0; if (TREE_CODE (t1) == INTEGER_CST && TREE_CODE (t2) == INTEGER_CST && TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2) && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2)) return 1; return 0;}/* Nonzero if integer constants T1 and T2 represent values that satisfy <. The precise way of comparison depends on their data type. */inttree_int_cst_lt (t1, t2) tree t1, t2;{ if (t1 == t2) return 0; if (!TREE_UNSIGNED (TREE_TYPE (t1))) return INT_CST_LT (t1, t2); return INT_CST_LT_UNSIGNED (t1, t2);}/* Compare two constructor-element-type constants. */intsimple_cst_equal (t1, t2) tree t1, t2;{ register enum tree_code code1, code2; if (t1 == t2) return 1; if (t1 == 0 || t2 == 0) return 0; code1 = TREE_CODE (t1); code2 = TREE_CODE (t2); if (code1 == NOP_EXPR || code1 == CONVERT_EXPR) if (code2 == NOP_EXPR || code2 == CONVERT_EXPR) return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); else return simple_cst_equal (TREE_OPERAND (t1, 0), t2); else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR) return simple_cst_equal (t1, TREE_OPERAND (t2, 0)); if (code1 != code2) return 0; switch (code1) { case INTEGER_CST: return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2) && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2); case REAL_CST: return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2)); case STRING_CST: return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2) && !strcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2)); case CONSTRUCTOR: abort (); case VAR_DECL: case PARM_DECL: case CONST_DECL: return 0; case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR: case LSHIFT_EXPR: case RSHIFT_EXPR: return (simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)) && simple_cst_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1))); case NEGATE_EXPR: case ADDR_EXPR: case REFERENCE_EXPR: case INDIRECT_REF: return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0)); default: abort (); }}/* Constructors for pointer, array and function types. (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are constructed by language-dependent code, not here.) *//* Construct, lay out and return the type of pointers to TO_TYPE. If such a type has already been constructed, reuse it. */treebuild_pointer_type (to_type) tree to_type;{ register tree t = TYPE_POINTER_TO (to_type); register struct obstack *ambient_obstack = current_obstack; register struct obstack *ambient_saveable_obstack = saveable_obstack; /* First, if we already have a type for pointers to TO_TYPE, use it. */ if (t) return t; /* We need a new one. If TO_TYPE is permanent, make this permanent too. */ if (TREE_PERMANENT (to_type)) { current_obstack = &permanent_obstack; saveable_obstack = &permanent_obstack; } t = make_node (POINTER_TYPE); TREE_TYPE (t) = to_type; /* Record this type as the pointer to TO_TYPE. */ TYPE_POINTER_TO (to_type) = t; /* Lay out the type. This function has many callers that are concerned with expression-construction, and this simplifies them all. Also, it guarantees the TYPE_SIZE is permanent if the type is. */ layout_type (t); current_obstack = ambient_obstack; saveable_obstack = ambient_saveable_obstack; return t;}/* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE. MAXVAL should be the maximum value in the domain (one less than the length of the array). */treebuild_index_type (maxval) tree maxval;{ register tree itype = make_node (INTEGER_TYPE); TYPE_PRECISION (itype) = BITS_PER_WORD; TYPE_MIN_VALUE (itype) = build_int_2 (0, 0); TREE_TYPE (TYPE_MIN_VALUE (itype)) = sizetype; TYPE_MAX_VALUE (itype) = convert (sizetype, maxval); TYPE_MODE (itype) = SImode; TYPE_SIZE (itype) = TYPE_SIZE (sizetype); TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype); TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype); if (TREE_CODE (maxval) == INTEGER_CST) { int maxint = TREE_INT_CST_LOW (maxval); return type_hash_canon (maxint > 0 ? maxint : - maxint, itype); } else return itype;}/* Construct, lay out and return the type of arrays of elements with ELT_TYPE and number of elements specified by the range of values of INDEX_TYPE. If such a type has already been constructed, reuse it. */treebuild_array_type (elt_type, index_type) tree elt_type, index_type;{ register tree t = make_node (ARRAY_TYPE); int hashcode; if (TREE_CODE (elt_type) == FUNCTION_TYPE) { error ("arrays of functions are not meaningful"); elt_type = integer_type_node; } TREE_TYPE (t) = elt_type; TYPE_DOMAIN (t) = index_type; /* Make sure TYPE_POINTER_TO (elt_type) is filled in. */ build_pointer_type (elt_type);#if 0 /* Also that of the main variant, which is the type the element will have. */ build_pointer_type (TYPE_MAIN_VARIANT (elt_type));#endif if (index_type == 0) return t; hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type); t = type_hash_canon (hashcode, t); if (TYPE_SIZE (t) == 0) layout_type (t); return t;}/* Construct, lay out and return the type of functions returning type VALUE_TYPE given arguments of types ARG_TYPES. ARG_TYPES is a chain of TREE_LIST nodes whose TREE_VALUEs are data type nodes for the arguments of the function. If such a type has already been constructed, reuse it. */treebuild_function_type (value_type, arg_types) tree value_type, arg_types;{ register tree t; int hashcode; if (TREE_CODE (value_type) == FUNCTION_TYPE || TREE_CODE (value_type) == ARRAY_TYPE) { error ("function return type cannot be function or array"); value_type = integer_type_node; } /* Make a node of the sort we want. */ t = make_node (FUNCTION_TYPE); TREE_TYPE (t) = value_type; TYPE_ARG_TYPES (t) = arg_types; /* If we already have such a type, use the old one and free this one. */ hashcode = TYPE_HASH (value_type) + type_hash_list (arg_types); t = type_hash_canon (hashcode, t); if (TYPE_SIZE (t) == 0) layout_type (t); return t;}/* Build the node for the type of references-to-TO_TYPE. */treebuild_reference_type (to_type) tree to_type;{ register tree t = TYPE_REFERENCE_TO (to_type); register struct obstack *ambient_obstack = current_obstack; register struct obstack *ambient_saveable_obstack = saveable_obstack; /* First, if we already have a type for pointers to TO_TYPE, use it. */ if (t) return t; /* We need a new one. If TO_TYPE is permanent, make this permanent too. */ if (TREE_PERMANENT (to_type)) { current_obstack = &permanent_obstack; saveable_obstack = &permanent_obstack; } t = make_node (REFERENCE_TYPE); TREE_TYPE (t) = to_type; /* Record this type as the pointer to TO_TYPE. */ TYPE_REFERENCE_TO (to_type) = t; layout_type (t); current_obstack = ambient_obstack; saveable_obstack = ambient_saveable_obstack; return t;}/* Construct, lay out and return the type of methods belonging to class BASETYPE and whose arguments and values are described by TYPE. If that type exists already, reuse it. TYPE must be a FUNCTION_TYPE node. */treebuild_method_type (basetype, type) tree basetype, type;{ register tree t; int hashcode; /* Make a node of the sort we want. */ t = make_node (METHOD_TYPE); if (TREE_CODE (type) != FUNCTION_TYPE) abort (); TYPE_METHOD_BASETYPE (t) = basetype; TREE_TYPE (t) = TREE_TYPE (type); /* The actual arglist for this function includes a "hidden" argument which is "this". Put it into the list of argument types. */ TYPE_ARG_TYPES (t) = tree_cons (NULL, build_pointer_type (basetype), TYPE_ARG_TYPES (type)); /* If we already have such a type, use the old one and free this one. */ hashcode = TYPE_HASH (basetype) + TYPE_HASH (type); t = type_hash_canon (hashcode, t); if (TYPE_SIZE (t) == 0) layout_type (t); return t;}/* Construct, lay out and return the type of methods belonging to class BASETYPE and whose arguments and values are described by TYPE. If that type exists already, reuse it. TYPE must be a FUNCTION_TYPE node. */treebuild_offset_type (basetype, type) tree basetype, type;{ register tree t; int hashcode; /* Make a node of the sort we want. */ t = make_node (OFFSET_TYPE); TYPE_OFFSET_BASETYPE (t) = basetype; TREE_TYPE (t) = type; /* If we already have such a type, use the old one and free this one. */ hashcode = TYPE_HASH (basetype) + TYPE_HASH (type); t = type_hash_canon (hashcode, t); if (TYPE_SIZE (t) == 0) layout_type (t); return t;}/* Return OP, stripped of any conversions to wider types as much as is safe. Converting the value back to OP's type makes a value equivalent to OP. If FOR_TYPE is nonzero, we return a value which, if converted to type FOR_TYPE, would be equivalent to converting OP to type FOR_TYPE. If FOR_TYPE is nonzero, unaligned bit-field references may be changed to the narrowest type that can hold the value, even if they don't exactly fit. Otherwise, bit-field references are changed to a narrower type only if they can be fetched directly from memory in that type. OP must have integer, real or enumeral type. Pointers are not allowed! There are some cases where the obvious value we could return would regenerate to OP if converted to OP's type, but would not extend like OP to wider types. If FOR_TYPE indicates such extension is contemplated, we eschew such values. For example, if OP is (unsigned short)(signed char)-1, we avoid returning (signed char)-1 if FOR_TYPE is int, even though extending that to an unsigned short would regenerate OP, since the result of extending (signed char)-1 to (int) is different from (int) OP. */treeget_unwidened (op, for_type) register tree op; tree for_type;{ /* Set UNS initially if converting OP to FOR_TYPE is a zero-extension. */ /* TYPE_PRECISION is safe in place of type_precision since pointer types are not allowed. */ register tree type = TREE_TYPE (op); register int final_prec = TYPE_PRECISION (for_type != 0 ? for_type : type); register int uns = (for_type != 0 && for_type != type && final_prec > TYPE_PRECISION (type) && TREE_UNSIGNED (type)); register tree win = op; while (TREE_CODE (op) == NOP_EXPR) { register int bitschange = TYPE_PRECISION (TREE_TYPE (op)) - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0))); /* Truncations are many-one so cannot be removed. Unless we are later going to truncate down even farther. */ if (bitschange < 0 && final_prec > TYPE_PRECISION (TREE_TYPE (op))) break; /* See what's inside this conversion. If we decide to strip it, we will set WIN. */ op = TREE_OPERAND (op, 0); /* If we have not stripped any zero-extensions (uns is 0), we can strip any kind of extension. If we have previously stripped a zero-extension, only zero-extensions can safely be stripped. Any extension can be stripped if the bits it would produce are all going to be discarded later by truncating to FOR_TYPE. */ if (bitschange > 0) { if (! uns || final_prec <= TYPE_PRECISION (TREE_TYPE (op))) win = op; /* TREE_UNSIGNED says whether this is a zero-extension. Let's avoid computing it if it does not affect WIN and if UNS will not be needed again. */ if ((uns || TREE_CODE (op) == NOP_EXPR) && TREE_UNSIGNED (TREE_TYPE (op))) { uns = 1; win = op; } } } if (TREE_CODE (op) == COMPONENT_REF /* Since type_for_size always gives an integer type. */ && TREE_CODE (type) != REAL_TYPE) { int innerprec = (TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1))) * DECL_SIZE_UNIT (TREE_OPERAND (op, 1))); type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1))); /* We can get this structure field in the narrowest type it fits in. If FOR_TYPE is 0, do this only for a field that matches the narrower type exactly and is aligned for it (i.e. mode isn't BI). The resulting extension to its nominal type (a fullword type) must fit the same conditions as for other extensions. */ if (innerprec < TYPE_PRECISION (TREE_TYPE (op)) && (for_type || DECL_MODE (TREE_OPERAND (op, 1)) != BImode) && (! uns || final_prec <= innerprec || TREE_UNSIGNED (TREE_OPERAND (op, 1))) && type != 0) { win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0), TREE_OPERAND (op, 1)); TREE_VOLATILE (win) = TREE_VOLATILE (op); TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op); } } return win;}/* Return OP or a simpler expression for a narrower value which can be sign-extended or zero-extended to give back OP. Store in *UNSIGNEDP_PTR either 1 if the value should be zero-extended or 0 if the value should be sign-extended. */treeget_narrower (op, unsignedp_ptr) register tree op; int *unsignedp_ptr;{ register int uns = 0; int first = 1; register tree win = op; while (TREE_CODE (op) == NOP_EXPR) { register int bitschange = TYPE_PRECISION (TREE_TYPE (op)) - TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op, 0))); /* Truncations are many-one so cannot be removed. */ if (bitschange < 0) break; /* See what's inside this conversion. If we decide to strip it, we will set WIN. */ op = TREE_OPERAND (op, 0); if (bitschange > 0) { /* An extension: the outermost one can be stripped, but remember whether it is zero or sign extension. */ if (first) uns = TREE_UNSIGNED (TREE_TYPE (op)); /* Otherwise, if a sign extension has been stripped, only sign extensions can now be stripped; if a zero extension has been stripped, only zero-extensions. */ else if (uns != TREE_UNSIGNED (TREE_TYPE (op))) break; first = 0; } /* A change in nominal type can always be stripped. */ win = op; } if (TREE_CODE (op) == COMPONENT_REF /* Since type_for_size always gives an integer type. */ && TREE_CODE (TREE_TYPE (op)) != REAL_TYPE) { int innerprec = (TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1))) * DECL_SIZE_UNIT (TREE_OPERAND (op, 1))); tree type = type_for_size (innerprec, TREE_UNSIGNED (op)); /* We can get this structure field in a narrower type that fits it, but the resulting extension to its nominal type (a fullword type) must satisfy the same conditions as for other extensions. Do this only for fields that are aligned (not BImode), because when bit-field insns will be used there is no advantage in doing this. */ if (innerprec < TYPE_PRECISION (TREE_TYPE (op)) && DECL_MODE (TREE_OPERAND (op, 1)) != BImode && (first || uns == TREE_UNSIGNED (TREE_OPERAND (op, 1))) && type != 0) { if (first) uns = TREE_UNSIGNED (TREE_OPERAND (op, 1)); win = build (COMPONENT_REF, type, TREE_OPERAND (op, 0), TREE_OPERAND (op, 1)); TREE_VOLATILE (win) = TREE_VOLATILE (op); TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op); } } *unsignedp_ptr = uns; return win;}/* Return the precision of a type, for arithmetic purposes. Supports all types on which arithmetic is possible (including pointer types). It's not clear yet what will be right for complex types. */inttype_precision (type) register tree type;{ return ((TREE_CODE (type) == INTEGER_TYPE || TREE_CODE (type) == ENUMERAL_TYPE || TREE_CODE (type) == REAL_TYPE) ? TYPE_PRECISION (type) : POINTER_SIZE);}/* Nonzero if integer constant C has a value that is permissible for type TYPE (an INTEGER_TYPE). */intint_fits_type_p (c, type) tree c, type;{ if (TREE_UNSIGNED (type)) return (!INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c) && !INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type))); else return (!INT_CST_LT (TYPE_MAX_VALUE (type), c) && !INT_CST_LT (c, TYPE_MIN_VALUE (type)));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -