/* Convert tree expression to rtl instructions, for GNU compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "machmode.h"
#include "real.h"
#include "rtl.h"
#ifdef PUSH_ROUNDING
+#ifndef PUSH_ARGS_REVERSED
#if defined (STACK_GROWS_DOWNWARD) != defined (ARGS_GROW_DOWNWARD)
#define PUSH_ARGS_REVERSED /* If it's last to first. */
#endif
+#endif
#endif
(move_by_pieces_ninsns (SIZE, ALIGN) < (unsigned int) CLEAR_RATIO)
#endif
+/* This macro is used to determine whether store_by_pieces should be
+ called to "memset" storage with byte values other than zero, or
+ to "memcpy" storage when the source is a constant string. */
+#ifndef STORE_BY_PIECES_P
+#define STORE_BY_PIECES_P(SIZE, ALIGN) MOVE_BY_PIECES_P (SIZE, ALIGN)
+#endif
+
/* This array records the insn_code of insns to perform block moves. */
enum insn_code movstr_optab[NUM_MACHINE_MODES];
/* If SIZE is that of a mode no bigger than a word, just use that
mode's store operation. */
if (size <= UNITS_PER_WORD
- && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode
- && !FUNCTION_ARG_REG_LITTLE_ENDIAN)
+ && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
{
emit_move_insn (adjust_address (x, mode, 0), gen_rtx_REG (mode, regno));
return;
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
to the left before storing to memory. Note that the previous test
doesn't handle all cases (e.g. SIZE == 3). */
- if (size < UNITS_PER_WORD
- && BYTES_BIG_ENDIAN
- && !FUNCTION_ARG_REG_LITTLE_ENDIAN)
+ if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
rtx shift;
}
}
+/* Generate a PARALLEL rtx for a new non-consecutive group of registers from
+ ORIG, where ORIG is a non-consecutive group of registers represented by
+ a PARALLEL. The clone is identical to the original except in that the
+ original set of registers is replaced by a new set of pseudo registers.
+ The new set has the same modes as the original set. */
+
+rtx
+gen_group_rtx (orig)
+ rtx orig;
+{
+ int i, length;
+ rtx *tmps;
+
+ if (GET_CODE (orig) != PARALLEL)
+ abort ();
+
+ length = XVECLEN (orig, 0);
+ tmps = (rtx *) alloca (sizeof (rtx) * length);
+
+ /* Skip a NULL entry in first slot. */
+ i = XEXP (XVECEXP (orig, 0, 0), 0) ? 0 : 1;
+
+ if (i)
+ tmps[0] = 0;
+
+ for (; i < length; i++)
+ {
+ enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+ rtx offset = XEXP (XVECEXP (orig, 0, i), 1);
+
+ tmps[i] = gen_rtx_EXPR_LIST (VOIDmode, gen_reg_rtx (mode), offset);
+ }
+
+ return gen_rtx_PARALLEL (GET_MODE (orig), gen_rtvec_v (length, tmps));
+}
+
/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
registers represented by a PARALLEL. SSIZE represents the total size of
block SRC in bytes, or -1 if not known. */
emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
}
+/* Emit code to move a block SRC to block DST, where SRC and DST are
+ non-consecutive groups of registers, each represented by a PARALLEL. */
+
+void
+emit_group_move (dst, src)
+ rtx dst, src;
+{
+ int i;
+
+ if (GET_CODE (src) != PARALLEL
+ || GET_CODE (dst) != PARALLEL
+ || XVECLEN (src, 0) != XVECLEN (dst, 0))
+ abort ();
+
+ /* Skip first entry if NULL. */
+ for (i = XEXP (XVECEXP (src, 0, 0), 0) ? 0 : 1; i < XVECLEN (src, 0); i++)
+ emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0),
+ XEXP (XVECEXP (src, 0, i), 0));
+}
+
/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
registers represented by a PARALLEL. SSIZE represents the total size of
block DST, or -1 if not known. */
{
dst = gen_reg_rtx (GET_MODE (orig_dst));
/* Make life a bit easier for combine. */
- emit_move_insn (dst, const0_rtx);
+ emit_move_insn (dst, CONST0_RTX (GET_MODE (orig_dst)));
}
/* Process the pieces. */
bytepos -= GET_MODE_SIZE (GET_MODE (XEXP (dst, 0)));
dest = XEXP (dst, 1);
}
+ else if (bytepos == 0 && XVECLEN (src, 0))
+ {
+ dest = assign_stack_temp (GET_MODE (dest),
+ GET_MODE_SIZE (GET_MODE (dest)), 0);
+ emit_move_insn (adjust_address (dest, GET_MODE (tmps[i]), bytepos),
+ tmps[i]);
+ dst = dest;
+ break;
+ }
else
abort ();
}
emit_queue ();
/* Copy from the pseudo into the (probable) hard reg. */
- if (GET_CODE (dst) == REG)
+ if (orig_dst != dst)
emit_move_insn (orig_dst, dst);
}
}
/* This code assumes srcreg is at least a full word. If it isn't, copy it
- into a new pseudo which is a full word.
+ into a new pseudo which is a full word. */
- If FUNCTION_ARG_REG_LITTLE_ENDIAN is set and convert_to_mode does a copy,
- the wrong part of the register gets copied so we fake a type conversion
- in place. */
if (GET_MODE (srcreg) != BLKmode
&& GET_MODE_SIZE (GET_MODE (srcreg)) < UNITS_PER_WORD)
- {
- if (FUNCTION_ARG_REG_LITTLE_ENDIAN)
- srcreg = simplify_gen_subreg (word_mode, srcreg, GET_MODE (srcreg), 0);
- else
- srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
- }
+ srcreg = convert_to_mode (word_mode, srcreg, TREE_UNSIGNED (type));
/* Structures whose size is not a multiple of a word are aligned
to the least significant byte (to the right). On a BYTES_BIG_ENDIAN
machine, this means we must skip the empty high order bytes when
calculating the bit offset. */
if (BYTES_BIG_ENDIAN
- && !FUNCTION_ARG_REG_LITTLE_ENDIAN
&& bytes % UNITS_PER_WORD)
big_endian_correction
= (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
int reverse;
rtx cst;
- if (! MOVE_BY_PIECES_P (len, align))
+ if (! STORE_BY_PIECES_P (len, align))
return 0;
if (! SLOW_UNALIGNED_ACCESS (word_mode, align)
{
struct store_by_pieces data;
- if (! MOVE_BY_PIECES_P (len, align))
+ if (! STORE_BY_PIECES_P (len, align))
abort ();
to = protect_from_queue (to, 1);
data.constfun = constfun;
else if (CONSTANT_P (y))
{
if (optimize
- && FLOAT_MODE_P (GET_MODE (x))
+ && SCALAR_FLOAT_MODE_P (GET_MODE (x))
&& (last_insn = compress_float_constant (x, y)))
return last_insn;
{
y_cst = y;
y = force_const_mem (mode, y);
+
+ /* If the target's cannot_force_const_mem prevented the spill,
+ assume that the target's move expanders will also take care
+ of the non-legitimate constant. */
+ if (!y)
+ y = y_cst;
}
}
/* Expand complex moves by moving real part and imag part, if possible. */
else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
- && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode)
- * BITS_PER_UNIT),
- (class == MODE_COMPLEX_INT
- ? MODE_INT : MODE_FLOAT),
- 0))
+ && BLKmode != (submode = GET_MODE_INNER (mode))
&& (mov_optab->handlers[(int) submode].insn_code
!= CODE_FOR_nothing))
{
else
{
rtx addr;
- rtx target = NULL_RTX;
rtx dest;
/* Push padding now if padding above and stack grows down,
else
addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
args_so_far));
- target = addr;
dest = gen_rtx_MEM (mode, addr);
if (type != 0)
{
problem. */
if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
- || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF)
+ || TREE_CODE (to) == ARRAY_REF || TREE_CODE (to) == ARRAY_RANGE_REF
+ || TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
enum machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
and storing the value into TARGET.
TARGET may contain a QUEUED rtx.
- If WANT_VALUE is nonzero, return a copy of the value
+ If WANT_VALUE & 1 is nonzero, return a copy of the value
not in TARGET, so that we can be sure to use the proper
value in a containing expression even if TARGET has something
else stored in it. If possible, we copy the value through a pseudo
with no sequence point. Will other languages need this to
be more thorough?
- If WANT_VALUE is 0, we return NULL, to make sure
+ If WANT_VALUE & 1 is 0, we return NULL, to make sure
to catch quickly any cases where the caller uses the value
- and fails to set WANT_VALUE. */
+ and fails to set WANT_VALUE.
+
+ If WANT_VALUE & 2 is set, this is a store into a call param on the
+ stack, and block moves may need to be treated specially. */
rtx
store_expr (exp, target, want_value)
{
/* Perform first part of compound expression, then assign from second
part. */
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+ want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
emit_queue ();
return store_expr (TREE_OPERAND (exp, 1), target, want_value);
}
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
start_cleanup_deferral ();
- store_expr (TREE_OPERAND (exp, 1), target, 0);
+ store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
start_cleanup_deferral ();
- store_expr (TREE_OPERAND (exp, 2), target, 0);
+ store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
end_cleanup_deferral ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
- return want_value ? target : NULL_RTX;
+ return want_value & 1 ? target : NULL_RTX;
}
else if (queued_subexp_p (target))
/* If target contains a postincrement, let's not risk
{
/* Expand EXP into a new pseudo. */
temp = gen_reg_rtx (GET_MODE (target));
- temp = expand_expr (exp, temp, GET_MODE (target), 0);
+ temp = expand_expr (exp, temp, GET_MODE (target),
+ (want_value & 2
+ ? EXPAND_STACK_PARM : EXPAND_NORMAL));
}
else
- temp = expand_expr (exp, NULL_RTX, GET_MODE (target), 0);
+ temp = expand_expr (exp, NULL_RTX, GET_MODE (target),
+ (want_value & 2
+ ? EXPAND_STACK_PARM : EXPAND_NORMAL));
/* If target is volatile, ANSI requires accessing the value
*from* the target, if it is accessed. So make that happen.
In no case return the target itself. */
- if (! MEM_VOLATILE_P (target) && want_value)
+ if (! MEM_VOLATILE_P (target) && (want_value & 1) != 0)
dont_return_target = 1;
}
- else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
+ else if ((want_value & 1) != 0
+ && GET_CODE (target) == MEM
+ && ! MEM_VOLATILE_P (target)
&& GET_MODE (target) != BLKmode)
/* If target is in memory and caller wants value in a register instead,
arrange that. Pass TARGET as target for expand_expr so that,
Don't do this if TARGET is volatile because we are supposed
to write it and then read it. */
{
- temp = expand_expr (exp, target, GET_MODE (target), 0);
+ temp = expand_expr (exp, target, GET_MODE (target),
+ want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
{
/* If TEMP is already in the desired TARGET, only copy it from
dont_return_target = 1;
}
else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
- /* If this is an scalar in a register that is stored in a wider mode
+ /* If this is a scalar in a register that is stored in a wider mode
than the declared mode, compute the result into its declared mode
and then convert to the wider mode. Our value is the computed
expression. */
the extend. But don't do this if the type of EXP is a subtype
of something else since then the conversion might involve
more than just converting modes. */
- if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+ if ((want_value & 1) == 0
+ && INTEGRAL_TYPE_P (TREE_TYPE (exp))
&& TREE_TYPE (TREE_TYPE (exp)) == 0)
{
if (TREE_UNSIGNED (TREE_TYPE (exp))
inner_target = SUBREG_REG (target);
}
- temp = expand_expr (exp, inner_target, VOIDmode, 0);
+ temp = expand_expr (exp, inner_target, VOIDmode,
+ want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
- /* If TEMP is a volatile MEM and we want a result value, make
- the access now so it gets done only once. Likewise if
- it contains TARGET. */
- if (GET_CODE (temp) == MEM && want_value
- && (MEM_VOLATILE_P (temp)
- || reg_mentioned_p (SUBREG_REG (target), XEXP (temp, 0))))
+ /* If TEMP is a MEM and we want a result value, make the access
+ now so it gets done only once. Strictly speaking, this is
+ only necessary if the MEM is volatile, or if the address
+ overlaps TARGET. But not performing the load twice also
+ reduces the amount of rtl we generate and then have to CSE. */
+ if (GET_CODE (temp) == MEM && (want_value & 1) != 0)
temp = copy_to_reg (temp);
/* If TEMP is a VOIDmode constant, use convert_modes to make
target. Otherwise, the caller might get confused by a result whose
mode is larger than expected. */
- if (want_value && GET_MODE (temp) != GET_MODE (target))
+ if ((want_value & 1) != 0 && GET_MODE (temp) != GET_MODE (target))
{
if (GET_MODE (temp) != VOIDmode)
{
temp, SUBREG_PROMOTED_UNSIGNED_P (target));
}
- return want_value ? temp : NULL_RTX;
+ return want_value & 1 ? temp : NULL_RTX;
}
else
{
- temp = expand_expr (exp, target, GET_MODE (target), 0);
+ temp = expand_expr (exp, target, GET_MODE (target),
+ want_value & 2 ? EXPAND_STACK_PARM : EXPAND_NORMAL);
/* Return TARGET if it's a specified hardware register.
If TARGET is a volatile mem ref, either return TARGET
or return a reg copied *from* TARGET; ANSI requires this.
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
&& !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
&& ! rtx_equal_p (temp, target)
- && (CONSTANT_P (temp) || want_value))
+ && (CONSTANT_P (temp) || (want_value & 1) != 0))
dont_return_target = 1;
}
if (GET_CODE (size) == CONST_INT
&& INTVAL (size) < TREE_STRING_LENGTH (exp))
- emit_block_move (target, temp, size, BLOCK_OP_NORMAL);
+ emit_block_move (target, temp, size,
+ (want_value & 2
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
{
/* Compute the size of the data to copy from the string. */
= size_binop (MIN_EXPR,
make_tree (sizetype, size),
size_int (TREE_STRING_LENGTH (exp)));
- rtx copy_size_rtx = expand_expr (copy_size, NULL_RTX,
- VOIDmode, 0);
+ rtx copy_size_rtx
+ = expand_expr (copy_size, NULL_RTX, VOIDmode,
+ (want_value & 2
+ ? EXPAND_STACK_PARM : EXPAND_NORMAL));
rtx label = 0;
/* Copy that much. */
copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, 0);
- emit_block_move (target, temp, copy_size_rtx, BLOCK_OP_NORMAL);
+ emit_block_move (target, temp, copy_size_rtx,
+ (want_value & 2
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
/* Figure out how much is left in TARGET that we have to clear.
Do all calculations in ptr_mode. */
else if (GET_CODE (target) == PARALLEL)
emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)));
else if (GET_MODE (temp) == BLKmode)
- emit_block_move (target, temp, expr_size (exp), BLOCK_OP_NORMAL);
+ emit_block_move (target, temp, expr_size (exp),
+ (want_value & 2
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (target, temp);
}
/* If we don't want a value, return NULL_RTX. */
- if (! want_value)
+ if ((want_value & 1) == 0)
return NULL_RTX;
/* If we are supposed to return TEMP, do so as long as it isn't a MEM.
return temp;
/* Return TARGET itself if it is a hard register. */
- else if (want_value && GET_MODE (target) != BLKmode
+ else if ((want_value & 1) != 0
+ && GET_MODE (target) != BLKmode
&& ! (GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER))
return copy_to_reg (target);
enum machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos = 0;
- int unsignedp;
tree offset;
rtx to_rtx = target;
else
bitsize = -1;
- unsignedp = TREE_UNSIGNED (field);
mode = DECL_MODE (field);
if (DECL_BIT_FIELD (field))
mode = VOIDmode;
{
tree lo_index = TREE_OPERAND (index, 0);
tree hi_index = TREE_OPERAND (index, 1);
- rtx index_r, pos_rtx, hi_r, loop_top, loop_end;
+ rtx index_r, pos_rtx, loop_end;
struct nesting *loop;
HOST_WIDE_INT lo, hi, count;
tree position;
}
else
{
- hi_r = expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
- loop_top = gen_label_rtx ();
+ expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
loop_end = gen_label_rtx ();
unsignedp = TREE_UNSIGNED (domain);
EXPAND_CONST_ADDRESS says that it is okay to return a MEM
with a constant address even if that address is not normally legitimate.
- EXPAND_INITIALIZER and EXPAND_SUM also have this effect. */
+ EXPAND_INITIALIZER and EXPAND_SUM also have this effect.
+
+ EXPAND_STACK_PARM is used when expanding to a TARGET on the stack for
+ a call parameter. Such targets require special care as we haven't yet
+ marked TARGET so that it's safe from being trashed by libcalls. We
+ don't want to use TARGET for anything but the final result;
+ Intermediate values must go elsewhere. Additionally, calls to
+ emit_block_move will be flagged with BLOCK_OP_CALL_PARM. */
rtx
expand_expr (exp, target, tmode, modifier)
#ifdef MAX_INTEGER_COMPUTATION_MODE
/* Only check stuff here if the mode we want is different from the mode
- of the expression; if it's the same, check_max_integer_computiation_mode
+ of the expression; if it's the same, check_max_integer_computation_mode
will handle it. Do we really need to check this stuff at all? */
if (target
/* If will do cse, generate all results into pseudo registers
since 1) that allows cse to find more things
and 2) otherwise cse could produce an insn the machine
- cannot support. And exception is a CONSTRUCTOR into a multi-word
- MEM: that's much more likely to be most efficient into the MEM. */
+ cannot support. An exception is a CONSTRUCTOR into a multi-word
+ MEM: that's much more likely to be most efficient into the MEM.
+ Another is a CALL_EXPR which must return in memory. */
if (! cse_not_expected && mode != BLKmode && target
&& (GET_CODE (target) != REG || REGNO (target) < FIRST_PSEUDO_REGISTER)
- && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
- target = subtarget;
+ && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ && ! (code == CALL_EXPR && aggregate_value_p (exp)))
+ target = 0;
switch (code)
{
return temp;
case CONST_DECL:
- return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+ return expand_expr (DECL_INITIAL (exp), target, VOIDmode, modifier);
case REAL_CST:
/* If optimized, generate immediate CONST_DOUBLE
if (temp == const0_rtx)
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
else
- store_expr (TREE_OPERAND (exp, 0), temp, 0);
+ store_expr (TREE_OPERAND (exp, 0), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
TREE_USED (exp) = 1;
}
case BIND_EXPR:
{
tree vars = TREE_OPERAND (exp, 0);
- int vars_need_expansion = 0;
/* Need to open a binding contour here because
if there are any cleanups they must be contained here. */
while (vars)
{
if (!DECL_RTL_SET_P (vars))
- {
- vars_need_expansion = 1;
- expand_decl (vars);
- }
+ expand_decl (vars);
expand_decl_init (vars);
vars = TREE_CHAIN (vars);
}
/* Handle calls that pass values in multiple non-contiguous
locations. The Irix 6 ABI has examples of this. */
if (target == 0 || ! safe_from_p (target, exp, 1)
- || GET_CODE (target) == PARALLEL)
+ || GET_CODE (target) == PARALLEL
+ || modifier == EXPAND_STACK_PARM)
target
= assign_temp (build_qualified_type (type,
(TYPE_QUALS (type)
&& (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
<= HOST_BITS_PER_WIDE_INT))))
{
+ if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
+ && modifier == EXPAND_STACK_PARM)
+ target = 0;
op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
{
(TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
+ && modifier != EXPAND_STACK_PARM
? target : NULL_RTX),
VOIDmode,
(modifier == EXPAND_INITIALIZER
- || modifier == EXPAND_CONST_ADDRESS)
+ || modifier == EXPAND_CONST_ADDRESS
+ || modifier == EXPAND_STACK_PARM)
? modifier : EXPAND_NORMAL);
/* If this is a constant, put it into a register if it is a
if (offset != 0)
{
- rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+ rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
+ EXPAND_SUM);
/* 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
emit_block_move (target, op0,
GEN_INT ((bitsize + BITS_PER_UNIT - 1)
/ BITS_PER_UNIT),
- BLOCK_OP_NORMAL);
+ (modifier == EXPAND_STACK_PARM
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
return target;
}
if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
- op0 = extract_bit_field (op0, bitsize, bitpos,
- unsignedp, target, ext_mode, ext_mode,
+ op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
+ (modifier == EXPAND_STACK_PARM
+ ? NULL_RTX : target),
+ ext_mode, ext_mode,
int_size_in_bytes (TREE_TYPE (tem)));
/* If the result is a record type and BITSIZE is narrower than
{
if (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
== BUILT_IN_FRONTEND)
- return (*lang_hooks.expand_expr)
- (exp, original_target, tmode, modifier);
+ return (*lang_hooks.expand_expr) (exp, original_target,
+ tmode, modifier);
else
return expand_builtin (exp, target, subtarget, tmode, ignore);
}
if (GET_CODE (target) == MEM)
/* Store data into beginning of memory target. */
store_expr (TREE_OPERAND (exp, 0),
- adjust_address (target, TYPE_MODE (valtype), 0), 0);
+ adjust_address (target, TYPE_MODE (valtype), 0),
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
else if (GET_CODE (target) == REG)
/* Store this field into a union of the proper type. */
if (GET_MODE (op0) == BLKmode)
emit_block_move (new_with_op0_mode, op0,
GEN_INT (GET_MODE_SIZE (TYPE_MODE (type))),
- BLOCK_OP_NORMAL);
+ (modifier == EXPAND_STACK_PARM
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
emit_move_insn (new_with_op0_mode, op0);
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
|| (mode == ptr_mode && (unsignedp || ! flag_trapv)))
{
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& TREE_CONSTANT (TREE_OPERAND (exp, 1)))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
- temp = simplify_binary_operation (PLUS, mode, op0, op1);
- if (temp)
- return temp;
+ if (op0 == const0_rtx)
+ return op1;
+ if (op1 == const0_rtx)
+ return op0;
goto binop2;
}
if (modifier == EXPAND_SUM && mode == ptr_mode
&& host_integerp (TREE_OPERAND (exp, 1), 0))
{
+ tree exp1 = TREE_OPERAND (exp, 1);
+
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
EXPAND_SUM);
if (GET_CODE (op0) != REG)
op0 = copy_to_mode_reg (mode, op0);
- return
- gen_rtx_MULT (mode, op0,
- GEN_INT (tree_low_cst (TREE_OPERAND (exp, 1), 0)));
+ return gen_rtx_MULT (mode, op0,
+ gen_int_mode (tree_low_cst (exp1, 0),
+ TYPE_MODE (TREE_TYPE (exp1))));
}
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
+
/* Check for multiplying things that have been extended
from a narrower type. If this machine supports multiplying
in that narrower type with a result in the desired type,
case EXACT_DIV_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
/* Possible optimization: compute the dividend with EXPAND_SUM
then if the divisor is constant can optimize the case
where some terms of the dividend have coeffs divisible by it. */
build (RDIV_EXPR, type,
build_real (type, dconst1),
TREE_OPERAND (exp, 1))),
- target, tmode, unsignedp);
+ target, tmode, modifier);
this_optab = sdiv_optab;
goto binop;
case ROUND_MOD_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
case FIX_TRUNC_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
- if (target == 0)
+ if (target == 0 || modifier == EXPAND_STACK_PARM)
target = gen_reg_rtx (mode);
expand_fix (target, op0, unsignedp);
return target;
case FLOAT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
- if (target == 0)
+ if (target == 0 || modifier == EXPAND_STACK_PARM)
target = gen_reg_rtx (mode);
/* expand_float can't figure out what to do if FROM has VOIDmode.
So give it the correct mode. With -O, cse will optimize this. */
case NEGATE_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
temp = expand_unop (mode,
! unsignedp && flag_trapv
&& (GET_MODE_CLASS(mode) == MODE_INT)
case ABS_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
/* Handle complex values specially. */
if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
case MAX_EXPR:
case MIN_EXPR:
target = original_target;
- if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
+ if (target == 0
+ || modifier == EXPAND_STACK_PARM
+ || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
|| (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
|| GET_MODE (target) != mode
|| (GET_CODE (target) == REG
case BIT_NOT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
if (temp == 0)
abort ();
case FFS_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
temp = expand_unop (mode, ffs_optab, op0, target, 1);
if (temp == 0)
abort ();
return temp;
+ case CLZ_EXPR:
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ temp = expand_unop (mode, clz_optab, op0, target, 1);
+ if (temp == 0)
+ abort ();
+ return temp;
+
+ case CTZ_EXPR:
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ temp = expand_unop (mode, ctz_optab, op0, target, 1);
+ if (temp == 0)
+ abort ();
+ return temp;
+
+ case POPCOUNT_EXPR:
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ temp = expand_unop (mode, popcount_optab, op0, target, 1);
+ if (temp == 0)
+ abort ();
+ return temp;
+
+ case PARITY_EXPR:
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
+ temp = expand_unop (mode, parity_optab, op0, target, 1);
+ if (temp == 0)
+ abort ();
+ return temp;
+
/* ??? Can optimize bitwise operations with one arg constant.
Can optimize (a bitwise1 n) bitwise2 (a bitwise3 b)
and (a bitwise1 b) bitwise2 b (etc)
case RROTATE_EXPR:
if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
unsignedp);
case UNGT_EXPR:
case UNGE_EXPR:
case UNEQ_EXPR:
- temp = do_store_flag (exp, target, tmode != VOIDmode ? tmode : mode, 0);
+ temp = do_store_flag (exp,
+ modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+ tmode != VOIDmode ? tmode : mode, 0);
if (temp != 0)
return temp;
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
if (! ignore
- && (target == 0 || ! safe_from_p (target, exp, 1)
+ && (target == 0
+ || modifier == EXPAND_STACK_PARM
+ || ! safe_from_p (target, exp, 1)
/* Make sure we don't have a hard reg (such as function's return
value) live across basic blocks, if not optimizing. */
|| (!optimize && GET_CODE (target) == REG
return ignore ? const0_rtx : target;
case TRUTH_NOT_EXPR:
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);
/* The parser is careful to generate TRUTH_NOT_EXPR
only with operands that are always zero or one. */
emit_queue ();
return expand_expr (TREE_OPERAND (exp, 1),
(ignore ? const0_rtx : target),
- VOIDmode, 0);
+ VOIDmode, modifier);
case COND_EXPR:
/* If we would have a "singleton" (see below) were it not for a
return const0_rtx;
}
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
if (GET_MODE (op0) == mode)
return op0;
if (ignore)
temp = 0;
+ else if (modifier == EXPAND_STACK_PARM)
+ temp = assign_temp (type, 0, 0, 1);
else if (original_target
&& (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
|| (singleton && GET_CODE (original_target) == REG
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
+ tree cond;
optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR
? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op))
? addv_optab : add_optab)
: TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab
: xor_optab);
- /* If we had X ? A : A + 1, do this as A + (X == 0).
-
- We have to invert the truth value here and then put it
- back later if do_store_flag fails. We cannot simply copy
- TREE_OPERAND (exp, 0) to another variable and modify that
- because invert_truthvalue can modify the tree pointed to
- by its argument. */
+ /* If we had X ? A : A + 1, do this as A + (X == 0). */
if (singleton == TREE_OPERAND (exp, 1))
- TREE_OPERAND (exp, 0)
- = invert_truthvalue (TREE_OPERAND (exp, 0));
+ cond = invert_truthvalue (TREE_OPERAND (exp, 0));
+ else
+ cond = TREE_OPERAND (exp, 0);
- result = do_store_flag (TREE_OPERAND (exp, 0),
- (safe_from_p (temp, singleton, 1)
- ? temp : NULL_RTX),
+ result = do_store_flag (cond, (safe_from_p (temp, singleton, 1)
+ ? temp : NULL_RTX),
mode, BRANCH_COST <= 1);
if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
return expand_binop (mode, boptab, op1, result, temp,
unsignedp, OPTAB_LIB_WIDEN);
}
- else if (singleton == TREE_OPERAND (exp, 1))
- TREE_OPERAND (exp, 0)
- = invert_truthvalue (TREE_OPERAND (exp, 0));
}
do_pending_stack_adjust ();
|| (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER))
temp = gen_reg_rtx (mode);
- store_expr (singleton, temp, 0);
+ store_expr (singleton, temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
}
else
expand_expr (singleton,
store_expr (build (TREE_CODE (binary_op), type,
make_tree (type, temp),
TREE_OPERAND (binary_op, 1)),
- temp, 0);
+ temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
else
store_expr (build1 (TREE_CODE (unary_op), type,
make_tree (type, temp)),
- temp, 0);
+ temp, modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
/* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
if (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
- store_expr (TREE_OPERAND (exp, 1), temp, 0);
+ store_expr (TREE_OPERAND (exp, 1), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpif (TREE_OPERAND (exp, 0), op0);
start_cleanup_deferral ();
- store_expr (TREE_OPERAND (exp, 2), temp, 0);
+ store_expr (TREE_OPERAND (exp, 2), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
else if (temp
if (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
- store_expr (TREE_OPERAND (exp, 2), temp, 0);
+ store_expr (TREE_OPERAND (exp, 2), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpifnot (TREE_OPERAND (exp, 0), op0);
start_cleanup_deferral ();
- store_expr (TREE_OPERAND (exp, 1), temp, 0);
+ store_expr (TREE_OPERAND (exp, 1), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
op1 = op0;
}
else
example A ? throw : E */
if (temp != 0
&& TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
- store_expr (TREE_OPERAND (exp, 1), temp, 0);
+ store_expr (TREE_OPERAND (exp, 1), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
else
expand_expr (TREE_OPERAND (exp, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
start_cleanup_deferral ();
if (temp != 0
&& TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
- store_expr (TREE_OPERAND (exp, 2), temp, 0);
+ store_expr (TREE_OPERAND (exp, 2), temp,
+ modifier == EXPAND_STACK_PARM ? 2 : 0);
else
expand_expr (TREE_OPERAND (exp, 2),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
/* Mark it as expanded. */
TREE_OPERAND (exp, 1) = NULL_TREE;
- store_expr (exp1, target, 0);
+ store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
return expand_increment (exp, ! ignore, ignore);
case ADDR_EXPR:
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
/* Are we taking the address of a nested function? */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
&& decl_function_context (TREE_OPERAND (exp, 0)) != 0
abort ();
emit_block_move (new, op0, expr_size (TREE_OPERAND (exp, 0)),
- BLOCK_OP_NORMAL);
+ (modifier == EXPAND_STACK_PARM
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
op0 = new;
}
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
binop2:
+ if (modifier == EXPAND_STACK_PARM)
+ target = 0;
temp = expand_binop (mode, this_optab, op0, op1, target,
unsignedp, OPTAB_LIB_WIDEN);
if (temp == 0)