diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2015-05-27 18:00:15 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2015-05-27 18:00:15 +0000 |
commit | 8974754f6f12f2f032d4122b06d26319545ced00 (patch) | |
tree | 400932ae2cd83549d10a0b94fb453c26608f0409 /gcc/tree.c | |
parent | e590690ef23053ddbd5b32c119f403f418a02d6a (diff) | |
download | gcc-8974754f6f12f2f032d4122b06d26319545ced00.zip gcc-8974754f6f12f2f032d4122b06d26319545ced00.tar.gz gcc-8974754f6f12f2f032d4122b06d26319545ced00.tar.bz2 |
expr.h (array_at_struct_end_p): Move to...
* expr.h (array_at_struct_end_p): Move to...
(array_ref_element_size): Likewise.
(component_ref_field_offset): Likewise.
* tree.h (array_ref_element_size): ...here.
(array_at_struct_end_p): Likewise.
(component_ref_field_offset): Likewise.
* expr.c (array_ref_element_size): Move to...
(array_ref_low_bound): Likewise.
(array_at_struct_end_p): Likewise.
(array_ref_up_bound): Likewise.
(component_ref_field_offset): Likewise.
* tree.c (array_ref_element_size): ...here.
(array_ref_low_bound): Likewise.
(array_ref_up_bound): Likewise.
(array_at_struct_end_p): Likewise.
(component_ref_field_offset): Likewise.
From-SVN: r223768
Diffstat (limited to 'gcc/tree.c')
-rw-r--r-- | gcc/tree.c | 137 |
1 files changed, 135 insertions, 2 deletions
@@ -24,8 +24,8 @@ along with GCC; see the file COPYING3. If not see tables index by tree code that describe how to take apart nodes of that code. - It is intended to be language-independent, but occasionally - calls language-dependent routines defined (for C) in typecheck.c. */ + It is intended to be language-independent but can occasionally + calls language-dependent routines. */ #include "config.h" #include "system.h" @@ -12453,6 +12453,139 @@ get_base_address (tree t) return t; } +/* Return a tree of sizetype representing the size, in bytes, of the element + of EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ + +tree +array_ref_element_size (tree exp) +{ + tree aligned_size = TREE_OPERAND (exp, 3); + tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))); + location_t loc = EXPR_LOCATION (exp); + + /* If a size was specified in the ARRAY_REF, it's the size measured + in alignment units of the element type. So multiply by that value. */ + if (aligned_size) + { + /* ??? tree_ssa_useless_type_conversion will eliminate casts to + sizetype from another type of the same width and signedness. */ + if (TREE_TYPE (aligned_size) != sizetype) + aligned_size = fold_convert_loc (loc, sizetype, aligned_size); + return size_binop_loc (loc, MULT_EXPR, aligned_size, + size_int (TYPE_ALIGN_UNIT (elmt_type))); + } + + /* Otherwise, take the size from that of the element type. Substitute + any PLACEHOLDER_EXPR that we have. */ + else + return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_SIZE_UNIT (elmt_type), exp); +} + +/* Return a tree representing the lower bound of the array mentioned in + EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ + +tree +array_ref_low_bound (tree exp) +{ + tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0))); + + /* If a lower bound is specified in EXP, use it. */ + if (TREE_OPERAND (exp, 2)) + return TREE_OPERAND (exp, 2); + + /* Otherwise, if there is a domain type and it has a lower bound, use it, + substituting for a PLACEHOLDER_EXPR as needed. */ + if (domain_type && TYPE_MIN_VALUE (domain_type)) + return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MIN_VALUE (domain_type), exp); + + /* Otherwise, return a zero of the appropriate type. */ + return build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0); +} + +/* Return a tree representing the upper bound of the array mentioned in + EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */ + +tree +array_ref_up_bound (tree exp) +{ + tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0))); + + /* If there is a domain type and it has an upper bound, use it, substituting + for a PLACEHOLDER_EXPR as needed. */ + if (domain_type && TYPE_MAX_VALUE (domain_type)) + return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp); + + /* Otherwise fail. */ + return NULL_TREE; +} + +/* Returns true if REF is an array reference to an array at the end of + a structure. If this is the case, the array may be allocated larger + than its upper bound implies. */ + +bool +array_at_struct_end_p (tree ref) +{ + if (TREE_CODE (ref) != ARRAY_REF + && TREE_CODE (ref) != ARRAY_RANGE_REF) + return false; + + while (handled_component_p (ref)) + { + /* If the reference chain contains a component reference to a + non-union type and there follows another field the reference + is not at the end of a structure. */ + if (TREE_CODE (ref) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE) + { + tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1)); + while (nextf && TREE_CODE (nextf) != FIELD_DECL) + nextf = DECL_CHAIN (nextf); + if (nextf) + return false; + } + + ref = TREE_OPERAND (ref, 0); + } + + /* If the reference is based on a declared entity, the size of the array + is constrained by its given domain. */ + if (DECL_P (ref)) + return false; + + return true; +} + +/* Return a tree representing the offset, in bytes, of the field referenced + by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */ + +tree +component_ref_field_offset (tree exp) +{ + tree aligned_offset = TREE_OPERAND (exp, 2); + tree field = TREE_OPERAND (exp, 1); + location_t loc = EXPR_LOCATION (exp); + + /* If an offset was specified in the COMPONENT_REF, it's the offset measured + in units of DECL_OFFSET_ALIGN / BITS_PER_UNIT. So multiply by that + value. */ + if (aligned_offset) + { + /* ??? tree_ssa_useless_type_conversion will eliminate casts to + sizetype from another type of the same width and signedness. */ + if (TREE_TYPE (aligned_offset) != sizetype) + aligned_offset = fold_convert_loc (loc, sizetype, aligned_offset); + return size_binop_loc (loc, MULT_EXPR, aligned_offset, + size_int (DECL_OFFSET_ALIGN (field) + / BITS_PER_UNIT)); + } + + /* Otherwise, take the offset from that of the field. Substitute + any PLACEHOLDER_EXPR that we have. */ + else + return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp); +} + /* Return the machine mode of T. For vectors, returns the mode of the inner type. The main use case is to feed the result to HONOR_NANS, avoiding the BLKmode that a direct TYPE_MODE (T) might return. */ |