/* Subroutines for manipulating rtx's in semantically interesting ways.
- Copyright (C) 1987, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
enum machine_mode to_mode;
rtx x;
{
+ enum machine_mode from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
rtx temp;
+ /* Here we handle some special cases. If none of them apply, fall through
+ to the default case. */
switch (GET_CODE (x))
{
case CONST_INT:
case SYMBOL_REF:
temp = gen_rtx (SYMBOL_REF, to_mode, XSTR (x, 0));
SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x);
+ CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x);
return temp;
- case PLUS:
- case MULT:
- return gen_rtx (GET_CODE (x), to_mode,
- convert_memory_address (to_mode, XEXP (x, 0)),
- convert_memory_address (to_mode, XEXP (x, 1)));
-
case CONST:
return gen_rtx (CONST, to_mode,
convert_memory_address (to_mode, XEXP (x, 0)));
- default:
- return convert_modes (to_mode,
- to_mode == ptr_mode ? Pmode : ptr_mode,
- x, POINTERS_EXTEND_UNSIGNED);
+ case PLUS:
+ case MULT:
+ /* For addition the second operand is a small constant, we can safely
+ permute the converstion and addition operation. We can always safely
+ permute them if we are making the address narrower. In addition,
+ always permute the operations if this is a constant. */
+ if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
+ || (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && (INTVAL (XEXP (x, 1)) + 20000 < 40000
+ || CONSTANT_P (XEXP (x, 0)))))
+ return gen_rtx (GET_CODE (x), to_mode,
+ convert_memory_address (to_mode, XEXP (x, 0)),
+ convert_memory_address (to_mode, XEXP (x, 1)));
}
+
+ return convert_modes (to_mode, from_mode,
+ x, POINTERS_EXTEND_UNSIGNED);
}
#endif
if (oldx == x)
return x;
else if (GET_CODE (x) == REG)
- mark_reg_pointer (x);
+ mark_reg_pointer (x, 1);
else if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
- mark_reg_pointer (XEXP (x, 0));
+ mark_reg_pointer (XEXP (x, 0), 1);
/* OLDX may have been the address on a temporary. Update the address
to indicate that X is now used. */
#endif
#ifdef POINTERS_EXTEND_UNSIGNED
+ case REFERENCE_TYPE:
case POINTER_TYPE:
mode = Pmode;
unsignedp = POINTERS_EXTEND_UNSIGNED;
else
{
/* CEIL_DIV_EXPR needs to worry about the addition overflowing,
- but we know it can't. So add ourselves and then do TRUNC_DIV_EXPR. */
+ but we know it can't. So add ourselves and then do
+ TRUNC_DIV_EXPR. */
size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
If we have to align, we must leave space in SIZE for the hole
that might result from the alignment operation. */
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || defined (ALLOCATE_OUTGOING_ARGS) || ! defined (STACK_BOUNDARY)
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (STACK_BOUNDARY)
#define MUST_ALIGN 1
#else
#define MUST_ALIGN (STACK_BOUNDARY < BIGGEST_ALIGNMENT)
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (Pmode);
- mark_reg_pointer (target);
+ mark_reg_pointer (target, known_align / BITS_PER_UNIT);
#ifndef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
if (MUST_ALIGN)
{
/* CEIL_DIV_EXPR needs to worry about the addition overflowing,
- but we know it can't. So add ourselves and then do TRUNC_DIV_EXPR. */
+ but we know it can't. So add ourselves and then do
+ TRUNC_DIV_EXPR. */
target = expand_binop (Pmode, add_optab, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);