#include "hard-reg-set.h"
#include "except.h"
#include "function.h"
-#include "insn-flags.h"
-#include "insn-codes.h"
#include "insn-config.h"
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
#include "intl.h"
#include "tm_p.h"
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
-/* Supply a default definition for PUSH_ARGS. */
-#ifndef PUSH_ARGS
-#ifdef PUSH_ROUNDING
-#define PUSH_ARGS !ACCUMULATE_OUTGOING_ARGS
-#else
-#define PUSH_ARGS 0
-#endif
-#endif
-
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
static void do_compare_and_jump PARAMS ((tree, enum rtx_code, enum rtx_code,
rtx, rtx));
static rtx do_store_flag PARAMS ((tree, rtx, enum machine_mode, int));
+static void emit_single_push_insn PARAMS ((enum machine_mode, rtx, tree));
/* Record for each mode whether we can move a register directly to or
from an object of that mode in memory. If we can't, we won't try
QUEUED_INSN (y));
return temp;
}
+ /* Copy the address into a pseudo, so that the returned value
+ remains correct across calls to emit_queue. */
+ XEXP (new, 0) = copy_to_reg (XEXP (new, 0));
return new;
}
/* Otherwise, recursively protect the subexpressions of all
}
return x;
}
- /* If the increment has not happened, use the variable itself. */
+ /* If the increment has not happened, use the variable itself. Copy it
+ into a new pseudo so that the value remains correct across calls to
+ emit_queue. */
if (QUEUED_INSN (x) == 0)
- return QUEUED_VAR (x);
+ return copy_to_reg (QUEUED_VAR (x));
/* If the increment has happened and a pre-increment copy exists,
use that copy. */
if (QUEUED_COPY (x) != 0)
&& (val & ((HOST_WIDE_INT) 1 << (width - 1))))
val |= (HOST_WIDE_INT) (-1) << width;
- return GEN_INT (val);
+ return GEN_INT (trunc_int_for_mode (val, mode));
}
return gen_lowpart (mode, x);
from block FROM to block TO. (These are MEM rtx's with BLKmode).
The caller must pass FROM and TO
through protect_from_queue before calling.
+
+ When TO is NULL, the emit_single_push_insn is used to push the
+ FROM to stack.
+
ALIGN is maximum alignment we can assume. */
void
unsigned int align;
{
struct move_by_pieces data;
- rtx to_addr = XEXP (to, 0), from_addr = XEXP (from, 0);
+ rtx to_addr, from_addr = XEXP (from, 0);
unsigned int max_size = MOVE_MAX_PIECES + 1;
enum machine_mode mode = VOIDmode, tmode;
enum insn_code icode;
data.offset = 0;
- data.to_addr = to_addr;
data.from_addr = from_addr;
- data.to = to;
+ if (to)
+ {
+ to_addr = XEXP (to, 0);
+ data.to = to;
+ data.autinc_to
+ = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
+ || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
+ data.reverse
+ = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
+ }
+ else
+ {
+ to_addr = NULL_RTX;
+ data.to = NULL_RTX;
+ data.autinc_to = 1;
+#ifdef STACK_GROWS_DOWNWARD
+ data.reverse = 1;
+#else
+ data.reverse = 0;
+#endif
+ }
+ data.to_addr = to_addr;
data.from = from;
- data.autinc_to
- = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
- || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
data.autinc_from
= (GET_CODE (from_addr) == PRE_INC || GET_CODE (from_addr) == PRE_DEC
|| GET_CODE (from_addr) == POST_INC
data.explicit_inc_from = 0;
data.explicit_inc_to = 0;
- data.reverse
- = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
if (data.reverse) data.offset = len;
data.len = len;
}
/* Return number of insns required to move L bytes by pieces.
- ALIGN (in bytes) is maximum alignment we can assume. */
+ ALIGN (in bits) is maximum alignment we can assume. */
static unsigned HOST_WIDE_INT
move_by_pieces_ninsns (l, align)
if (data->reverse)
data->offset -= size;
- if (data->autinc_to)
+ if (data->to)
{
- to1 = gen_rtx_MEM (mode, data->to_addr);
- MEM_COPY_ATTRIBUTES (to1, data->to);
+ if (data->autinc_to)
+ {
+ to1 = gen_rtx_MEM (mode, data->to_addr);
+ MEM_COPY_ATTRIBUTES (to1, data->to);
+ }
+ else
+ to1 = change_address (data->to, mode,
+ plus_constant (data->to_addr, data->offset));
}
- else
- to1 = change_address (data->to, mode,
- plus_constant (data->to_addr, data->offset));
if (data->autinc_from)
{
if (HAVE_PRE_DECREMENT && data->explicit_inc_from < 0)
emit_insn (gen_add2_insn (data->from_addr, GEN_INT (-size)));
- emit_insn ((*genfun) (to1, from1));
+ if (data->to)
+ emit_insn ((*genfun) (to1, from1));
+ else
+ emit_single_push_insn (mode, from1, NULL);
if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0)
emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR);
+ make_decl_rtl (fn, NULL);
assemble_external (fn);
}
tmps = (rtx *) alloca (sizeof (rtx) * XVECLEN (dst, 0));
- /* If we won't be loading directly from memory, protect the real source
- from strange tricks we might play. */
- src = orig_src;
- if (GET_CODE (src) != MEM && ! CONSTANT_P (src))
- {
- if (GET_MODE (src) == VOIDmode)
- src = gen_reg_rtx (GET_MODE (dst));
- else
- src = gen_reg_rtx (GET_MODE (orig_src));
- emit_move_insn (src, orig_src);
- }
-
/* Process the pieces. */
for (i = start; i < XVECLEN (dst, 0); i++)
{
abort ();
}
+ /* If we won't be loading directly from memory, protect the real source
+ from strange tricks we might play; but make sure that the source can
+ be loaded directly into the destination. */
+ src = orig_src;
+ if (GET_CODE (orig_src) != MEM
+ && (!CONSTANT_P (orig_src)
+ || (GET_MODE (orig_src) != mode
+ && GET_MODE (orig_src) != VOIDmode)))
+ {
+ if (GET_MODE (orig_src) == VOIDmode)
+ src = gen_reg_rtx (mode);
+ else
+ src = gen_reg_rtx (GET_MODE (orig_src));
+ emit_move_insn (src, orig_src);
+ }
+
/* Optimize the access just a bit. */
if (GET_CODE (src) == MEM
&& align >= GET_MODE_ALIGNMENT (mode)
else
abort ();
}
- else if ((CONSTANT_P (src)
- && (GET_MODE (src) == VOIDmode || GET_MODE (src) == mode))
+ else if (CONSTANT_P (src)
|| (GET_CODE (src) == REG && GET_MODE (src) == mode))
tmps[i] = src;
else
struct store_by_pieces data;
data.constfun = clear_by_pieces_1;
- data.constfundata = NULL_PTR;
+ data.constfundata = NULL;
data.len = len;
data.to = to;
store_by_pieces_1 (&data, align);
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
- make_decl_rtl (fn, NULL_PTR);
+ make_decl_rtl (fn, NULL);
assemble_external (fn);
}
enum mode_class class = GET_MODE_CLASS (mode);
unsigned int i;
- if (mode >= MAX_MACHINE_MODE)
+ if ((unsigned int) mode >= (unsigned int) MAX_MACHINE_MODE)
abort ();
if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
/* Don't split destination if it is a stack push. */
int stack = push_operand (x, GET_MODE (x));
+#ifdef PUSH_ROUNDING
+ /* In case we output to the stack, but the size is smaller machine can
+ push exactly, we need to use move instructions. */
+ if (stack
+ && PUSH_ROUNDING (GET_MODE_SIZE (submode)) != GET_MODE_SIZE (submode))
+ {
+ rtx temp;
+ int offset1, offset2;
+
+ /* Do not use anti_adjust_stack, since we don't want to update
+ stack_pointer_delta. */
+ temp = expand_binop (Pmode,
+#ifdef STACK_GROWS_DOWNWARD
+ sub_optab,
+#else
+ add_optab,
+#endif
+ stack_pointer_rtx,
+ GEN_INT
+ (PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))),
+ stack_pointer_rtx,
+ 0,
+ OPTAB_LIB_WIDEN);
+ if (temp != stack_pointer_rtx)
+ emit_move_insn (stack_pointer_rtx, temp);
+#ifdef STACK_GROWS_DOWNWARD
+ offset1 = 0;
+ offset2 = GET_MODE_SIZE (submode);
+#else
+ offset1 = -PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)));
+ offset2 = (-PUSH_ROUNDING (GET_MODE_SIZE (GET_MODE (x)))
+ + GET_MODE_SIZE (submode));
+#endif
+ emit_move_insn (change_address (x, submode,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (offset1))),
+ gen_realpart (submode, y));
+ emit_move_insn (change_address (x, submode,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (offset2))),
+ gen_imagpart (submode, y));
+ }
+ else
+#endif
/* If this is a stack, push the highpart first, so it
will be in the argument order.
return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);
}
-rtx
-gen_push_operand ()
-{
- return gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
-}
/* Return an rtx for the address of the beginning of a as-if-it-was-pushed
block of SIZE bytes. */
return copy_to_reg (temp);
}
+/* Emit single push insn. */
+static void
+emit_single_push_insn (mode, x, type)
+ rtx x;
+ enum machine_mode mode;
+ tree type;
+{
+#ifdef PUSH_ROUNDING
+ rtx dest_addr;
+ int rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
+ rtx dest;
+
+ if (GET_MODE_SIZE (mode) == rounded_size)
+ dest_addr = gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+ else
+ {
+#ifdef STACK_GROWS_DOWNWARD
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (-rounded_size));
+#else
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ GEN_INT (rounded_size));
+#endif
+ dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
+ }
+
+ dest = gen_rtx_MEM (mode, dest_addr);
+
+ stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
+
+ if (type != 0)
+ {
+ set_mem_attributes (dest, type, 1);
+ /* Function incoming arguments may overlap with sibling call
+ outgoing arguments and we cannot allow reordering of reads
+ from function arguments with stores to outgoing arguments
+ of sibling calls. */
+ MEM_ALIAS_SET (dest) = 0;
+ }
+ emit_move_insn (dest, x);
+#else
+ abort();
+#endif
+}
+
/* Generate code to push X onto the stack, assuming it has mode MODE and
type TYPE.
MODE is redundant except when X is a CONST_INT (since they don't
SIZE is an rtx for the size of data to be copied (in bytes),
needed only if X is BLKmode.
- ALIGN is maximum alignment we can assume.
+ ALIGN (in bits) is maximum alignment we can assume.
If PARTIAL and REG are both nonzero, then copy that many of the first
words of X into registers starting with REG, and push the rest of X.
and such small pushes do rounding that causes trouble. */
&& ((! SLOW_UNALIGNED_ACCESS (word_mode, align))
|| align >= BIGGEST_ALIGNMENT
- || PUSH_ROUNDING (align) == align)
+ || (PUSH_ROUNDING (align / BITS_PER_UNIT)
+ == (align / BITS_PER_UNIT)))
&& PUSH_ROUNDING (INTVAL (size)) == INTVAL (size))
{
/* Push padding now if padding above and stack grows down,
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
- stack_pointer_delta += INTVAL (size) - used;
- move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
- INTVAL (size) - used, align);
+ move_by_pieces (NULL, xinner, INTVAL (size) - used, align);
if (current_function_check_memory_usage && ! in_check_memory_usage)
{
#ifdef PUSH_ROUNDING
if (args_addr == 0 && PUSH_ARGS)
- {
- addr = gen_push_operand ();
- stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
- }
+ emit_single_push_insn (mode, x, type);
else
#endif
{
addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
args_so_far));
target = addr;
- }
+ dest = gen_rtx_MEM (mode, addr);
+ if (type != 0)
+ {
+ set_mem_attributes (dest, type, 1);
+ /* Function incoming arguments may overlap with sibling call
+ outgoing arguments and we cannot allow reordering of reads
+ from function arguments with stores to outgoing arguments
+ of sibling calls. */
+ MEM_ALIAS_SET (dest) = 0;
+ }
- dest = gen_rtx_MEM (mode, addr);
- if (type != 0)
- {
- set_mem_attributes (dest, type, 1);
- /* Function incoming arguments may overlap with sibling call
- outgoing arguments and we cannot allow reordering of reads
- from function arguments with stores to outgoing arguments
- of sibling calls. */
- MEM_ALIAS_SET (dest) = 0;
- }
+ emit_move_insn (dest, x);
- emit_move_insn (dest, x);
+ }
if (current_function_check_memory_usage && ! in_check_memory_usage)
{
problem. */
if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
- || TREE_CODE (to) == ARRAY_REF)
+ || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF)
{
enum machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
TYPE_MODE (sizetype));
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, LCT_NORMAL,
+ emit_library_call (memmove_libfunc, LCT_NORMAL,
VOIDmode, 3, XEXP (to_rtx, 0), Pmode,
XEXP (from_rtx, 0), Pmode,
convert_to_mode (TYPE_MODE (sizetype),
{
register rtx temp;
int dont_return_target = 0;
+ int dont_store_target = 0;
if (TREE_CODE (exp) == COMPOUND_EXPR)
{
{
temp = expand_expr (exp, target, GET_MODE (target), 0);
if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
- temp = copy_to_reg (temp);
+ {
+ /* If TEMP is already in the desired TARGET, only copy it from
+ memory and don't store it there again. */
+ if (temp == target
+ || (rtx_equal_p (temp, target)
+ && ! side_effects_p (temp) && ! side_effects_p (target)))
+ dont_store_target = 1;
+ temp = copy_to_reg (temp);
+ }
dont_return_target = 1;
}
else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
if (want_value && GET_MODE (temp) != GET_MODE (target)
&& GET_MODE (temp) != VOIDmode)
{
- temp = gen_rtx_SUBREG (GET_MODE (target), temp, 0);
+ temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp)
= SUBREG_PROMOTED_UNSIGNED_P (target);
if ((! rtx_equal_p (temp, target)
|| (temp != target && (side_effects_p (temp)
|| side_effects_p (target))))
- && TREE_CODE (exp) != ERROR_MARK)
+ && TREE_CODE (exp) != ERROR_MARK
+ && ! dont_store_target)
{
target = protect_from_queue (target, 1);
if (GET_MODE (temp) != GET_MODE (target)
index = build_decl (VAR_DECL, NULL_TREE, domain);
- DECL_RTL (index) = index_r
+ index_r
= gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
&unsignedp, 0));
-
+ SET_DECL_RTL (index, index_r);
if (TREE_CODE (value) == SAVE_EXPR
&& SAVE_EXPR_RTL (value) == 0)
{
if (TREE_CODE (exp) == ERROR_MARK)
return const0_rtx;
+ /* If we have nothing to store, do nothing unless the expression has
+ side-effects. */
+ if (bitsize == 0)
+ return expand_expr (exp, const0_rtx, VOIDmode, 0);
+
if (bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
enum machine_mode tmode;
if (unsignedp)
- return expand_and (temp, GEN_INT (width_mask), NULL_RTX);
+ return expand_and (temp,
+ GEN_INT
+ (trunc_int_for_mode
+ (width_mask,
+ GET_MODE (temp) == VOIDmode
+ ? value_mode
+ : GET_MODE (temp))), NULL_RTX);
tmode = GET_MODE (temp);
if (tmode == VOIDmode)
tmode = value_mode;
}
\f
/* Given an expression EXP that may be a COMPONENT_REF, a BIT_FIELD_REF,
- or an ARRAY_REF, look for nested COMPONENT_REFs, BIT_FIELD_REFs, or
- ARRAY_REFs and find the ultimate containing object, which we return.
+ an ARRAY_REF, or an ARRAY_RANGE_REF, look for nested operations of these
+ codes and find the ultimate containing object, which we return.
We set *PBITSIZE to the size in bits that we want, *PBITPOS to the
bit position, and *PUNSIGNEDP to the signedness of the field.
alignment = MIN (alignment, DECL_OFFSET_ALIGN (field));
}
- else if (TREE_CODE (exp) == ARRAY_REF)
+ else if (TREE_CODE (exp) == ARRAY_REF
+ || TREE_CODE (exp) == ARRAY_RANGE_REF)
{
tree index = TREE_OPERAND (exp, 1);
- tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ 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 (exp));
+ tree unit_size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (array)));
/* 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 = build (WITH_RECORD_EXPR, TREE_TYPE (index), index, exp);
if (! TREE_CONSTANT (unit_size)
&& contains_placeholder_p (unit_size))
- unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size,
- TREE_OPERAND (exp, 0));
+ unit_size = build (WITH_RECORD_EXPR, sizetype, unit_size, array);
offset = size_binop (PLUS_EXPR, offset,
size_binop (MULT_EXPR,
switch (TREE_CODE_CLASS (TREE_CODE (exp)))
{
case 'd':
- exp_rtl = DECL_RTL (exp);
+ exp_rtl = DECL_RTL_SET_P (exp) ? DECL_RTL (exp) : NULL_RTX;
break;
case 'c':
/* If this is a language-specific tree code, it may require
special handling. */
- if (TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE
+ if ((unsigned int) TREE_CODE (exp)
+ >= (unsigned int) LAST_AND_UNUSED_TREE_CODE
&& lang_safe_from_p
&& !(*lang_safe_from_p) (x, exp))
return 0;
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
VOIDmode, ro_modifier);
else if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<'
- || code == ARRAY_REF)
+ || code == ARRAY_REF || code == ARRAY_RANGE_REF)
{
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
- expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+ ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode,
+ ro_modifier);
return const0_rtx;
}
else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
VOIDmode, ro_modifier);
else if (code == BIT_FIELD_REF)
{
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
- expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
- expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode, ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+ ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode,
+ ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 2), const0_rtx, VOIDmode,
+ ro_modifier);
return const0_rtx;
}
;
&& TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_REF
+ && TREE_CODE (exp) != ARRAY_RANGE_REF
&& TREE_CODE (exp) != COMPONENT_REF
&& TREE_CODE (exp) != BIT_FIELD_REF
&& TREE_CODE (exp) != INDIRECT_REF
&& TREE_CODE (exp) != INTEGER_CST
&& TREE_CODE (exp) != PARM_DECL
&& TREE_CODE (exp) != ARRAY_REF
+ && TREE_CODE (exp) != ARRAY_RANGE_REF
&& TREE_CODE (exp) != COMPONENT_REF
&& TREE_CODE (exp) != BIT_FIELD_REF
&& TREE_CODE (exp) != INDIRECT_REF
copy_rtx (XEXP (DECL_RTL (exp), 0)));
/* If we got something, return it. But first, set the alignment
- the address is a register. */
+ if the address is a register. */
if (temp != 0)
{
if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
!= promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
abort ();
- temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0);
+ temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
return temp;
if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
{
- temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
+ temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
}
{
/* Compute the signedness and make the proper SUBREG. */
promote_mode (type, mode, &unsignedp, 0);
- temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
+ temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
return temp;
return const0_rtx;
case EXIT_EXPR:
- expand_exit_loop_if_false (NULL_PTR,
+ expand_exit_loop_if_false (NULL,
invert_truthvalue (TREE_OPERAND (exp, 0)));
return const0_rtx;
case LABELED_BLOCK_EXPR:
if (LABELED_BLOCK_BODY (exp))
expand_expr_stmt (LABELED_BLOCK_BODY (exp));
+ /* Should perhaps use expand_label, but this is simpler and safer. */
+ do_pending_stack_adjust ();
emit_label (label_rtx (LABELED_BLOCK_LABEL (exp)));
return const0_rtx;
/* If VARS have not yet been expanded, expand them now. */
while (vars)
{
- if (DECL_RTL (vars) == 0)
+ if (!DECL_RTL_SET_P (vars))
{
vars_need_expansion = 1;
expand_decl (vars);
Don't fold if this is for wide characters since it's too
difficult to do correctly and this is a very rare case. */
- if (TREE_CODE (array) == STRING_CST
+ if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
+ && TREE_CODE (array) == STRING_CST
&& TREE_CODE (index) == INTEGER_CST
&& compare_tree_int (index, TREE_STRING_LENGTH (array)) < 0
&& GET_MODE_CLASS (mode) == MODE_INT
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)
+ if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER
+ && TREE_CODE (array) == CONSTRUCTOR && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (index) == INTEGER_CST
&& 0 > compare_tree_int (index,
list_length (CONSTRUCTOR_ELTS
}
else if (optimize >= 1
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
&& TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
&& TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
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 (code != ARRAY_REF
+ if (code == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
&& TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
{
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
- /* If this object is in memory, put it into a register.
+ /* 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. */
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. */
+ storing into memory, and changing the mode to BLKmode. */
if (mode1 == VOIDmode
|| GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || (modifier != EXPAND_CONST_ADDRESS
- && modifier != EXPAND_INITIALIZER
- && ((mode1 != BLKmode && ! direct_load[(int) mode1]
- && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
- /* If the field isn't aligned enough to fetch as a memref,
- fetch it as a bit field. */
- || (mode1 != BLKmode
- && SLOW_UNALIGNED_ACCESS (mode1, alignment)
- && ((TYPE_ALIGN (TREE_TYPE (tem))
- < GET_MODE_ALIGNMENT (mode))
- || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
- /* If the type and the field are a constant size and the
- size of the type isn't the same size as the bitfield,
- we must use bitfield operations. */
- || ((bitsize >= 0
- && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
- == INTEGER_CST)
- && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
- bitsize)))))
- || (modifier != EXPAND_CONST_ADDRESS
- && modifier != EXPAND_INITIALIZER
- && mode == BLKmode
+ || (mode1 != BLKmode && ! direct_load[(int) mode1]
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+ /* If the field isn't aligned enough to fetch as a memref,
+ fetch it as a bit field. */
+ || (mode1 != BLKmode
+ && SLOW_UNALIGNED_ACCESS (mode1, alignment)
+ && ((TYPE_ALIGN (TREE_TYPE (tem))
+ < GET_MODE_ALIGNMENT (mode))
+ || (bitpos % GET_MODE_ALIGNMENT (mode) != 0)))
+ /* If the type and the field are a constant size and the
+ size of the type isn't the same size as the bitfield,
+ we must use bitfield operations. */
+ || (bitsize >= 0
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (exp)))
+ == INTEGER_CST)
+ && 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
+ bitsize))
+ || (mode == BLKmode
&& SLOW_UNALIGNED_ACCESS (mode, alignment)
&& (TYPE_ALIGN (type) > alignment
|| bitpos % TYPE_ALIGN (type) != 0)))
&& (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
{
- tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
- tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
-
- if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
- && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
- && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
- && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
- || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
- && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+ tree iftrue = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+ tree iffalse = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+ if ((TREE_CODE_CLASS (TREE_CODE (iftrue)) == '2'
+ && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '2'
+ && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iftrue)) == '1'
+ && operand_equal_p (iffalse, TREE_OPERAND (iftrue, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (iffalse)) == '1'
+ && operand_equal_p (iftrue, TREE_OPERAND (iffalse, 0), 0)))
return expand_expr (build1 (NOP_EXPR, type,
- build (COND_EXPR, TREE_TYPE (true),
+ build (COND_EXPR, TREE_TYPE (iftrue),
TREE_OPERAND (exp, 0),
- true, false)),
+ iftrue, iffalse)),
target, tmode, modifier);
}
if (target == 0)
{
- if (DECL_RTL (slot) != 0)
+ if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
/* If we have already expanded the slot, so don't do
target = assign_temp (type, 2, 0, 1);
/* All temp slots at this level must not conflict. */
preserve_temp_slots (target);
- DECL_RTL (slot) = target;
+ SET_DECL_RTL (slot, target);
if (TREE_ADDRESSABLE (slot))
put_var_into_stack (slot);
/* If we have already assigned it space, use that space,
not target that we were passed in, as our target
parameter is only a hint. */
- if (DECL_RTL (slot) != 0)
+ if (DECL_RTL_SET_P (slot))
{
target = DECL_RTL (slot);
/* If we have already expanded the slot, so don't do
}
else
{
- DECL_RTL (slot) = target;
+ SET_DECL_RTL (slot, target);
/* If we must have an addressable slot, then make sure that
the RTL that we just stored in slot is OK. */
if (TREE_ADDRESSABLE (slot))
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
if (TYPE_NONCOPIED_PARTS (lhs_type) != 0 && !fixed_type_p (rhs))
- noncopied_parts = init_noncopied_parts (stabilize_reference (lhs),
- TYPE_NONCOPIED_PARTS (lhs_type));
+ noncopied_parts
+ = init_noncopied_parts (stabilize_reference (lhs),
+ TYPE_NONCOPIED_PARTS (lhs_type));
+
while (noncopied_parts != 0)
{
expand_assignment (TREE_VALUE (noncopied_parts),
temp = 0;
- if (TREE_CODE (lhs) != VAR_DECL
- && TREE_CODE (lhs) != RESULT_DECL
- && TREE_CODE (lhs) != PARM_DECL
- && ! (TREE_CODE (lhs) == INDIRECT_REF
- && TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
-
/* Check for |= or &= of a bitfield of size one into another bitfield
of size 1. In this case, (unless we need the result of the
assignment) we can do this more efficiently with a
if (TYPE_NONCOPIED_PARTS (lhs_type) != 0
&& ! (fixed_type_p (lhs) && fixed_type_p (rhs)))
- noncopied_parts = save_noncopied_parts (stabilize_reference (lhs),
- TYPE_NONCOPIED_PARTS (lhs_type));
+ noncopied_parts
+ = save_noncopied_parts (stabilize_reference (lhs),
+ TYPE_NONCOPIED_PARTS (lhs_type));
temp = expand_assignment (lhs, rhs, ! ignore, original_target != 0);
while (noncopied_parts != 0)
if (ignore)
return op0;
- op0 = protect_from_queue (op0, 0);
+ /* Pass 1 for MODIFY, so that protect_from_queue doesn't get
+ clever and returns a REG when given a MEM. */
+ op0 = protect_from_queue (op0, 1);
/* We would like the object in memory. If it is a constant, we can
have it be statically allocated into memory. For a non-constant,
op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
- expand_eh_region_end (handler);
+ expand_eh_region_end_cleanup (handler);
return op0;
}
return const0_rtx;
}
- case POPDCC_EXPR:
- {
- rtx dcc = get_dynamic_cleanup_chain ();
- emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
- return const0_rtx;
- }
-
- case POPDHC_EXPR:
- {
- rtx dhc = get_dynamic_handler_chain ();
- emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
- return const0_rtx;
- }
-
case VA_ARG_EXPR:
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
+ case EXC_PTR_EXPR:
+ return get_exception_pointer ();
+
default:
return (*lang_expand_expr) (exp, original_target, tmode, modifier);
}
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) != ARRAY_REF
+ if (TREE_CODE (exp) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR
&& TREE_CST_RTL (TREE_OPERAND (exp, 0)) == 0)
{
case NOP_EXPR:
if (TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF
|| TREE_CODE (TREE_OPERAND (exp, 0)) == BIT_FIELD_REF
- || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF)
+ || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF
+ || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF)
goto normal;
case CONVERT_EXPR:
/* If we are narrowing the operand, we have to do the compare in the
case COMPONENT_REF:
case BIT_FIELD_REF:
case ARRAY_REF:
+ case ARRAY_RANGE_REF:
{
HOST_WIDE_INT bitsize, bitpos;
int unsignedp;
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
- if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
- || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+ if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;
/* If one operand is constant, make it the second one. Only do this
if the other operand is not constant as well. */
- if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
- || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+ if (swap_commutative_operands_p (op0, op1))
{
tem = op0;
op0 = op1;