diff options
Diffstat (limited to 'gcc/expr.c')
-rw-r--r-- | gcc/expr.c | 83 |
1 files changed, 69 insertions, 14 deletions
@@ -5591,15 +5591,13 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, else if (TREE_CODE (exp) == COMPONENT_REF) { tree field = TREE_OPERAND (exp, 1); - tree this_offset = DECL_FIELD_OFFSET (field); + tree this_offset = component_ref_field_offset (exp); /* If this field hasn't been filled in yet, don't go past it. This should only happen when folding expressions made during type construction. */ if (this_offset == 0) break; - else - this_offset = SUBSTITUTE_PLACEHOLDER_IN_EXPR (this_offset, exp); offset = size_binop (PLUS_EXPR, offset, this_offset); bit_offset = size_binop (PLUS_EXPR, bit_offset, @@ -5612,23 +5610,17 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, || TREE_CODE (exp) == ARRAY_RANGE_REF) { tree index = TREE_OPERAND (exp, 1); - tree array = TREE_OPERAND (exp, 0); - tree domain = TYPE_DOMAIN (TREE_TYPE (array)); - tree low_bound = (domain ? TYPE_MIN_VALUE (domain) : 0); - tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array))); + tree low_bound = array_ref_low_bound (exp); + tree unit_size = array_ref_element_size (exp); /* We assume all arrays have sizes that are a multiple of a byte. First subtract the lower bound, if any, in the type of the index, then convert to sizetype and multiply by the size of the array element. */ - if (low_bound != 0 && ! integer_zerop (low_bound)) + if (! integer_zerop (low_bound)) index = fold (build (MINUS_EXPR, TREE_TYPE (index), index, low_bound)); - /* If the index has a self-referential type, instantiate it with - the object; likewise for the component size. */ - index = SUBSTITUTE_PLACEHOLDER_IN_EXPR (index, exp); - unit_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (unit_size, array); offset = size_binop (PLUS_EXPR, offset, size_binop (MULT_EXPR, convert (sizetype, index), @@ -5676,6 +5668,70 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize, return exp; } +/* Return a tree of sizetype representing the size, in bytes, of the element + of EXP, an ARRAY_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))); + + /* 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) + return size_binop (MULT_EXPR, aligned_size, + size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT)); + + /* 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. */ + +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 fold_convert (TREE_TYPE (TREE_OPERAND (exp, 1)), integer_zero_node); +} + +/* 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); + + /* 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) + return size_binop (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 1 if T is an expression that get_inner_reference handles. */ int @@ -7001,8 +7057,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, { tree array = TREE_OPERAND (exp, 0); - tree domain = TYPE_DOMAIN (TREE_TYPE (array)); - tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node; + tree low_bound = array_ref_low_bound (exp); tree index = convert (sizetype, TREE_OPERAND (exp, 1)); HOST_WIDE_INT i; |