-/* Similar to expand_expr, except that we don't specify a target, target
- mode, or modifier and we return the alignment of the inner type. This is
- used in cases where it is not necessary to align the result to the
- alignment of its type as long as we know the alignment of the result, for
- example for comparisons of BLKmode values. */
-
-static rtx
-expand_expr_unaligned (exp, palign)
- register tree exp;
- unsigned int *palign;
-{
- register rtx op0;
- tree type = TREE_TYPE (exp);
- register enum machine_mode mode = TYPE_MODE (type);
-
- /* Default the alignment we return to that of the type. */
- *palign = TYPE_ALIGN (type);
-
- /* The only cases in which we do anything special is if the resulting mode
- is BLKmode. */
- if (mode != BLKmode)
- return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-
- switch (TREE_CODE (exp))
- {
- case CONVERT_EXPR:
- case NOP_EXPR:
- case NON_LVALUE_EXPR:
- /* Conversions between BLKmode values don't change the underlying
- alignment or value. */
- if (TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == BLKmode)
- return expand_expr_unaligned (TREE_OPERAND (exp, 0), palign);
- break;
-
- case ARRAY_REF:
- /* Much of the code for this case is copied directly from expand_expr.
- We need to duplicate it here because we will do something different
- in the fall-through case, so we need to handle the same exceptions
- it does. */
- {
- 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 index = convert (sizetype, TREE_OPERAND (exp, 1));
- HOST_WIDE_INT i;
-
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) != ARRAY_TYPE)
- abort ();
-
- /* Optimize the special-case of a zero lower bound.
-
- We convert the low_bound to sizetype to avoid some problems
- with constant folding. (E.g. suppose the lower bound is 1,
- and its mode is QI. Without the conversion, (ARRAY
- +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
- +INDEX), which becomes (ARRAY+255+INDEX). Oops!) */
-
- if (! integer_zerop (low_bound))
- index = size_diffop (index, convert (sizetype, low_bound));
-
- /* If this is a constant index into a constant array,
- just get the value from the array. Handle both the cases when
- we have an explicit constructor and when our operand is a variable
- that was declared const. */
-
- if (TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
- && host_integerp (index, 0)
- && 0 > compare_tree_int (index,
- list_length (CONSTRUCTOR_ELTS
- (TREE_OPERAND (exp, 0)))))
- {
- tree elem;
-
- for (elem = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
- i = tree_low_cst (index, 0);
- elem != 0 && i != 0; i--, elem = TREE_CHAIN (elem))
- ;
-
- if (elem)
- return expand_expr_unaligned (fold (TREE_VALUE (elem)), palign);
- }
-
- else if (optimize >= 1
- && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
- && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
- && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
- {
- if (TREE_CODE (index) == INTEGER_CST)
- {
- tree init = DECL_INITIAL (array);
-
- if (TREE_CODE (init) == CONSTRUCTOR)
- {
- tree elem;
-
- for (elem = CONSTRUCTOR_ELTS (init);
- ! tree_int_cst_equal (TREE_PURPOSE (elem), index);
- elem = TREE_CHAIN (elem))
- ;
-
- if (elem)
- return expand_expr_unaligned (fold (TREE_VALUE (elem)),
- palign);
- }
- }
- }
- }
- /* Fall through. */
-
- case COMPONENT_REF:
- case BIT_FIELD_REF:
- case ARRAY_RANGE_REF:
- /* If the operand is a CONSTRUCTOR, we can just extract the
- appropriate field if it is present. Don't do this if we have
- already written the data since we want to refer to that copy
- and varasm.c assumes that's what we'll do. */
- if (TREE_CODE (exp) == COMPONENT_REF
- && TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
- && TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
- {
- tree elt;
-
- for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
- elt = TREE_CHAIN (elt))
- if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
- /* Note that unlike the case in expand_expr, we know this is
- BLKmode and hence not an integer. */
- return expand_expr_unaligned (TREE_VALUE (elt), palign);
- }
-
- {
- enum machine_mode mode1;
- HOST_WIDE_INT bitsize, bitpos;
- tree offset;
- int volatilep = 0;
- unsigned int alignment;
- int unsignedp;
- tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep,
- &alignment);
-
- /* If we got back the original object, something is wrong. Perhaps
- we are evaluating an expression too early. In any event, don't
- infinitely recurse. */
- if (tem == exp)
- abort ();
-
- op0 = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-
- /* If this is a constant, put it into a register if it is a
- legitimate constant and OFFSET is 0 and memory if it isn't. */
- if (CONSTANT_P (op0))
- {
- enum machine_mode inner_mode = TYPE_MODE (TREE_TYPE (tem));
-
- if (inner_mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
- && offset == 0)
- op0 = force_reg (inner_mode, op0);
- else
- op0 = validize_mem (force_const_mem (inner_mode, op0));
- }
-
- if (offset != 0)
- {
- rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
-
- /* If this object is in a register, put it into memory.
- This case can't occur in C, but can in Ada if we have
- unchecked conversion of an expression from a scalar type to
- an array or record type. */
- if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
- {
- tree nt = build_qualified_type (TREE_TYPE (tem),
- (TYPE_QUALS (TREE_TYPE (tem))
- | TYPE_QUAL_CONST));
- rtx memloc = assign_temp (nt, 1, 1, 1);
-
- mark_temp_addr_taken (memloc);
- emit_move_insn (memloc, op0);
- op0 = memloc;
- }
-
- if (GET_CODE (op0) != MEM)
- abort ();
-
- if (GET_MODE (offset_rtx) != ptr_mode)
- {
-#ifdef POINTERS_EXTEND_UNSIGNED
- offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
-#else
- offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
-#endif
- }
-
- op0 = change_address (op0, VOIDmode,
- gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
- force_reg (ptr_mode,
- offset_rtx)));
- }
-
- /* Don't forget about volatility even if this is a bitfield. */
- if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
- {
- op0 = copy_rtx (op0);
- MEM_VOLATILE_P (op0) = 1;
- }
-
- /* Check the access. */
- if (current_function_check_memory_usage && GET_CODE (op0) == MEM)
- {
- rtx to;
- int size;
-
- to = plus_constant (XEXP (op0, 0), (bitpos / BITS_PER_UNIT));
- size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
-
- /* Check the access right of the pointer. */
- in_check_memory_usage = 1;
- if (size > BITS_PER_UNIT)
- emit_library_call (chkr_check_addr_libfunc,
- LCT_CONST_MAKE_BLOCK, VOIDmode, 3,
- to, ptr_mode, GEN_INT (size / BITS_PER_UNIT),
- TYPE_MODE (sizetype),
- GEN_INT (MEMORY_USE_RO),
- TYPE_MODE (integer_type_node));
- in_check_memory_usage = 0;
- }
-
- /* In cases where an aligned union has an unaligned object
- as a field, we might be extracting a BLKmode value from
- an integer-mode (e.g., SImode) object. Handle this case
- by doing the extract into an object as wide as the field
- (which we know to be the width of a basic mode), then
- storing into memory, and changing the mode to BLKmode.
- If we ultimately want the address (EXPAND_CONST_ADDRESS or
- EXPAND_INITIALIZER), then we must not copy to a temporary. */
- if (mode1 == VOIDmode
- || GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || (SLOW_UNALIGNED_ACCESS (mode1, alignment)
- && (TYPE_ALIGN (type) > alignment
- || bitpos % TYPE_ALIGN (type) != 0)))
- {
- enum machine_mode ext_mode = mode_for_size (bitsize, MODE_INT, 1);
-
- if (ext_mode == BLKmode)
- {
- /* In this case, BITPOS must start at a byte boundary. */
- if (GET_CODE (op0) != MEM
- || bitpos % BITS_PER_UNIT != 0)
- abort ();
-
- op0 = adjust_address (op0, VOIDmode, bitpos / BITS_PER_UNIT);
- }
- else
- {
- tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
- TYPE_QUAL_CONST);
- rtx new = assign_temp (nt, 0, 1, 1);
-
- op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
- unsignedp, NULL_RTX, ext_mode,
- ext_mode, alignment,
- int_size_in_bytes (TREE_TYPE (tem)));
-
- /* If the result is a record type and BITSIZE is narrower than
- the mode of OP0, an integral mode, and this is a big endian
- machine, we must put the field into the high-order bits. */
- if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
- && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
- op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
- size_int (GET_MODE_BITSIZE
- (GET_MODE (op0))
- - bitsize),
- op0, 1);
-
- emit_move_insn (new, op0);
- op0 = copy_rtx (new);
- PUT_MODE (op0, BLKmode);
- }
- }
- else
- /* Get a reference to just this component. */
- op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
-
- set_mem_alias_set (op0, get_alias_set (exp));
-
- /* Adjust the alignment in case the bit position is not
- a multiple of the alignment of the inner object. */
- while (bitpos % alignment != 0)
- alignment >>= 1;
-
- if (GET_CODE (XEXP (op0, 0)) == REG)
- mark_reg_pointer (XEXP (op0, 0), alignment);
-
- MEM_IN_STRUCT_P (op0) = 1;
- MEM_VOLATILE_P (op0) |= volatilep;
-
- *palign = alignment;
- return op0;
- }
-
- default:
- break;
-
- }
-
- return expand_expr (exp, NULL_RTX, VOIDmode, EXPAND_NORMAL);
-}
-\f