/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988-2013 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "machmode.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "attribs.h"
#include "function.h"
#include "insn-config.h"
#include "insn-attr.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
#include "expr.h"
+#include "insn-codes.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "intl.h"
#include "tm_p.h"
#include "tree-iterator.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
#include "basic-block.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-expr.h"
-#include "is-a.h"
#include "gimple.h"
#include "gimple-ssa.h"
#include "cgraph.h"
#include "params.h"
#include "tree-ssa-address.h"
#include "cfgexpand.h"
-
-/* Decide whether a function's arguments should be processed
- from first to last or from last to first.
-
- They should if the stack and args grow in opposite directions, but
- only if we have push insns. */
-
-#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
-
-#ifndef STACK_PUSH_CODE
-#ifdef STACK_GROWS_DOWNWARD
-#define STACK_PUSH_CODE PRE_DEC
-#else
-#define STACK_PUSH_CODE PRE_INC
-#endif
-#endif
+#include "builtins.h"
+#include "tree-chkp.h"
+#include "rtl-chkp.h"
+#include "ccmp.h"
/* If this is nonzero, we do not bother generating VOLATILE
int explicit_inc_to;
unsigned HOST_WIDE_INT len;
HOST_WIDE_INT offset;
- rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode);
+ rtx (*constfun) (void *, HOST_WIDE_INT, machine_mode);
void *constfundata;
int reverse;
};
unsigned HOST_WIDE_INT);
static tree emit_block_move_libcall_fn (int);
static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
-static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, enum machine_mode);
+static rtx clear_by_pieces_1 (void *, HOST_WIDE_INT, machine_mode);
static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
static void store_by_pieces_1 (struct store_by_pieces_d *, unsigned int);
static void store_by_pieces_2 (insn_gen_fn, machine_mode,
struct store_by_pieces_d *);
static tree clear_storage_libcall_fn (int);
-static rtx compress_float_constant (rtx, rtx);
+static rtx_insn *compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
- HOST_WIDE_INT, enum machine_mode,
+ HOST_WIDE_INT, machine_mode,
tree, int, alias_set_type);
static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT,
unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
- enum machine_mode, tree, alias_set_type, bool);
+ machine_mode, tree, alias_set_type, bool);
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, const_tree);
static int is_aligning_offset (const_tree, const_tree);
-static void expand_operands (tree, tree, rtx, rtx*, rtx*,
- enum expand_modifier);
static rtx reduce_to_bit_field_precision (rtx, rtx, tree);
-static rtx do_store_flag (sepops, rtx, enum machine_mode);
+static rtx do_store_flag (sepops, rtx, machine_mode);
#ifdef PUSH_ROUNDING
-static void emit_single_push_insn (enum machine_mode, rtx, tree);
+static void emit_single_push_insn (machine_mode, rtx, tree);
#endif
-static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx, int);
+static void do_tablejump (rtx, machine_mode, rtx, rtx, rtx, int);
static rtx const_vector_from_tree (tree);
-static void write_complex_part (rtx, rtx, bool);
-
-/* This macro is used to determine whether move_by_pieces should be called
- to perform a structure copy. */
-#ifndef MOVE_BY_PIECES_P
-#define MOVE_BY_PIECES_P(SIZE, ALIGN) \
- (move_by_pieces_ninsns (SIZE, ALIGN, MOVE_MAX_PIECES + 1) \
- < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
-#endif
-
-/* This macro is used to determine whether clear_by_pieces should be
- called to clear storage. */
-#ifndef CLEAR_BY_PIECES_P
-#define CLEAR_BY_PIECES_P(SIZE, ALIGN) \
- (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) CLEAR_RATIO (optimize_insn_for_speed_p ()))
-#endif
-
-/* This macro is used to determine whether store_by_pieces should be
- called to "memset" storage with byte values other than zero. */
-#ifndef SET_BY_PIECES_P
-#define SET_BY_PIECES_P(SIZE, ALIGN) \
- (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) SET_RATIO (optimize_insn_for_speed_p ()))
-#endif
+static tree tree_expr_size (const_tree);
+static HOST_WIDE_INT int_expr_size (tree);
-/* This macro is used to determine whether store_by_pieces should be
- called 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_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
- < (unsigned int) MOVE_RATIO (optimize_insn_for_speed_p ()))
-#endif
\f
/* This is run to set up which modes can be used
directly in memory and to initialize the block move optab. It is run
init_expr_target (void)
{
rtx insn, pat;
- enum machine_mode mode;
+ machine_mode mode;
int num_clobbers;
rtx mem, mem1;
rtx reg;
/* Try indexing by frame ptr and try by stack ptr.
It is known that on the Convex the stack ptr isn't a valid index.
With luck, one or the other is valid on any machine. */
- mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
- mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
+ mem = gen_rtx_MEM (word_mode, stack_pointer_rtx);
+ mem1 = gen_rtx_MEM (word_mode, frame_pointer_rtx);
/* A scratch register we can modify in-place below to avoid
useless RTL allocations. */
- reg = gen_rtx_REG (VOIDmode, -1);
+ reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
insn = rtx_alloc (INSN);
- pat = gen_rtx_SET (VOIDmode, NULL_RTX, NULL_RTX);
+ pat = gen_rtx_SET (NULL_RTX, NULL_RTX);
PATTERN (insn) = pat;
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
- mode = (enum machine_mode) ((int) mode + 1))
+ mode = (machine_mode) ((int) mode + 1))
{
int regno;
direct_load[(int) mode] = direct_store[(int) mode] = 0;
PUT_MODE (mem, mode);
PUT_MODE (mem1, mode);
- PUT_MODE (reg, mode);
/* See if there is some register that can be used in this mode and
directly loaded or stored from memory. */
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
- SET_REGNO (reg, regno);
+ set_mode_and_regno (reg, mode, regno);
SET_SRC (pat) = mem;
SET_DEST (pat) = reg;
}
}
- mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000));
+ mem = gen_rtx_MEM (VOIDmode, gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1));
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- enum machine_mode srcmode;
+ machine_mode srcmode;
for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode;
srcmode = GET_MODE_WIDER_MODE (srcmode))
{
void
convert_move (rtx to, rtx from, int unsignedp)
{
- enum machine_mode to_mode = GET_MODE (to);
- enum machine_mode from_mode = GET_MODE (from);
+ machine_mode to_mode = GET_MODE (to);
+ machine_mode from_mode = GET_MODE (from);
int to_real = SCALAR_FLOAT_MODE_P (to_mode);
int from_real = SCALAR_FLOAT_MODE_P (from_mode);
enum insn_code code;
if (GET_CODE (from) == SUBREG && SUBREG_PROMOTED_VAR_P (from)
&& (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (from)))
>= GET_MODE_PRECISION (to_mode))
- && SUBREG_PROMOTED_UNSIGNED_P (from) == unsignedp)
+ && SUBREG_CHECK_PROMOTED_SIGN (from, unsignedp))
from = gen_lowpart (to_mode, from), from_mode = to_mode;
gcc_assert (GET_CODE (to) != SUBREG || !SUBREG_PROMOTED_VAR_P (to));
if (to_real)
{
- rtx value, insns;
+ rtx value;
+ rtx_insn *insns;
convert_optab tab;
gcc_assert ((GET_MODE_PRECISION (from_mode)
}
/* Handle pointer conversion. */ /* SPEE 900220. */
+ /* If the target has a converter from FROM_MODE to TO_MODE, use it. */
+ {
+ convert_optab ctab;
+
+ if (GET_MODE_PRECISION (from_mode) > GET_MODE_PRECISION (to_mode))
+ ctab = trunc_optab;
+ else if (unsignedp)
+ ctab = zext_optab;
+ else
+ ctab = sext_optab;
+
+ if (convert_optab_handler (ctab, to_mode, from_mode)
+ != CODE_FOR_nothing)
+ {
+ emit_unop_insn (convert_optab_handler (ctab, to_mode, from_mode),
+ to, from, UNKNOWN);
+ return;
+ }
+ }
+
/* Targets are expected to provide conversion insns between PxImode and
xImode for all MODE_PARTIAL_INT modes they use, but no others. */
if (GET_MODE_CLASS (to_mode) == MODE_PARTIAL_INT)
{
- enum machine_mode full_mode
+ machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)
if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT)
{
rtx new_from;
- enum machine_mode full_mode
+ machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
convert_optab ctab = unsignedp ? zext_optab : sext_optab;
enum insn_code icode;
if (GET_MODE_PRECISION (from_mode) < GET_MODE_PRECISION (to_mode)
&& GET_MODE_PRECISION (to_mode) > BITS_PER_WORD)
{
- rtx insns;
+ rtx_insn *insns;
rtx lowpart;
rtx fill_value;
rtx lowfrom;
int i;
- enum machine_mode lowpart_mode;
+ machine_mode lowpart_mode;
int nwords = CEIL (GET_MODE_SIZE (to_mode), UNITS_PER_WORD);
/* Try converting directly if the insn is supported. */
if (unsignedp)
fill_value = const0_rtx;
else
- fill_value = emit_store_flag (gen_reg_rtx (word_mode),
- LT, lowfrom, const0_rtx,
- VOIDmode, 0, -1);
+ fill_value = emit_store_flag_force (gen_reg_rtx (word_mode),
+ LT, lowfrom, const0_rtx,
+ lowpart_mode, 0, -1);
/* Fill the remaining words. */
for (i = GET_MODE_SIZE (lowpart_mode) / UNITS_PER_WORD; i < nwords; i++)
}
else
{
- enum machine_mode intermediate;
+ machine_mode intermediate;
rtx tmp;
int shift_amount;
or by copying to a new temporary with conversion. */
rtx
-convert_to_mode (enum machine_mode mode, rtx x, int unsignedp)
+convert_to_mode (machine_mode mode, rtx x, int unsignedp)
{
return convert_modes (mode, VOIDmode, x, unsignedp);
}
You can give VOIDmode for OLDMODE, if you are sure X has a nonvoid mode. */
rtx
-convert_modes (enum machine_mode mode, enum machine_mode oldmode, rtx x, int unsignedp)
+convert_modes (machine_mode mode, machine_mode oldmode, rtx x, int unsignedp)
{
rtx temp;
if (GET_CODE (x) == SUBREG && SUBREG_PROMOTED_VAR_P (x)
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) >= GET_MODE_SIZE (mode)
- && SUBREG_PROMOTED_UNSIGNED_P (x) == unsignedp)
- x = gen_lowpart (mode, x);
+ && SUBREG_CHECK_PROMOTED_SIGN (x, unsignedp))
+ x = gen_lowpart (mode, SUBREG_REG (x));
if (GET_MODE (x) != VOIDmode)
oldmode = GET_MODE (x);
if (mode == oldmode)
return x;
- /* There is one case that we must handle specially: If we are converting
- a CONST_INT into a mode whose size is twice HOST_BITS_PER_WIDE_INT and
- we are to interpret the constant as unsigned, gen_lowpart will do
- the wrong if the constant appears negative. What we want to do is
- make the high-order word of the constant zero, not all ones. */
-
- if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_BITSIZE (mode) == HOST_BITS_PER_DOUBLE_INT
- && CONST_INT_P (x) && INTVAL (x) < 0)
+ if (CONST_SCALAR_INT_P (x) && GET_MODE_CLASS (mode) == MODE_INT)
{
- double_int val = double_int::from_uhwi (INTVAL (x));
-
- /* We need to zero extend VAL. */
- if (oldmode != VOIDmode)
- val = val.zext (GET_MODE_BITSIZE (oldmode));
-
- return immed_double_int_const (val, mode);
+ /* If the caller did not tell us the old mode, then there is not
+ much to do with respect to canonicalization. We have to
+ assume that all the bits are significant. */
+ if (GET_MODE_CLASS (oldmode) != MODE_INT)
+ oldmode = MAX_MODE_INT;
+ wide_int w = wide_int::from (std::make_pair (x, oldmode),
+ GET_MODE_PRECISION (mode),
+ unsignedp ? UNSIGNED : SIGNED);
+ return immed_wide_int_const (w, mode);
}
/* We can do this with a gen_lowpart if both desired and current modes
are integer, and this is either a constant integer, a register, or a
- non-volatile MEM. Except for the constant case where MODE is no
- wider than HOST_BITS_PER_WIDE_INT, we must be narrowing the operand. */
-
- if ((CONST_INT_P (x)
- && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT)
- || (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_CLASS (oldmode) == MODE_INT
- && (CONST_DOUBLE_AS_INT_P (x)
- || (GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
- && ((MEM_P (x) && ! MEM_VOLATILE_P (x)
- && direct_load[(int) mode])
- || (REG_P (x)
- && (! HARD_REGISTER_P (x)
- || HARD_REGNO_MODE_OK (REGNO (x), mode))
- && TRULY_NOOP_TRUNCATION_MODES_P (mode,
- GET_MODE (x))))))))
- {
- /* ?? If we don't know OLDMODE, we have to assume here that
- X does not need sign- or zero-extension. This may not be
- the case, but it's the best we can do. */
- if (CONST_INT_P (x) && oldmode != VOIDmode
- && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (oldmode))
- {
- HOST_WIDE_INT val = INTVAL (x);
-
- /* We must sign or zero-extend in this case. Start by
- zero-extending, then sign extend if we need to. */
- val &= GET_MODE_MASK (oldmode);
- if (! unsignedp
- && val_signbit_known_set_p (oldmode, val))
- val |= ~GET_MODE_MASK (oldmode);
-
- return gen_int_mode (val, mode);
- }
-
- return gen_lowpart (mode, x);
- }
+ non-volatile MEM. */
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_CLASS (oldmode) == MODE_INT
+ && GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (oldmode)
+ && ((MEM_P (x) && !MEM_VOLATILE_P (x) && direct_load[(int) mode])
+ || (REG_P (x)
+ && (!HARD_REGISTER_P (x)
+ || HARD_REGNO_MODE_OK (REGNO (x), mode))
+ && TRULY_NOOP_TRUNCATION_MODES_P (mode, GET_MODE (x)))))
+
+ return gen_lowpart (mode, x);
/* Converting from integer constant into mode is always equivalent to an
subreg operation. */
static unsigned int
alignment_for_piecewise_move (unsigned int max_pieces, unsigned int align)
{
- enum machine_mode tmode;
+ machine_mode tmode;
tmode = mode_for_size (max_pieces * BITS_PER_UNIT, MODE_INT, 1);
if (align >= GET_MODE_ALIGNMENT (tmode))
align = GET_MODE_ALIGNMENT (tmode);
else
{
- enum machine_mode tmode, xmode;
+ machine_mode tmode, xmode;
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT), xmode = tmode;
tmode != VOIDmode;
/* Return the widest integer mode no wider than SIZE. If no such mode
can be found, return VOIDmode. */
-static enum machine_mode
+static machine_mode
widest_int_mode_for_size (unsigned int size)
{
- enum machine_mode tmode, mode = VOIDmode;
+ machine_mode tmode, mode = VOIDmode;
for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
return mode;
}
-/* STORE_MAX_PIECES is the number of bytes at a time that we can
- store efficiently. Due to internal GCC limitations, this is
- MOVE_MAX_PIECES limited by the number of bytes GCC can represent
- for an immediate constant. */
-
-#define STORE_MAX_PIECES MIN (MOVE_MAX_PIECES, 2 * sizeof (HOST_WIDE_INT))
-
/* Determine whether the LEN bytes can be moved by using several move
instructions. Return nonzero if a call to move_by_pieces should
succeed. */
int
-can_move_by_pieces (unsigned HOST_WIDE_INT len ATTRIBUTE_UNUSED,
- unsigned int align ATTRIBUTE_UNUSED)
+can_move_by_pieces (unsigned HOST_WIDE_INT len,
+ unsigned int align)
{
- return MOVE_BY_PIECES_P (len, align);
+ return targetm.use_by_pieces_infrastructure_p (len, align, MOVE_BY_PIECES,
+ optimize_insn_for_speed_p ());
}
/* Generate several move instructions to copy LEN bytes from block FROM to
unsigned int align, int endp)
{
struct move_by_pieces_d data;
- enum machine_mode to_addr_mode;
- enum machine_mode from_addr_mode = get_address_mode (from);
+ machine_mode to_addr_mode;
+ machine_mode from_addr_mode = get_address_mode (from);
rtx to_addr, from_addr = XEXP (from, 0);
unsigned int max_size = MOVE_MAX_PIECES + 1;
enum insn_code icode;
to_addr = NULL_RTX;
data.to = NULL_RTX;
data.autinc_to = 1;
-#ifdef STACK_GROWS_DOWNWARD
- data.reverse = 1;
-#else
- data.reverse = 0;
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ data.reverse = 1;
+ else
+ data.reverse = 0;
}
data.to_addr = to_addr;
data.from = from;
/* Find the mode of the largest move...
MODE might not be used depending on the definitions of the
USE_* macros below. */
- enum machine_mode mode ATTRIBUTE_UNUSED
+ machine_mode mode ATTRIBUTE_UNUSED
= widest_int_mode_for_size (max_size);
if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from)
while (max_size > 1 && data.len > 0)
{
- enum machine_mode mode = widest_int_mode_for_size (max_size);
+ machine_mode mode = widest_int_mode_for_size (max_size);
if (mode == VOIDmode)
break;
while (max_size > 1 && l > 0)
{
- enum machine_mode mode;
+ machine_mode mode;
enum insn_code icode;
mode = widest_int_mode_for_size (max_size);
set_mem_size (y, INTVAL (size));
}
- if (CONST_INT_P (size) && MOVE_BY_PIECES_P (INTVAL (size), align))
+ if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align))
move_by_pieces (x, y, INTVAL (size), align, 0);
else if (emit_block_move_via_movmem (x, y, size, align,
expected_align, expected_size,
arg = TYPE_ARG_TYPES (TREE_TYPE (fn));
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
- enum machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+ machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
rtx tmp = targetm.calls.function_arg (args_so_far, mode,
NULL_TREE, true);
if (!tmp || !REG_P (tmp))
unsigned HOST_WIDE_INT probable_max_size)
{
int save_volatile_ok = volatile_ok;
- enum machine_mode mode;
+ machine_mode mode;
if (expected_align < align)
expected_align = align;
{
rtx dst_addr, src_addr;
tree call_expr, fn, src_tree, dst_tree, size_tree;
- enum machine_mode size_mode;
+ machine_mode size_mode;
rtx retval;
/* Emit code to copy the addresses of DST and SRC and SIZE into new
emit_block_move_via_loop (rtx x, rtx y, rtx size,
unsigned int align ATTRIBUTE_UNUSED)
{
- rtx cmp_label, top_label, iter, x_addr, y_addr, tmp;
- enum machine_mode x_addr_mode = get_address_mode (x);
- enum machine_mode y_addr_mode = get_address_mode (y);
- enum machine_mode iter_mode;
+ rtx_code_label *cmp_label, *top_label;
+ rtx iter, x_addr, y_addr, tmp;
+ machine_mode x_addr_mode = get_address_mode (x);
+ machine_mode y_addr_mode = get_address_mode (y);
+ machine_mode iter_mode;
iter_mode = GET_MODE (size);
if (iter_mode == VOIDmode)
The number of registers to be filled is NREGS. */
void
-move_block_to_reg (int regno, rtx x, int nregs, enum machine_mode mode)
+move_block_to_reg (int regno, rtx x, int nregs, machine_mode mode)
{
int i;
-#ifdef HAVE_load_multiple
rtx pat;
- rtx last;
-#endif
+ rtx_insn *last;
if (nregs == 0)
return;
x = validize_mem (force_const_mem (mode, x));
/* See if the machine can do this with a load multiple insn. */
-#ifdef HAVE_load_multiple
if (HAVE_load_multiple)
{
last = get_last_insn ();
else
delete_insns_since (last);
}
-#endif
for (i = 0; i < nregs; i++)
emit_move_insn (gen_rtx_REG (word_mode, regno + i),
return;
/* See if the machine can do this with a store multiple insn. */
-#ifdef HAVE_store_multiple
if (HAVE_store_multiple)
{
- rtx last = get_last_insn ();
+ rtx_insn *last = get_last_insn ();
rtx pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
GEN_INT (nregs));
if (pat)
else
delete_insns_since (last);
}
-#endif
for (i = 0; i < nregs; i++)
{
for (; i < length; i++)
{
- enum machine_mode mode = GET_MODE (XEXP (XVECEXP (orig, 0, i), 0));
+ 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);
{
rtx src;
int start, i;
- enum machine_mode m = GET_MODE (orig_src);
+ machine_mode m = GET_MODE (orig_src);
gcc_assert (GET_CODE (dst) == PARALLEL);
&& !MEM_P (orig_src)
&& GET_CODE (orig_src) != CONCAT)
{
- enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
+ machine_mode imode = int_mode_for_mode (GET_MODE (orig_src));
if (imode == BLKmode)
src = assign_stack_temp (GET_MODE (orig_src), ssize);
else
/* Process the pieces. */
for (i = start; i < XVECLEN (dst, 0); i++)
{
- enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
+ machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
unsigned int bytelen = GET_MODE_SIZE (mode);
int shift = 0;
{
rtx first, second;
+ /* TODO: const_wide_int can have sizes other than this... */
gcc_assert (2 * len == ssize);
split_double (src, &first, &second);
if (i)
{
rtx *tmps, dst;
int start, finish, i;
- enum machine_mode m = GET_MODE (orig_dst);
+ machine_mode m = GET_MODE (orig_dst);
gcc_assert (GET_CODE (src) == PARALLEL);
if (!SCALAR_INT_MODE_P (m)
&& !MEM_P (orig_dst) && GET_CODE (orig_dst) != CONCAT)
{
- enum machine_mode imode = int_mode_for_mode (GET_MODE (orig_dst));
+ machine_mode imode = int_mode_for_mode (GET_MODE (orig_dst));
if (imode == BLKmode)
dst = assign_stack_temp (GET_MODE (orig_dst), ssize);
else
/* It is unclear if we can ever reach here, but we may as well handle
it. Allocate a temporary, and split this into a store/load to/from
the temporary. */
-
temp = assign_stack_temp (GET_MODE (dst), ssize);
emit_group_store (temp, src, type, ssize);
emit_group_load (dst, temp, type, ssize);
}
else if (!MEM_P (dst) && GET_CODE (dst) != CONCAT)
{
- enum machine_mode outer = GET_MODE (dst);
- enum machine_mode inner;
+ machine_mode outer = GET_MODE (dst);
+ machine_mode inner;
HOST_WIDE_INT bytepos;
bool done = false;
rtx temp;
for (i = start; i < finish; i++)
{
HOST_WIDE_INT bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
- enum machine_mode mode = GET_MODE (tmps[i]);
+ machine_mode mode = GET_MODE (tmps[i]);
unsigned int bytelen = GET_MODE_SIZE (mode);
- unsigned int adj_bytelen = bytelen;
+ unsigned int adj_bytelen;
rtx dest = dst;
/* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
adj_bytelen = ssize - bytepos;
+ else
+ adj_bytelen = bytelen;
if (GET_CODE (dst) == CONCAT)
{
}
else
{
- enum machine_mode dest_mode = GET_MODE (dest);
- enum machine_mode tmp_mode = GET_MODE (tmps[i]);
+ machine_mode dest_mode = GET_MODE (dest);
+ machine_mode tmp_mode = GET_MODE (tmps[i]);
gcc_assert (bytepos == 0 && XVECLEN (src, 0));
}
}
+ /* Handle trailing fragments that run over the size of the struct. */
if (ssize >= 0 && bytepos + (HOST_WIDE_INT) bytelen > ssize)
{
/* store_bit_field always takes its value from the lsb.
tmps[i] = expand_shift (RSHIFT_EXPR, mode, tmps[i],
shift, tmps[i], 0);
}
- bytelen = adj_bytelen;
+
+ /* Make sure not to write past the end of the struct. */
+ store_bit_field (dest,
+ adj_bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
+ bytepos * BITS_PER_UNIT, ssize * BITS_PER_UNIT - 1,
+ VOIDmode, tmps[i]);
}
/* Optimize the access just a bit. */
- if (MEM_P (dest)
- && (! SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
- || MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
- && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
- && bytelen == GET_MODE_SIZE (mode))
+ else if (MEM_P (dest)
+ && (!SLOW_UNALIGNED_ACCESS (mode, MEM_ALIGN (dest))
+ || MEM_ALIGN (dest) >= GET_MODE_ALIGNMENT (mode))
+ && bytepos * BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+ && bytelen == GET_MODE_SIZE (mode))
emit_move_insn (adjust_address (dest, mode, bytepos), tmps[i]);
+
else
store_bit_field (dest, bytelen * BITS_PER_UNIT, bytepos * BITS_PER_UNIT,
0, 0, mode, tmps[i]);
rtx
maybe_emit_group_store (rtx x, tree type)
{
- enum machine_mode mode = TYPE_MODE (type);
+ machine_mode mode = TYPE_MODE (type);
gcc_checking_assert (GET_MODE (x) == VOIDmode || GET_MODE (x) == mode);
if (GET_CODE (x) == PARALLEL)
{
rtx src = NULL, dst = NULL;
unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
- enum machine_mode mode = GET_MODE (srcreg);
- enum machine_mode tmode = GET_MODE (target);
- enum machine_mode copy_mode;
+ machine_mode mode = GET_MODE (srcreg);
+ machine_mode tmode = GET_MODE (target);
+ machine_mode copy_mode;
/* BLKmode registers created in the back-end shouldn't have survived. */
gcc_assert (mode != BLKmode);
copy_mode = word_mode;
if (MEM_P (target))
{
- enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
+ machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
if (mem_mode != BLKmode)
copy_mode = mem_mode;
}
This is used on targets that return BLKmode values in registers. */
rtx
-copy_blkmode_to_reg (enum machine_mode mode, tree src)
+copy_blkmode_to_reg (machine_mode mode, tree src)
{
int i, n_regs;
unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0, bytes;
unsigned int bitsize;
rtx *dst_words, dst, x, src_word = NULL_RTX, dst_word = NULL_RTX;
- enum machine_mode dst_mode;
+ machine_mode dst_mode;
gcc_assert (TYPE_MODE (TREE_TYPE (src)) == BLKmode);
to by CALL_FUSAGE. REG must denote a hard register. */
void
-use_reg_mode (rtx *call_fusage, rtx reg, enum machine_mode mode)
+use_reg_mode (rtx *call_fusage, rtx reg, machine_mode mode)
{
- gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
+ gcc_assert (REG_P (reg));
+
+ if (!HARD_REGISTER_P (reg))
+ return;
*call_fusage
= gen_rtx_EXPR_LIST (mode, gen_rtx_USE (VOIDmode, reg), *call_fusage);
}
+/* Add a CLOBBER expression for REG to the (possibly empty) list pointed
+ to by CALL_FUSAGE. REG must denote a hard register. */
+
+void
+clobber_reg_mode (rtx *call_fusage, rtx reg, machine_mode mode)
+{
+ gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
+
+ *call_fusage
+ = gen_rtx_EXPR_LIST (mode, gen_rtx_CLOBBER (VOIDmode, reg), *call_fusage);
+}
+
/* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs,
starting at REGNO. All of these registers must be hard registers. */
return def_stmt;
}
-#ifdef HAVE_conditional_move
/* Return the defining gimple statement for SSA_NAME NAME if it is an
assigment and the class of the expresion on the RHS is CLASS. Return
NULL otherwise. */
return def_stmt;
}
-#endif
\f
/* Determine whether the LEN bytes generated by CONSTFUN can be
int
can_store_by_pieces (unsigned HOST_WIDE_INT len,
- rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
+ rtx (*constfun) (void *, HOST_WIDE_INT, machine_mode),
void *constfundata, unsigned int align, bool memsetp)
{
unsigned HOST_WIDE_INT l;
unsigned int max_size;
HOST_WIDE_INT offset = 0;
- enum machine_mode mode;
+ machine_mode mode;
enum insn_code icode;
int reverse;
/* cst is set but not used if LEGITIMATE_CONSTANT doesn't use it. */
if (len == 0)
return 1;
- if (! (memsetp
- ? SET_BY_PIECES_P (len, align)
- : STORE_BY_PIECES_P (len, align)))
+ if (!targetm.use_by_pieces_infrastructure_p (len, align,
+ memsetp
+ ? SET_BY_PIECES
+ : STORE_BY_PIECES,
+ optimize_insn_for_speed_p ()))
return 0;
align = alignment_for_piecewise_move (STORE_MAX_PIECES, align);
rtx
store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
- rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
+ rtx (*constfun) (void *, HOST_WIDE_INT, machine_mode),
void *constfundata, unsigned int align, bool memsetp, int endp)
{
- enum machine_mode to_addr_mode = get_address_mode (to);
+ machine_mode to_addr_mode = get_address_mode (to);
struct store_by_pieces_d data;
if (len == 0)
return to;
}
- gcc_assert (memsetp
- ? SET_BY_PIECES_P (len, align)
- : STORE_BY_PIECES_P (len, align));
+ gcc_assert (targetm.use_by_pieces_infrastructure_p
+ (len, align,
+ memsetp
+ ? SET_BY_PIECES
+ : STORE_BY_PIECES,
+ optimize_insn_for_speed_p ()));
+
data.constfun = constfun;
data.constfundata = constfundata;
data.len = len;
static rtx
clear_by_pieces_1 (void *data ATTRIBUTE_UNUSED,
HOST_WIDE_INT offset ATTRIBUTE_UNUSED,
- enum machine_mode mode ATTRIBUTE_UNUSED)
+ machine_mode mode ATTRIBUTE_UNUSED)
{
return const0_rtx;
}
store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED,
unsigned int align ATTRIBUTE_UNUSED)
{
- enum machine_mode to_addr_mode = get_address_mode (data->to);
+ machine_mode to_addr_mode = get_address_mode (data->to);
rtx to_addr = XEXP (data->to, 0);
unsigned int max_size = STORE_MAX_PIECES + 1;
enum insn_code icode;
/* Determine the main mode we'll be using.
MODE might not be used depending on the definitions of the
USE_* macros below. */
- enum machine_mode mode ATTRIBUTE_UNUSED
+ machine_mode mode ATTRIBUTE_UNUSED
= widest_int_mode_for_size (max_size);
if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to)
while (max_size > 1 && data->len > 0)
{
- enum machine_mode mode = widest_int_mode_for_size (max_size);
+ machine_mode mode = widest_int_mode_for_size (max_size);
if (mode == VOIDmode)
break;
unsigned HOST_WIDE_INT max_size,
unsigned HOST_WIDE_INT probable_max_size)
{
- enum machine_mode mode = GET_MODE (object);
+ machine_mode mode = GET_MODE (object);
unsigned int align;
gcc_assert (method == BLOCK_OP_NORMAL || method == BLOCK_OP_TAILCALL);
align = MEM_ALIGN (object);
if (CONST_INT_P (size)
- && CLEAR_BY_PIECES_P (INTVAL (size), align))
+ && targetm.use_by_pieces_infrastructure_p (INTVAL (size), align,
+ CLEAR_BY_PIECES,
+ optimize_insn_for_speed_p ()))
clear_by_pieces (object, INTVAL (size), align);
else if (set_storage_via_setmem (object, size, const0_rtx, align,
expected_align, expected_size,
set_storage_via_libcall (rtx object, rtx size, rtx val, bool tailcall)
{
tree call_expr, fn, object_tree, size_tree, val_tree;
- enum machine_mode size_mode;
+ machine_mode size_mode;
rtx retval;
/* Emit code to copy OBJECT and SIZE into new pseudos. We can then
including more than one in the machine description unless
the more limited one has some advantage. */
- enum machine_mode mode;
+ machine_mode mode;
if (expected_align < align)
expected_align = align;
/* Write to one of the components of the complex value CPLX. Write VAL to
the real part if IMAG_P is false, and the imaginary part if its true. */
-static void
+void
write_complex_part (rtx cplx, rtx val, bool imag_p)
{
- enum machine_mode cmode;
- enum machine_mode imode;
+ machine_mode cmode;
+ machine_mode imode;
unsigned ibitsize;
if (GET_CODE (cplx) == CONCAT)
where the natural size of floating-point regs is 32-bit. */
|| (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+ && REG_NREGS (cplx) % 2 == 0))
{
rtx part = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
static rtx
read_complex_part (rtx cplx, bool imag_p)
{
- enum machine_mode cmode, imode;
+ machine_mode cmode, imode;
unsigned ibitsize;
if (GET_CODE (cplx) == CONCAT)
where the natural size of floating-point regs is 32-bit. */
|| (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
+ && REG_NREGS (cplx) % 2 == 0))
{
rtx ret = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
we'll force-create a SUBREG if needed. */
static rtx
-emit_move_change_mode (enum machine_mode new_mode,
- enum machine_mode old_mode, rtx x, bool force)
+emit_move_change_mode (machine_mode new_mode,
+ machine_mode old_mode, rtx x, bool force)
{
rtx ret;
an integer mode of the same size as MODE. Returns the instruction
emitted, or NULL if such a move could not be generated. */
-static rtx
-emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
+static rtx_insn *
+emit_move_via_integer (machine_mode mode, rtx x, rtx y, bool force)
{
- enum machine_mode imode;
+ machine_mode imode;
enum insn_code code;
/* There must exist a mode of the exact size we require. */
imode = int_mode_for_mode (mode);
if (imode == BLKmode)
- return NULL_RTX;
+ return NULL;
/* The target must support moves in this mode. */
code = optab_handler (mov_optab, imode);
if (code == CODE_FOR_nothing)
- return NULL_RTX;
+ return NULL;
x = emit_move_change_mode (imode, mode, x, force);
if (x == NULL_RTX)
- return NULL_RTX;
+ return NULL;
y = emit_move_change_mode (imode, mode, y, force);
if (y == NULL_RTX)
- return NULL_RTX;
+ return NULL;
return emit_insn (GEN_FCN (code) (x, y));
}
/* A subroutine of emit_move_insn_1. X is a push_operand in MODE.
Return an equivalent MEM that does not use an auto-increment. */
-static rtx
-emit_move_resolve_push (enum machine_mode mode, rtx x)
+rtx
+emit_move_resolve_push (machine_mode mode, rtx x)
{
enum rtx_code code = GET_CODE (XEXP (x, 0));
HOST_WIDE_INT adjust;
X is known to satisfy push_operand, and MODE is known to be complex.
Returns the last instruction emitted. */
-rtx
-emit_move_complex_push (enum machine_mode mode, rtx x, rtx y)
+rtx_insn *
+emit_move_complex_push (machine_mode mode, rtx x, rtx y)
{
- enum machine_mode submode = GET_MODE_INNER (mode);
+ machine_mode submode = GET_MODE_INNER (mode);
bool imag_first;
#ifdef PUSH_ROUNDING
/* A subroutine of emit_move_complex. Perform the move from Y to X
via two moves of the parts. Returns the last instruction emitted. */
-rtx
+rtx_insn *
emit_move_complex_parts (rtx x, rtx y)
{
/* Show the output dies here. This is necessary for SUBREGs
/* A subroutine of emit_move_insn_1. Generate a move from Y into X.
MODE is known to be complex. Returns the last instruction emitted. */
-static rtx
-emit_move_complex (enum machine_mode mode, rtx x, rtx y)
+static rtx_insn *
+emit_move_complex (machine_mode mode, rtx x, rtx y)
{
bool try_int;
&& optab_handler (mov_optab, GET_MODE_INNER (mode)) != CODE_FOR_nothing
&& !(REG_P (x)
&& HARD_REGISTER_P (x)
- && hard_regno_nregs[REGNO (x)][mode] == 1)
+ && REG_NREGS (x) == 1)
&& !(REG_P (y)
&& HARD_REGISTER_P (y)
- && hard_regno_nregs[REGNO (y)][mode] == 1))
+ && REG_NREGS (y) == 1))
try_int = false;
/* Not possible if the values are inherently not adjacent. */
else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
if (try_int)
{
- rtx ret;
+ rtx_insn *ret;
/* For memory to memory moves, optimal behavior can be had with the
existing block move logic. */
/* A subroutine of emit_move_insn_1. Generate a move from Y into X.
MODE is known to be MODE_CC. Returns the last instruction emitted. */
-static rtx
-emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
+static rtx_insn *
+emit_move_ccmode (machine_mode mode, rtx x, rtx y)
{
- rtx ret;
+ rtx_insn *ret;
/* Assume all MODE_CC modes are equivalent; if we have movcc, use it. */
if (mode != CCmode)
static bool
undefined_operand_subword_p (const_rtx op, int i)
{
- enum machine_mode innermode, innermostmode;
+ machine_mode innermode, innermostmode;
int offset;
if (GET_CODE (op) != SUBREG)
return false;
pattern. Note that you will get better code if you define such
patterns, even if they must turn into multiple assembler instructions. */
-static rtx
-emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
+static rtx_insn *
+emit_move_multi_word (machine_mode mode, rtx x, rtx y)
{
- rtx last_insn = 0;
- rtx seq, inner;
+ rtx_insn *last_insn = 0;
+ rtx_insn *seq;
+ rtx inner;
bool need_clobber;
int i;
Called just like emit_move_insn, but assumes X and Y
are basically valid. */
-rtx
+rtx_insn *
emit_move_insn_1 (rtx x, rtx y)
{
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
enum insn_code code;
gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT
|| ALL_FIXED_POINT_MODE_P (mode))
{
- rtx result = emit_move_via_integer (mode, x, y, true);
+ rtx_insn *result = emit_move_via_integer (mode, x, y, true);
/* If we can't find an integer mode, use multi words. */
if (result)
fits within a HOST_WIDE_INT. */
if (!CONSTANT_P (y) || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
- rtx ret = emit_move_via_integer (mode, x, y, lra_in_progress);
+ rtx_insn *ret = emit_move_via_integer (mode, x, y, lra_in_progress);
if (ret)
{
Return the last instruction emitted. */
-rtx
+rtx_insn *
emit_move_insn (rtx x, rtx y)
{
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
rtx y_cst = NULL_RTX;
- rtx last_insn, set;
+ rtx_insn *last_insn;
+ rtx set;
gcc_assert (mode != BLKmode
&& (GET_MODE (y) == mode || GET_MODE (y) == VOIDmode));
return last_insn;
}
+/* Generate the body of an instruction to copy Y into X.
+ It may be a list of insns, if one insn isn't enough. */
+
+rtx_insn *
+gen_move_insn (rtx x, rtx y)
+{
+ rtx_insn *seq;
+
+ start_sequence ();
+ emit_move_insn_1 (x, y);
+ seq = get_insns ();
+ end_sequence ();
+ return seq;
+}
+
+/* Same as above, but return rtx (used as a callback, which must have
+ prototype compatible with other functions returning rtx). */
+
+rtx
+gen_move_insn_uncast (rtx x, rtx y)
+{
+ return gen_move_insn (x, y);
+}
+
/* If Y is representable exactly in a narrower mode, and the target can
perform the extension directly from constant or memory, then emit the
move as an extension. */
-static rtx
+static rtx_insn *
compress_float_constant (rtx x, rtx y)
{
- enum machine_mode dstmode = GET_MODE (x);
- enum machine_mode orig_srcmode = GET_MODE (y);
- enum machine_mode srcmode;
+ machine_mode dstmode = GET_MODE (x);
+ machine_mode orig_srcmode = GET_MODE (y);
+ machine_mode srcmode;
REAL_VALUE_TYPE r;
int oldcost, newcost;
bool speed = optimize_insn_for_speed_p ();
srcmode = GET_MODE_WIDER_MODE (srcmode))
{
enum insn_code ic;
- rtx trunc_y, last_insn;
+ rtx trunc_y;
+ rtx_insn *last_insn;
/* Skip if the target can't extend this way. */
ic = can_extend_p (dstmode, srcmode, 0);
into a new pseudo. This constant may be used in different modes,
and if not, combine will put things back together for us. */
trunc_y = force_reg (srcmode, trunc_y);
- emit_unop_insn (ic, x, trunc_y, UNKNOWN);
+
+ /* If x is a hard register, perform the extension into a pseudo,
+ so that e.g. stack realignment code is aware of it. */
+ rtx target = x;
+ if (REG_P (x) && HARD_REGISTER_P (x))
+ target = gen_reg_rtx (dstmode);
+
+ emit_unop_insn (ic, target, trunc_y, UNKNOWN);
last_insn = get_last_insn ();
- if (REG_P (x))
+ if (REG_P (target))
set_unique_reg_note (last_insn, REG_EQUAL, y);
+ if (target != x)
+ return emit_move_insn (x, target);
return last_insn;
}
- return NULL_RTX;
+ return NULL;
}
\f
/* Pushing data onto the stack. */
anti_adjust_stack (temp);
}
-#ifndef STACK_GROWS_DOWNWARD
- if (0)
-#else
- if (1)
-#endif
+ if (STACK_GROWS_DOWNWARD)
{
temp = virtual_outgoing_args_rtx;
if (extra != 0 && below)
cannot be trivially extracted, the return value is INT_MIN. */
HOST_WIDE_INT
-find_args_size_adjust (rtx insn)
+find_args_size_adjust (rtx_insn *insn)
{
rtx dest, set, pat;
int i;
}
int
-fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
+fixup_args_size_notes (rtx_insn *prev, rtx_insn *last, int end_args_size)
{
int args_size = end_args_size;
bool saw_unknown = false;
- rtx insn;
+ rtx_insn *insn;
for (insn = last; insn != prev; insn = PREV_INSN (insn))
{
saw_unknown = true;
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
-#ifdef STACK_GROWS_DOWNWARD
- this_delta = -(unsigned HOST_WIDE_INT) this_delta;
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ this_delta = -(unsigned HOST_WIDE_INT) this_delta;
+
args_size -= this_delta;
}
/* Emit single push insn. */
static void
-emit_single_push_insn_1 (enum machine_mode mode, rtx x, tree type)
+emit_single_push_insn_1 (machine_mode mode, rtx x, tree type)
{
rtx dest_addr;
unsigned rounded_size = PUSH_ROUNDING (GET_MODE_SIZE (mode));
emit_move_insn (stack_pointer_rtx,
expand_binop (Pmode,
-#ifdef STACK_GROWS_DOWNWARD
- sub_optab,
-#else
- add_optab,
-#endif
+ STACK_GROWS_DOWNWARD ? sub_optab
+ : add_optab,
stack_pointer_rtx,
gen_int_mode (rounded_size, Pmode),
NULL_RTX, 0, OPTAB_LIB_WIDEN));
offset = (HOST_WIDE_INT) padding_size;
-#ifdef STACK_GROWS_DOWNWARD
- if (STACK_PUSH_CODE == POST_DEC)
+ if (STACK_GROWS_DOWNWARD && STACK_PUSH_CODE == POST_DEC)
/* We have already decremented the stack pointer, so get the
previous value. */
offset += (HOST_WIDE_INT) rounded_size;
-#else
- if (STACK_PUSH_CODE == POST_INC)
+
+ if (!STACK_GROWS_DOWNWARD && STACK_PUSH_CODE == POST_INC)
/* We have already incremented the stack pointer, so get the
previous value. */
offset -= (HOST_WIDE_INT) rounded_size;
-#endif
+
dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
gen_int_mode (offset, Pmode));
}
else
{
-#ifdef STACK_GROWS_DOWNWARD
- /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */
- dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- gen_int_mode (-(HOST_WIDE_INT) rounded_size,
- Pmode));
-#else
- /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */
- dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- gen_int_mode (rounded_size, Pmode));
-#endif
+ if (STACK_GROWS_DOWNWARD)
+ /* ??? This seems wrong if STACK_PUSH_CODE == POST_DEC. */
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ gen_int_mode (-(HOST_WIDE_INT) rounded_size,
+ Pmode));
+ else
+ /* ??? This seems wrong if STACK_PUSH_CODE == POST_INC. */
+ dest_addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ gen_int_mode (rounded_size, Pmode));
+
dest_addr = gen_rtx_PRE_MODIFY (Pmode, stack_pointer_rtx, dest_addr);
}
{
set_mem_attributes (dest, type, 1);
- if (flag_optimize_sibling_calls)
+ if (cfun->tail_call_marked)
/* 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
/* Emit and annotate a single push insn. */
static void
-emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
+emit_single_push_insn (machine_mode mode, rtx x, tree type)
{
int delta, old_delta = stack_pointer_delta;
- rtx prev = get_last_insn ();
- rtx last;
+ rtx_insn *prev = get_last_insn ();
+ rtx_insn *last;
emit_single_push_insn_1 (mode, x, type);
}
#endif
+/* If reading SIZE bytes from X will end up reading from
+ Y return the number of bytes that overlap. Return -1
+ if there is no overlap or -2 if we can't determine
+ (for example when X and Y have different base registers). */
+
+static int
+memory_load_overlap (rtx x, rtx y, HOST_WIDE_INT size)
+{
+ rtx tmp = plus_constant (Pmode, x, size);
+ rtx sub = simplify_gen_binary (MINUS, Pmode, tmp, y);
+
+ if (!CONST_INT_P (sub))
+ return -2;
+
+ HOST_WIDE_INT val = INTVAL (sub);
+
+ return IN_RANGE (val, 1, size) ? val : -1;
+}
+
/* 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
carry mode info).
SIZE is an rtx for the size of data to be copied (in bytes),
needed only if X is BLKmode.
+ Return true if successful. May return false if asked to push a
+ partial argument during a sibcall optimization (as specified by
+ SIBCALL_P) and the incoming and outgoing pointers cannot be shown
+ to not overlap.
ALIGN (in bits) is maximum alignment we can assume.
for arguments passed in registers. If nonzero, it will be the number
of bytes required. */
-void
-emit_push_insn (rtx x, enum machine_mode mode, tree type, rtx size,
+bool
+emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
unsigned int align, int partial, rtx reg, int extra,
rtx args_addr, rtx args_so_far, int reg_parm_stack_space,
- rtx alignment_pad)
+ rtx alignment_pad, bool sibcall_p)
{
rtx xinner;
- enum direction stack_direction
-#ifdef STACK_GROWS_DOWNWARD
- = downward;
-#else
- = upward;
-#endif
+ enum direction stack_direction = STACK_GROWS_DOWNWARD ? downward : upward;
/* Decide where to pad the argument: `downward' for below,
`upward' for above, or `none' for don't pad it.
xinner = x;
+ int nregs = partial / UNITS_PER_WORD;
+ rtx *tmp_regs = NULL;
+ int overlapping = 0;
+
if (mode == BLKmode
|| (STRICT_ALIGNMENT && align < GET_MODE_ALIGNMENT (mode)))
{
&& CONST_INT_P (size)
&& skip == 0
&& MEM_ALIGN (xinner) >= align
- && (MOVE_BY_PIECES_P ((unsigned) INTVAL (size) - used, align))
+ && can_move_by_pieces ((unsigned) INTVAL (size) - used, align)
/* Here we avoid the case of a structure whose weak alignment
forces many pushes of a small amount of data,
and such small pushes do rounding that causes trouble. */
PARM_BOUNDARY. Assume the caller isn't lying. */
set_mem_align (target, align);
+ /* If part should go in registers and pushing to that part would
+ overwrite some of the values that need to go into regs, load the
+ overlapping values into temporary pseudos to be moved into the hard
+ regs at the end after the stack pushing has completed.
+ We cannot load them directly into the hard regs here because
+ they can be clobbered by the block move expansions.
+ See PR 65358. */
+
+ if (partial > 0 && reg != 0 && mode == BLKmode
+ && GET_CODE (reg) != PARALLEL)
+ {
+ overlapping = memory_load_overlap (XEXP (x, 0), temp, partial);
+ if (overlapping > 0)
+ {
+ gcc_assert (overlapping % UNITS_PER_WORD == 0);
+ overlapping /= UNITS_PER_WORD;
+
+ tmp_regs = XALLOCAVEC (rtx, overlapping);
+
+ for (int i = 0; i < overlapping; i++)
+ tmp_regs[i] = gen_reg_rtx (word_mode);
+
+ for (int i = 0; i < overlapping; i++)
+ emit_move_insn (tmp_regs[i],
+ operand_subword_force (target, i, mode));
+ }
+ else if (overlapping == -1)
+ overlapping = 0;
+ /* Could not determine whether there is overlap.
+ Fail the sibcall. */
+ else
+ {
+ overlapping = 0;
+ if (sibcall_p)
+ return false;
+ }
+ }
emit_block_move (target, xinner, size, BLOCK_OP_CALL_PARM);
}
}
/* Loop over all the words allocated on the stack for this arg. */
/* We can do it by words, because any scalar bigger than a word
has a size a multiple of a word. */
-#ifndef PUSH_ARGS_REVERSED
- for (i = not_stack; i < size; i++)
-#else
for (i = size - 1; i >= not_stack; i--)
-#endif
if (i >= not_stack + offset)
- emit_push_insn (operand_subword_force (x, i, mode),
+ if (!emit_push_insn (operand_subword_force (x, i, mode),
word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
* UNITS_PER_WORD)),
- reg_parm_stack_space, alignment_pad);
+ reg_parm_stack_space, alignment_pad, sibcall_p))
+ return false;
}
else
{
}
}
- /* If part should go in registers, copy that part
- into the appropriate registers. Do this now, at the end,
- since mem-to-mem copies above may do function calls. */
+ /* Move the partial arguments into the registers and any overlapping
+ values that we moved into the pseudos in tmp_regs. */
if (partial > 0 && reg != 0)
{
/* Handle calls that pass values in multiple non-contiguous locations.
if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x, type, -1);
else
- {
+ {
gcc_assert (partial % UNITS_PER_WORD == 0);
- move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode);
+ move_block_to_reg (REGNO (reg), x, nregs - overlapping, mode);
+
+ for (int i = 0; i < overlapping; i++)
+ emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg)
+ + nregs - overlapping + i),
+ tmp_regs[i]);
+
}
}
if (alignment_pad && args_addr == 0)
anti_adjust_stack (alignment_pad);
+
+ return true;
}
\f
/* Return X if X can be used as a subtarget in a sequence of arithmetic
unsigned HOST_WIDE_INT bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- enum machine_mode mode1, rtx str_rtx,
+ machine_mode mode1, rtx str_rtx,
tree to, tree src)
{
- enum machine_mode str_mode = GET_MODE (str_rtx);
+ machine_mode str_mode = GET_MODE (str_rtx);
unsigned int str_bitsize = GET_MODE_BITSIZE (str_mode);
tree op0, op1;
rtx value, result;
useful purpose. This can occur in Ada. */
if (handled_component_p (TREE_OPERAND (exp, 0)))
{
- enum machine_mode rmode;
+ machine_mode rmode;
HOST_WIDE_INT rbitsize, rbitpos;
tree roffset;
int unsignedp;
{
rtx to_rtx = 0;
rtx result;
- enum machine_mode mode;
+ machine_mode mode;
unsigned int align;
enum insn_code icode;
expand_insn (icode, 2, ops);
}
else
- store_bit_field (mem, GET_MODE_BITSIZE (mode),
- 0, 0, 0, mode, reg);
+ store_bit_field (mem, GET_MODE_BITSIZE (mode), 0, 0, 0, mode, reg);
return;
}
&& mem_ref_refers_to_non_mem_p (to))
|| TREE_CODE (TREE_TYPE (to)) == ARRAY_TYPE)
{
- enum machine_mode mode1;
+ machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
unsigned HOST_WIDE_INT bitregion_start = 0;
unsigned HOST_WIDE_INT bitregion_end = 0;
if (TREE_CODE (to) == COMPONENT_REF
&& DECL_BIT_FIELD_TYPE (TREE_OPERAND (to, 1)))
get_bit_range (&bitregion_start, &bitregion_end, to, &bitpos, &offset);
+ /* The C++ memory model naturally applies to byte-aligned fields.
+ However, if we do not have a DECL_BIT_FIELD_TYPE but BITPOS or
+ BITSIZE are not byte-aligned, there is no need to limit the range
+ we can access. This can occur with packed structures in Ada. */
+ else if (bitsize > 0
+ && bitsize % BITS_PER_UNIT == 0
+ && bitpos % BITS_PER_UNIT == 0)
+ {
+ bitregion_start = bitpos;
+ bitregion_end = bitpos + bitsize - 1;
+ }
to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_WRITE);
- /* If the bitfield is volatile, we want to access it in the
+ /* If the field has a mode, we want to access it in the
field's mode, not the computed mode.
If a MEM has VOIDmode (external with incomplete type),
use BLKmode for it instead. */
if (MEM_P (to_rtx))
{
- if (volatilep && flag_strict_volatile_bitfields > 0)
+ if (mode1 != VOIDmode)
to_rtx = adjust_address (to_rtx, mode1, 0);
else if (GET_MODE (to_rtx) == VOIDmode)
to_rtx = adjust_address (to_rtx, BLKmode, 0);
if (offset != 0)
{
- enum machine_mode address_mode;
+ machine_mode address_mode;
rtx offset_rtx;
if (!MEM_P (to_rtx))
offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
address_mode = get_address_mode (to_rtx);
if (GET_MODE (offset_rtx) != address_mode)
- offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ {
+ /* We cannot be sure that the RTL in offset_rtx is valid outside
+ of a memory address context, so force it into a register
+ before attempting to convert it to the desired mode. */
+ offset_rtx = force_operand (offset_rtx, NULL_RTX);
+ offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ }
+
+ /* If we have an expression in OFFSET_RTX and a non-zero
+ byte offset in BITPOS, adding the byte offset before the
+ OFFSET_RTX results in better intermediate code, which makes
+ later rtl optimization passes perform better.
+
+ We prefer intermediate code like this:
+
+ r124:DI=r123:DI+0x18
+ [r124:DI]=r121:DI
+
+ ... instead of ...
- /* A constant address in TO_RTX can have VOIDmode, we must not try
- to call force_reg for that case. Avoid that case. */
- if (MEM_P (to_rtx)
- && GET_MODE (to_rtx) == BLKmode
- && GET_MODE (XEXP (to_rtx, 0)) != VOIDmode
+ r124:DI=r123:DI+0x10
+ [r124:DI+0x8]=r121:DI
+
+ This is only done for aligned data values, as these can
+ be expected to result in single move instructions. */
+ if (mode1 != VOIDmode
+ && bitpos != 0
&& bitsize > 0
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
- && MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
+ && MEM_ALIGN (to_rtx) >= GET_MODE_ALIGNMENT (mode1))
{
to_rtx = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
+ bitregion_start = 0;
+ if (bitregion_end >= (unsigned HOST_WIDE_INT) bitpos)
+ bitregion_end -= bitpos;
bitpos = 0;
}
|| TREE_CODE (to) == SSA_NAME))
{
rtx value;
+ rtx bounds;
push_temp_slots ();
value = expand_normal (from);
+
+ /* Split value and bounds to store them separately. */
+ chkp_split_slot (value, &value, &bounds);
+
if (to_rtx == 0)
to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE);
emit_move_insn (to_rtx, value);
}
+
+ /* Store bounds if required. */
+ if (bounds
+ && (BOUNDED_P (to) || chkp_type_has_pointer (TREE_TYPE (to))))
+ {
+ gcc_assert (MEM_P (to_rtx));
+ chkp_emit_bounds_store (bounds, value, to_rtx);
+ }
+
preserve_temp_slots (to_rtx);
pop_temp_slots ();
return;
/* Compute FROM and store the value in the rtx we got. */
push_temp_slots ();
- result = store_expr (from, to_rtx, 0, nontemporal);
+ result = store_expr_with_bounds (from, to_rtx, 0, nontemporal, to);
preserve_temp_slots (result);
pop_temp_slots ();
return;
emit_storent_insn (rtx to, rtx from)
{
struct expand_operand ops[2];
- enum machine_mode mode = GET_MODE (to);
+ machine_mode mode = GET_MODE (to);
enum insn_code code = optab_handler (storent_optab, mode);
if (code == CODE_FOR_nothing)
If CALL_PARAM_P is nonzero, this is a store into a call param on the
stack, and block moves may need to be treated specially.
- If NONTEMPORAL is true, try using a nontemporal store instruction. */
+ If NONTEMPORAL is true, try using a nontemporal store instruction.
+
+ If BTARGET is not NULL then computed bounds of EXP are
+ associated with BTARGET. */
rtx
-store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
+store_expr_with_bounds (tree exp, rtx target, int call_param_p,
+ bool nontemporal, tree btarget)
{
rtx temp;
rtx alt_rtl = NULL_RTX;
part. */
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
- return store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
- nontemporal);
+ return store_expr_with_bounds (TREE_OPERAND (exp, 1), target,
+ call_param_p, nontemporal, btarget);
}
else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
{
side. This avoids the creation of unnecessary temporaries.
For non-BLKmode, it is more efficient not to do this. */
- rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+ rtx_code_label *lab1 = gen_label_rtx (), *lab2 = gen_label_rtx ();
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1, -1);
- store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
- nontemporal);
+ store_expr_with_bounds (TREE_OPERAND (exp, 1), target, call_param_p,
+ nontemporal, btarget);
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
- store_expr (TREE_OPERAND (exp, 2), target, call_param_p,
- nontemporal);
+ store_expr_with_bounds (TREE_OPERAND (exp, 2), target, call_param_p,
+ nontemporal, btarget);
emit_label (lab2);
OK_DEFER_POP;
&& GET_MODE_PRECISION (GET_MODE (target))
== TYPE_PRECISION (TREE_TYPE (exp)))
{
- if (TYPE_UNSIGNED (TREE_TYPE (exp))
- != SUBREG_PROMOTED_UNSIGNED_P (target))
+ if (!SUBREG_CHECK_PROMOTED_SIGN (target,
+ TYPE_UNSIGNED (TREE_TYPE (exp))))
{
/* Some types, e.g. Fortran's logical*4, won't have a signed
version, so use the mode instead. */
tree ntype
= (signed_or_unsigned_type_for
- (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)));
+ (SUBREG_PROMOTED_SIGN (target), TREE_TYPE (exp)));
if (ntype == NULL)
ntype = lang_hooks.types.type_for_mode
(TYPE_MODE (TREE_TYPE (exp)),
- SUBREG_PROMOTED_UNSIGNED_P (target));
+ SUBREG_PROMOTED_SIGN (target));
exp = fold_convert_loc (loc, ntype, exp);
}
exp = fold_convert_loc (loc, lang_hooks.types.type_for_mode
(GET_MODE (SUBREG_REG (target)),
- SUBREG_PROMOTED_UNSIGNED_P (target)),
+ SUBREG_PROMOTED_SIGN (target)),
exp);
inner_target = SUBREG_REG (target);
temp = expand_expr (exp, inner_target, VOIDmode,
call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
+ /* Handle bounds returned by call. */
+ if (TREE_CODE (exp) == CALL_EXPR)
+ {
+ rtx bounds;
+ chkp_split_slot (temp, &temp, &bounds);
+ if (bounds && btarget)
+ {
+ gcc_assert (TREE_CODE (btarget) == SSA_NAME);
+ rtx tmp = targetm.calls.load_returned_bounds (bounds);
+ chkp_set_rtl_bounds (btarget, tmp);
+ }
+ }
+
/* If TEMP is a VOIDmode constant, use convert_modes to make
sure that we properly convert it. */
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode)
{
temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
- temp, SUBREG_PROMOTED_UNSIGNED_P (target));
+ temp, SUBREG_PROMOTED_SIGN (target));
temp = convert_modes (GET_MODE (SUBREG_REG (target)),
GET_MODE (target), temp,
- SUBREG_PROMOTED_UNSIGNED_P (target));
+ SUBREG_PROMOTED_SIGN (target));
}
convert_move (SUBREG_REG (target), temp,
- SUBREG_PROMOTED_UNSIGNED_P (target));
+ SUBREG_PROMOTED_SIGN (target));
return NULL_RTX;
}
temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
- &alt_rtl);
+ &alt_rtl, false);
+
+ /* Handle bounds returned by call. */
+ if (TREE_CODE (exp) == CALL_EXPR)
+ {
+ rtx bounds;
+ chkp_split_slot (temp, &temp, &bounds);
+ if (bounds && btarget)
+ {
+ gcc_assert (TREE_CODE (btarget) == SSA_NAME);
+ rtx tmp = targetm.calls.load_returned_bounds (bounds);
+ chkp_set_rtl_bounds (btarget, tmp);
+ }
+ }
}
/* If TEMP is a VOIDmode constant and the mode of the type of EXP is not
the same as that of TARGET, adjust the constant. This is needed, for
- example, in case it is a CONST_DOUBLE and we want only a word-sized
- value. */
+ example, in case it is a CONST_DOUBLE or CONST_WIDE_INT and we want
+ only a word-sized value. */
if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode
&& TREE_CODE (exp) != ERROR_MARK
&& GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
else
{
- enum machine_mode pointer_mode
+ machine_mode pointer_mode
= targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target));
- enum machine_mode address_mode = get_address_mode (target);
+ machine_mode address_mode = get_address_mode (target);
/* Compute the size of the data to copy from the string. */
tree copy_size
= expand_expr (copy_size, NULL_RTX, VOIDmode,
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL));
- rtx label = 0;
+ rtx_code_label *label = 0;
/* Copy that much. */
copy_size_rtx = convert_to_mode (pointer_mode, copy_size_rtx,
return NULL_RTX;
}
+
+/* Same as store_expr_with_bounds but ignoring bounds of EXP. */
+rtx
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
+{
+ return store_expr_with_bounds (exp, target, call_param_p, nontemporal, NULL);
+}
\f
/* Return true if field F of structure TYPE is a flexible array. */
static void
store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
- HOST_WIDE_INT bitpos, enum machine_mode mode,
+ HOST_WIDE_INT bitpos, machine_mode mode,
tree exp, int cleared, alias_set_type alias_set)
{
if (TREE_CODE (exp) == CONSTRUCTOR
corresponding field of TARGET. */
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, field, value)
{
- enum machine_mode mode;
+ machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos = 0;
tree offset;
if (offset)
{
- enum machine_mode address_mode;
+ machine_mode address_mode;
rtx offset_rtx;
offset
elements. */
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), i, index, value)
{
- enum machine_mode mode;
+ machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
rtx xtarget = target;
}
else
{
- rtx loop_start = gen_label_rtx ();
- rtx loop_end = gen_label_rtx ();
+ rtx_code_label *loop_start = gen_label_rtx ();
+ rtx_code_label *loop_end = gen_label_rtx ();
tree exit_cond;
expand_normal (hi_index);
int icode = CODE_FOR_nothing;
tree elttype = TREE_TYPE (type);
int elt_size = tree_to_uhwi (TYPE_SIZE (elttype));
- enum machine_mode eltmode = TYPE_MODE (elttype);
+ machine_mode eltmode = TYPE_MODE (elttype);
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
rtvec vector = NULL;
n_elts = TYPE_VECTOR_SUBPARTS (type);
if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
{
- enum machine_mode mode = GET_MODE (target);
+ machine_mode mode = GET_MODE (target);
icode = (int) optab_handler (vec_init_optab, mode);
/* Don't use vec_init<mode> if some elements have VECTOR_TYPE. */
}
else
{
- enum machine_mode value_mode =
+ machine_mode value_mode =
TREE_CODE (TREE_TYPE (value)) == VECTOR_TYPE
? TYPE_MODE (TREE_TYPE (value))
: eltmode;
store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
unsigned HOST_WIDE_INT bitregion_start,
unsigned HOST_WIDE_INT bitregion_end,
- enum machine_mode mode, tree exp,
+ machine_mode mode, tree exp,
alias_set_type alias_set, bool nontemporal)
{
if (TREE_CODE (exp) == ERROR_MARK)
&& mode != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
- /* If the modes of TEMP and TARGET are both BLKmode, both
- must be in memory and BITPOS must be aligned on a byte
- boundary. If so, we simply do a block copy. Likewise
- for a BLKmode-like TARGET. */
- if (GET_MODE (temp) == BLKmode
+ /* If TEMP is not a PARALLEL (see below) and its mode and that of TARGET
+ are both BLKmode, both must be in memory and BITPOS must be aligned
+ on a byte boundary. If so, we simply do a block copy. Likewise for
+ a BLKmode-like TARGET. */
+ if (GET_CODE (temp) != PARALLEL
+ && GET_MODE (temp) == BLKmode
&& (GET_MODE (target) == BLKmode
|| (MEM_P (target)
&& GET_MODE_CLASS (GET_MODE (target)) == MODE_INT
{
HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
rtx temp_target;
- if (mode == BLKmode)
+ if (mode == BLKmode || mode == VOIDmode)
mode = smallest_mode_for_size (size * BITS_PER_UNIT, MODE_INT);
temp_target = gen_reg_rtx (mode);
emit_group_store (temp_target, temp, TREE_TYPE (exp), size);
tree
get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
HOST_WIDE_INT *pbitpos, tree *poffset,
- enum machine_mode *pmode, int *punsignedp,
+ machine_mode *pmode, int *punsignedp,
int *pvolatilep, bool keep_aligning)
{
tree size_tree = 0;
- enum machine_mode mode = VOIDmode;
+ machine_mode mode = VOIDmode;
bool blkmode_bitfield = false;
tree offset = size_zero_node;
- double_int bit_offset = double_int_zero;
+ offset_int bit_offset = 0;
/* First get the mode, signedness, and size. We do this from just the
outermost expression. */
switch (TREE_CODE (exp))
{
case BIT_FIELD_REF:
- bit_offset += tree_to_double_int (TREE_OPERAND (exp, 2));
+ bit_offset += wi::to_offset (TREE_OPERAND (exp, 2));
break;
case COMPONENT_REF:
break;
offset = size_binop (PLUS_EXPR, offset, this_offset);
- bit_offset += tree_to_double_int (DECL_FIELD_BIT_OFFSET (field));
+ bit_offset += wi::to_offset (DECL_FIELD_BIT_OFFSET (field));
/* ??? Right now we don't do anything with DECL_OFFSET_ALIGN. */
}
break;
case IMAGPART_EXPR:
- bit_offset += double_int::from_uhwi (*pbitsize);
+ bit_offset += *pbitsize;
break;
case VIEW_CONVERT_EXPR:
tree off = TREE_OPERAND (exp, 1);
if (!integer_zerop (off))
{
- double_int boff, coff = mem_ref_offset (exp);
- boff = coff.lshift (BITS_PER_UNIT == 8
- ? 3 : exact_log2 (BITS_PER_UNIT));
+ offset_int boff, coff = mem_ref_offset (exp);
+ boff = wi::lshift (coff, LOG2_BITS_PER_UNIT);
bit_offset += boff;
}
exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
this conversion. */
if (TREE_CODE (offset) == INTEGER_CST)
{
- double_int tem = tree_to_double_int (offset);
- tem = tem.sext (TYPE_PRECISION (sizetype));
- tem = tem.lshift (BITS_PER_UNIT == 8 ? 3 : exact_log2 (BITS_PER_UNIT));
+ offset_int tem = wi::sext (wi::to_offset (offset),
+ TYPE_PRECISION (sizetype));
+ tem = wi::lshift (tem, LOG2_BITS_PER_UNIT);
tem += bit_offset;
- if (tem.fits_shwi ())
+ if (wi::fits_shwi_p (tem))
{
*pbitpos = tem.to_shwi ();
*poffset = offset = NULL_TREE;
if (offset)
{
/* Avoid returning a negative bitpos as this may wreak havoc later. */
- if (bit_offset.is_negative ())
+ if (wi::neg_p (bit_offset) || !wi::fits_shwi_p (bit_offset))
{
- double_int mask
- = double_int::mask (BITS_PER_UNIT == 8
- ? 3 : exact_log2 (BITS_PER_UNIT));
- double_int tem = bit_offset.and_not (mask);
+ offset_int mask = wi::mask <offset_int> (LOG2_BITS_PER_UNIT, false);
+ offset_int tem = bit_offset.and_not (mask);
/* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
Subtract it to BIT_OFFSET and add it (scaled) to OFFSET. */
bit_offset -= tem;
- tem = tem.arshift (BITS_PER_UNIT == 8
- ? 3 : exact_log2 (BITS_PER_UNIT),
- HOST_BITS_PER_DOUBLE_INT);
+ tem = wi::arshift (tem, LOG2_BITS_PER_UNIT);
offset = size_binop (PLUS_EXPR, offset,
- double_int_to_tree (sizetype, tem));
+ wide_int_to_tree (sizetype, tem));
}
*pbitpos = bit_offset.to_shwi ();
return exp;
}
-/* Return a tree of sizetype representing the size, in bytes, of the element
- of EXP, an ARRAY_REF or an ARRAY_RANGE_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)));
- location_t loc = EXPR_LOCATION (exp);
-
- /* 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)
- {
- /* ??? tree_ssa_useless_type_conversion will eliminate casts to
- sizetype from another type of the same width and signedness. */
- if (TREE_TYPE (aligned_size) != sizetype)
- aligned_size = fold_convert_loc (loc, sizetype, aligned_size);
- return size_binop_loc (loc, MULT_EXPR, aligned_size,
- size_int (TYPE_ALIGN_UNIT (elmt_type)));
- }
-
- /* 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 or an ARRAY_RANGE_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 build_int_cst (TREE_TYPE (TREE_OPERAND (exp, 1)), 0);
-}
-
-/* Returns true if REF is an array reference to an array at the end of
- a structure. If this is the case, the array may be allocated larger
- than its upper bound implies. */
-
-bool
-array_at_struct_end_p (tree ref)
-{
- if (TREE_CODE (ref) != ARRAY_REF
- && TREE_CODE (ref) != ARRAY_RANGE_REF)
- return false;
-
- while (handled_component_p (ref))
- {
- /* If the reference chain contains a component reference to a
- non-union type and there follows another field the reference
- is not at the end of a structure. */
- if (TREE_CODE (ref) == COMPONENT_REF
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 0))) == RECORD_TYPE)
- {
- tree nextf = DECL_CHAIN (TREE_OPERAND (ref, 1));
- while (nextf && TREE_CODE (nextf) != FIELD_DECL)
- nextf = DECL_CHAIN (nextf);
- if (nextf)
- return false;
- }
-
- ref = TREE_OPERAND (ref, 0);
- }
-
- /* If the reference is based on a declared entity, the size of the array
- is constrained by its given domain. */
- if (DECL_P (ref))
- return false;
-
- return true;
-}
-
-/* Return a tree representing the upper bound of the array mentioned in
- EXP, an ARRAY_REF or an ARRAY_RANGE_REF. */
-
-tree
-array_ref_up_bound (tree exp)
-{
- tree domain_type = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (exp, 0)));
-
- /* If there is a domain type and it has an upper bound, use it, substituting
- for a PLACEHOLDER_EXPR as needed. */
- if (domain_type && TYPE_MAX_VALUE (domain_type))
- return SUBSTITUTE_PLACEHOLDER_IN_EXPR (TYPE_MAX_VALUE (domain_type), exp);
-
- /* Otherwise fail. */
- return NULL_TREE;
-}
-
-/* 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);
- location_t loc = EXPR_LOCATION (exp);
-
- /* 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)
- {
- /* ??? tree_ssa_useless_type_conversion will eliminate casts to
- sizetype from another type of the same width and signedness. */
- if (TREE_TYPE (aligned_offset) != sizetype)
- aligned_offset = fold_convert_loc (loc, sizetype, aligned_offset);
- return size_binop_loc (loc, 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);
-}
-
/* Alignment in bits the TARGET of an assignment may be assumed to have. */
static unsigned HOST_WIDE_INT
return MAX (factor, talign);
}
\f
-#ifdef HAVE_conditional_move
/* Convert the tree comparison code TCODE to the rtl one where the
signedness is UNSIGNEDP. */
}
return code;
}
-#endif
/* Subroutine of expand_expr. Expand the two operands of a binary
expression EXP0 and EXP1 placing the results in OP0 and OP1.
The value may be stored in TARGET if TARGET is nonzero. The
MODIFIER argument is as documented by expand_expr. */
-static void
+void
expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
enum expand_modifier modifier)
{
The TARGET, TMODE and MODIFIER arguments are as for expand_expr. */
static rtx
-expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
+expand_expr_addr_expr_1 (tree exp, rtx target, machine_mode tmode,
enum expand_modifier modifier, addr_space_t as)
{
rtx result, subtarget;
tree inner, offset;
HOST_WIDE_INT bitsize, bitpos;
int volatilep, unsignedp;
- enum machine_mode mode1;
+ machine_mode mode1;
/* If we are taking the address of a constant and are at the top level,
we have to use output_constant_def since we can't call force_const_mem
break;
case COMPOUND_LITERAL_EXPR:
- /* Allow COMPOUND_LITERAL_EXPR in initializers, if e.g.
- rtl_for_decl_init is called on DECL_INITIAL with
- COMPOUNT_LITERAL_EXPRs in it, they aren't gimplified. */
- if (modifier == EXPAND_INITIALIZER
- && COMPOUND_LITERAL_EXPR_DECL (exp))
+ /* Allow COMPOUND_LITERAL_EXPR in initializers or coming from
+ initializers, if e.g. rtl_for_decl_init is called on DECL_INITIAL
+ with COMPOUND_LITERAL_EXPRs in it, or ARRAY_REF on a const static
+ array with address of COMPOUND_LITERAL_EXPR in DECL_INITIAL;
+ the initializers aren't gimplified. */
+ if (COMPOUND_LITERAL_EXPR_DECL (exp)
+ && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
return expand_expr_addr_expr_1 (COMPOUND_LITERAL_EXPR_DECL (exp),
target, tmode, modifier, as);
/* FALLTHRU */
modifier == EXPAND_INITIALIZER
? EXPAND_INITIALIZER : EXPAND_NORMAL);
+ /* expand_expr is allowed to return an object in a mode other
+ than TMODE. If it did, we need to convert. */
+ if (GET_MODE (tmp) != VOIDmode && tmode != GET_MODE (tmp))
+ tmp = convert_modes (tmode, GET_MODE (tmp),
+ tmp, TYPE_UNSIGNED (TREE_TYPE (offset)));
result = convert_memory_address_addr_space (tmode, result, as);
tmp = convert_memory_address_addr_space (tmode, tmp, as);
The TARGET, TMODE and MODIFIER arguments are as for expand_expr. */
static rtx
-expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
+expand_expr_addr_expr (tree exp, rtx target, machine_mode tmode,
enum expand_modifier modifier)
{
addr_space_t as = ADDR_SPACE_GENERIC;
- enum machine_mode address_mode = Pmode;
- enum machine_mode pointer_mode = ptr_mode;
- enum machine_mode rmode;
+ machine_mode address_mode = Pmode;
+ machine_mode pointer_mode = ptr_mode;
+ machine_mode rmode;
rtx result;
/* Target mode of VOIDmode says "whatever's natural". */
bool avoid_temp_mem)
{
tree type = TREE_TYPE (exp);
- enum machine_mode mode = TYPE_MODE (type);
+ machine_mode mode = TYPE_MODE (type);
/* Try to avoid creating a temporary at all. This is possible
if all of the initializer is zero.
/* All elts simple constants => refer to a constant in memory. But
if this is a non-BLKmode mode, let it store a field at a time
- since that should make a CONST_INT or CONST_DOUBLE when we
- fold. Likewise, if we have a target we can use, it is best to
- store directly into the target unless the type is large enough
- that memcpy will be used. If we are making an initializer and
- all operands are constant, put it in memory as well.
+ since that should make a CONST_INT, CONST_WIDE_INT or
+ CONST_DOUBLE when we fold. Likewise, if we have a target we can
+ use, it is best to store directly into the target unless the type
+ is large enough that memcpy will be used. If we are making an
+ initializer and all operands are constant, put it in memory as
+ well.
FIXME: Avoid trying to fill vector constructors piece-meal.
Output them with output_constant_def below unless we're sure
&& ! (target != 0 && safe_from_p (target, exp, 1)))
|| TREE_ADDRESSABLE (exp)
|| (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
- && (! MOVE_BY_PIECES_P
+ && (! can_move_by_pieces
(tree_to_uhwi (TYPE_SIZE_UNIT (type)),
TYPE_ALIGN (type)))
&& ! mostly_zeros_p (exp))))
if (avoid_temp_mem)
return NULL_RTX;
- target
- = assign_temp (build_qualified_type (type, (TYPE_QUALS (type)
- | (TREE_READONLY (exp)
- * TYPE_QUAL_CONST))),
- TREE_ADDRESSABLE (exp), 1);
+ target = assign_temp (type, TREE_ADDRESSABLE (exp), 1);
}
store_constructor (exp, target, 0, int_expr_size (exp));
address, and ALT_RTL is non-NULL, then *ALT_RTL is set to the
DECL_RTL of the VAR_DECL. *ALT_RTL is also set if EXP is a
COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
- recursively. */
+ recursively.
+
+ If INNER_REFERENCE_P is true, we are expanding an inner reference.
+ In this case, we don't adjust a returned MEM rtx that wouldn't be
+ sufficiently aligned for its mode; instead, it's up to the caller
+ to deal with it afterwards. This is used to make sure that unaligned
+ base objects for which out-of-bounds accesses are supported, for
+ example record types with trailing arrays, aren't realigned behind
+ the back of the caller.
+ The normal operating mode is to pass FALSE for this parameter. */
rtx
-expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
- enum expand_modifier modifier, rtx *alt_rtl)
+expand_expr_real (tree exp, rtx target, machine_mode tmode,
+ enum expand_modifier modifier, rtx *alt_rtl,
+ bool inner_reference_p)
{
rtx ret;
return ret ? ret : const0_rtx;
}
- ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl);
+ ret = expand_expr_real_1 (exp, target, tmode, modifier, alt_rtl,
+ inner_reference_p);
return ret;
}
tree treeop1 ATTRIBUTE_UNUSED,
tree treeop2 ATTRIBUTE_UNUSED)
{
-#ifdef HAVE_conditional_move
rtx insn;
rtx op00, op01, op1, op2;
enum rtx_code comparison_code;
- enum machine_mode comparison_mode;
+ machine_mode comparison_mode;
gimple srcstmt;
rtx temp;
tree type = TREE_TYPE (treeop1);
int unsignedp = TYPE_UNSIGNED (type);
- enum machine_mode mode = TYPE_MODE (type);
- enum machine_mode orig_mode = mode;
+ machine_mode mode = TYPE_MODE (type);
+ machine_mode orig_mode = mode;
/* If we cannot do a conditional move on the mode, try doing it
with the promoted mode. */
unsignedp = TYPE_UNSIGNED (type);
comparison_code = convert_tree_comp_to_rtx (cmpcode, unsignedp);
}
- else if (TREE_CODE_CLASS (TREE_CODE (treeop0)) == tcc_comparison)
+ else if (COMPARISON_CLASS_P (treeop0))
{
tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
enum tree_code cmpcode = TREE_CODE (treeop0);
op00 = expand_normal (treeop0);
op01 = const0_rtx;
comparison_code = NE;
- comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
+ comparison_mode = GET_MODE (op00);
+ if (comparison_mode == VOIDmode)
+ comparison_mode = TYPE_MODE (TREE_TYPE (treeop0));
}
if (GET_MODE (op1) != mode)
and return. */
if (insn)
{
- rtx seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
emit_insn (seq);
return convert_modes (orig_mode, mode, temp, 0);
/* Otherwise discard the sequence and fall back to code with
branches. */
end_sequence ();
-#endif
return NULL_RTX;
}
rtx
-expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode,
+expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
enum expand_modifier modifier)
{
rtx op0, op1, op2, temp;
+ rtx_code_label *lab;
tree type;
int unsignedp;
- enum machine_mode mode;
+ machine_mode mode;
enum tree_code code = ops->code;
optab this_optab;
rtx subtarget, original_target;
else if (CONSTANT_P (op0))
{
tree inner_type = TREE_TYPE (treeop0);
- enum machine_mode inner_mode = GET_MODE (op0);
+ machine_mode inner_mode = GET_MODE (op0);
if (inner_mode == VOIDmode)
inner_mode = TYPE_MODE (inner_type);
&& TREE_CONSTANT (treeop1))
{
rtx constant_part;
+ HOST_WIDE_INT wc;
+ machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop1));
op1 = expand_expr (treeop1, subtarget, VOIDmode,
EXPAND_SUM);
- /* Use immed_double_const to ensure that the constant is
+ /* Use wi::shwi to ensure that the constant is
truncated according to the mode of OP1, then sign extended
to a HOST_WIDE_INT. Using the constant directly can result
in non-canonical RTL in a 64x32 cross compile. */
- constant_part
- = immed_double_const (TREE_INT_CST_LOW (treeop0),
- (HOST_WIDE_INT) 0,
- TYPE_MODE (TREE_TYPE (treeop1)));
+ wc = TREE_INT_CST_LOW (treeop0);
+ constant_part =
+ immed_wide_int_const (wi::shwi (wc, wmode), wmode);
op1 = plus_constant (mode, op1, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op1 = force_operand (op1, target);
&& TREE_CONSTANT (treeop0))
{
rtx constant_part;
+ HOST_WIDE_INT wc;
+ machine_mode wmode = TYPE_MODE (TREE_TYPE (treeop0));
op0 = expand_expr (treeop0, subtarget, VOIDmode,
(modifier == EXPAND_INITIALIZER
return simplify_gen_binary (PLUS, mode, op0, op1);
goto binop2;
}
- /* Use immed_double_const to ensure that the constant is
+ /* Use wi::shwi to ensure that the constant is
truncated according to the mode of OP1, then sign extended
to a HOST_WIDE_INT. Using the constant directly can result
in non-canonical RTL in a 64x32 cross compile. */
+ wc = TREE_INT_CST_LOW (treeop1);
constant_part
- = immed_double_const (TREE_INT_CST_LOW (treeop1),
- (HOST_WIDE_INT) 0,
- TYPE_MODE (TREE_TYPE (treeop0)));
+ = immed_wide_int_const (wi::shwi (wc, wmode), wmode);
op0 = plus_constant (mode, op0, INTVAL (constant_part));
if (modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
op0 = force_operand (op0, target);
Thus the following special case checks need only
check the second operand. */
if (TREE_CODE (treeop0) == INTEGER_CST)
- {
- tree t1 = treeop0;
- treeop0 = treeop1;
- treeop1 = t1;
- }
+ std::swap (treeop0, treeop1);
/* First, check if we have a multiplication of one signed and one
unsigned operand. */
&& (TYPE_UNSIGNED (TREE_TYPE (treeop0))
!= TYPE_UNSIGNED (TREE_TYPE (treeop1))))
{
- enum machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
+ machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
this_optab = usmul_widen_optab;
if (find_widening_optab_handler (this_optab, mode, innermode, 0)
!= CODE_FOR_nothing)
== TYPE_UNSIGNED (TREE_TYPE (treeop0))))
{
tree op0type = TREE_TYPE (treeop0);
- enum machine_mode innermode = TYPE_MODE (op0type);
+ machine_mode innermode = TYPE_MODE (op0type);
bool zextend_p = TYPE_UNSIGNED (op0type);
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
}
def0 = get_def_for_expr (treeop0, NEGATE_EXPR);
+ /* The multiplication is commutative - look at its 2nd operand
+ if the first isn't fed by a negate. */
+ if (!def0)
+ {
+ def0 = get_def_for_expr (treeop1, NEGATE_EXPR);
+ /* Swap operands if the 2nd operand is fed by a negate. */
+ if (def0)
+ std::swap (treeop0, treeop1);
+ }
def2 = get_def_for_expr (treeop2, NEGATE_EXPR);
op0 = op2 = NULL;
Thus the following special case checks need only
check the second operand. */
if (TREE_CODE (treeop0) == INTEGER_CST)
- {
- tree t1 = treeop0;
- treeop0 = treeop1;
- treeop1 = t1;
- }
+ std::swap (treeop0, treeop1);
/* Attempt to return something suitable for generating an
indexed address, for machines that support that. */
/* If op1 was placed in target, swap op0 and op1. */
if (target != op0 && target == op1)
- {
- temp = op0;
- op0 = op1;
- op1 = temp;
- }
+ std::swap (op0, op1);
/* We generate better code and avoid problems with op1 mentioning
target by forcing op1 into a pseudo if it isn't a constant. */
if (code == MIN_EXPR)
comparison_code = LT;
}
-#ifdef HAVE_conditional_move
+
/* Use a conditional move if possible. */
if (can_conditionally_move_p (mode))
{
rtx insn;
- /* ??? Same problem as in expmed.c: emit_conditional_move
- forces a stack adjustment via compare_from_rtx, and we
- lose the stack adjustment if the sequence we are about
- to create is discarded. */
- do_pending_stack_adjust ();
-
start_sequence ();
/* Try to emit the conditional move. */
and return. */
if (insn)
{
- rtx seq = get_insns ();
+ rtx_insn *seq = get_insns ();
end_sequence ();
emit_insn (seq);
return target;
branches. */
end_sequence ();
}
-#endif
+
if (target != op0)
emit_move_insn (target, op0);
- temp = gen_label_rtx ();
+ lab = gen_label_rtx ();
do_compare_rtx_and_jump (target, cmpop1, comparison_code,
- unsignedp, mode, NULL_RTX, NULL_RTX, temp,
+ unsignedp, mode, NULL_RTX, NULL, lab,
-1);
}
emit_move_insn (target, op1);
- emit_label (temp);
+ emit_label (lab);
return target;
case BIT_NOT_EXPR:
for unsigned bitfield expand this as XOR with a proper constant
instead. */
if (reduce_bit_field && TYPE_UNSIGNED (type))
- temp = expand_binop (mode, xor_optab, op0,
- immed_double_int_const
- (double_int::mask (TYPE_PRECISION (type)), mode),
- target, 1, OPTAB_LIB_WIDEN);
+ {
+ wide_int mask = wi::mask (TYPE_PRECISION (type),
+ false, GET_MODE_PRECISION (mode));
+
+ temp = expand_binop (mode, xor_optab, op0,
+ immed_wide_int_const (mask, mode),
+ target, 1, OPTAB_LIB_WIDEN);
+ }
else
temp = expand_unop (mode, one_cmpl_optab, op0, target, 1);
gcc_assert (temp);
case UNGE_EXPR:
case UNEQ_EXPR:
case LTGT_EXPR:
- temp = do_store_flag (ops,
- modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
- tmode != VOIDmode ? tmode : mode);
- if (temp)
- return temp;
-
- /* Use a compare and a jump for BLKmode comparisons, or for function
- type comparisons is HAVE_canonicalize_funcptr_for_compare. */
-
- if ((target == 0
- || modifier == EXPAND_STACK_PARM
- || ! safe_from_p (target, treeop0, 1)
- || ! safe_from_p (target, treeop1, 1)
- /* Make sure we don't have a hard reg (such as function's return
- value) live across basic blocks, if not optimizing. */
- || (!optimize && REG_P (target)
- && REGNO (target) < FIRST_PSEUDO_REGISTER)))
- target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+ {
+ temp = do_store_flag (ops,
+ modifier != EXPAND_STACK_PARM ? target : NULL_RTX,
+ tmode != VOIDmode ? tmode : mode);
+ if (temp)
+ return temp;
- emit_move_insn (target, const0_rtx);
+ /* Use a compare and a jump for BLKmode comparisons, or for function
+ type comparisons is HAVE_canonicalize_funcptr_for_compare. */
+
+ if ((target == 0
+ || modifier == EXPAND_STACK_PARM
+ || ! safe_from_p (target, treeop0, 1)
+ || ! safe_from_p (target, treeop1, 1)
+ /* Make sure we don't have a hard reg (such as function's return
+ value) live across basic blocks, if not optimizing. */
+ || (!optimize && REG_P (target)
+ && REGNO (target) < FIRST_PSEUDO_REGISTER)))
+ target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
- op1 = gen_label_rtx ();
- jumpifnot_1 (code, treeop0, treeop1, op1, -1);
+ emit_move_insn (target, const0_rtx);
- if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
- emit_move_insn (target, constm1_rtx);
- else
- emit_move_insn (target, const1_rtx);
+ rtx_code_label *lab1 = gen_label_rtx ();
+ jumpifnot_1 (code, treeop0, treeop1, lab1, -1);
- emit_label (op1);
- return target;
+ if (TYPE_PRECISION (type) == 1 && !TYPE_UNSIGNED (type))
+ emit_move_insn (target, constm1_rtx);
+ else
+ emit_move_insn (target, const1_rtx);
+ emit_label (lab1);
+ return target;
+ }
case COMPLEX_EXPR:
/* Get the rtx code of the operands. */
op0 = expand_normal (treeop0);
GET_MODE_INNER (GET_MODE (target)), 0);
if (reg_overlap_mentioned_p (temp, op1))
{
- enum machine_mode imode = GET_MODE_INNER (GET_MODE (target));
+ machine_mode imode = GET_MODE_INNER (GET_MODE (target));
temp = adjust_address_nv (target, imode,
GET_MODE_SIZE (imode));
if (reg_overlap_mentioned_p (temp, op0))
{
op0 = expand_normal (treeop0);
this_optab = optab_for_tree_code (code, type, optab_default);
- temp = expand_unop (mode, this_optab, op0, target, unsignedp);
+ machine_mode vec_mode = TYPE_MODE (TREE_TYPE (treeop0));
+
+ if (optab_handler (this_optab, vec_mode) != CODE_FOR_nothing)
+ {
+ struct expand_operand ops[2];
+ enum insn_code icode = optab_handler (this_optab, vec_mode);
+
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], op0, vec_mode);
+ if (maybe_expand_insn (icode, 2, ops))
+ {
+ target = ops[0].value;
+ if (GET_MODE (target) != mode)
+ return gen_lowpart (tmode, target);
+ return target;
+ }
+ }
+ /* Fall back to optab with vector result, and then extract scalar. */
+ this_optab = scalar_reduc_to_vector (this_optab, type);
+ temp = expand_unop (vec_mode, this_optab, op0, NULL_RTX, unsignedp);
+ gcc_assert (temp);
+ /* The tree code produces a scalar result, but (somewhat by convention)
+ the optab produces a vector with the result in element 0 if
+ little-endian, or element N-1 if big-endian. So pull the scalar
+ result out of that element. */
+ int index = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (vec_mode) - 1 : 0;
+ int bitsize = GET_MODE_BITSIZE (GET_MODE_INNER (vec_mode));
+ temp = extract_bit_field (temp, bitsize, bitsize * index, unsignedp,
+ target, mode, mode);
gcc_assert (temp);
return temp;
}
- case VEC_LSHIFT_EXPR:
- case VEC_RSHIFT_EXPR:
- {
- target = expand_vec_shift_expr (ops, target);
- return target;
- }
-
case VEC_UNPACK_HI_EXPR:
case VEC_UNPACK_LO_EXPR:
{
if (CONSTANT_P (op2) && GET_CODE (op2) != CONST_VECTOR)
{
tree sel_type = TREE_TYPE (treeop2);
- enum machine_mode vmode
+ machine_mode vmode
= mode_for_vector (TYPE_MODE (TREE_TYPE (sel_type)),
TYPE_VECTOR_SUBPARTS (sel_type));
gcc_assert (GET_MODE_CLASS (vmode) == MODE_VECTOR_INT);
return target;
}
+ case SAD_EXPR:
+ {
+ tree oprnd0 = treeop0;
+ tree oprnd1 = treeop1;
+ tree oprnd2 = treeop2;
+ rtx op2;
+
+ expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
+ op2 = expand_normal (oprnd2);
+ target = expand_widen_pattern_expr (ops, op0, op1, op2,
+ target, unsignedp);
+ return target;
+ }
+
case REALIGN_LOAD_EXPR:
{
tree oprnd0 = treeop0;
}
case COND_EXPR:
- /* A COND_EXPR with its type being VOID_TYPE represents a
- conditional jump and is handled in
- expand_gimple_cond_expr. */
- gcc_assert (!VOID_TYPE_P (type));
-
- /* Note that COND_EXPRs whose type is a structure or union
- are required to be constructed to contain assignments of
- a temporary variable, so that we can evaluate them here
- for side effect only. If type is void, we must do likewise. */
-
- gcc_assert (!TREE_ADDRESSABLE (type)
- && !ignore
- && TREE_TYPE (treeop1) != void_type_node
- && TREE_TYPE (treeop2) != void_type_node);
-
- temp = expand_cond_expr_using_cmove (treeop0, treeop1, treeop2);
- if (temp)
- return temp;
-
- /* If we are not to produce a result, we have no target. Otherwise,
- if a target was specified use it; it will not be used as an
- intermediate target unless it is safe. If no target, use a
- temporary. */
-
- if (modifier != EXPAND_STACK_PARM
- && original_target
- && safe_from_p (original_target, treeop0, 1)
- && GET_MODE (original_target) == mode
- && !MEM_P (original_target))
- temp = original_target;
- else
- temp = assign_temp (type, 0, 1);
-
- do_pending_stack_adjust ();
- NO_DEFER_POP;
- op0 = gen_label_rtx ();
- op1 = gen_label_rtx ();
- jumpifnot (treeop0, op0, -1);
- store_expr (treeop1, temp,
- modifier == EXPAND_STACK_PARM,
- false);
-
- emit_jump_insn (gen_jump (op1));
- emit_barrier ();
- emit_label (op0);
- store_expr (treeop2, temp,
- modifier == EXPAND_STACK_PARM,
- false);
+ {
+ /* A COND_EXPR with its type being VOID_TYPE represents a
+ conditional jump and is handled in
+ expand_gimple_cond_expr. */
+ gcc_assert (!VOID_TYPE_P (type));
+
+ /* Note that COND_EXPRs whose type is a structure or union
+ are required to be constructed to contain assignments of
+ a temporary variable, so that we can evaluate them here
+ for side effect only. If type is void, we must do likewise. */
+
+ gcc_assert (!TREE_ADDRESSABLE (type)
+ && !ignore
+ && TREE_TYPE (treeop1) != void_type_node
+ && TREE_TYPE (treeop2) != void_type_node);
+
+ temp = expand_cond_expr_using_cmove (treeop0, treeop1, treeop2);
+ if (temp)
+ return temp;
- emit_label (op1);
- OK_DEFER_POP;
- return temp;
+ /* If we are not to produce a result, we have no target. Otherwise,
+ if a target was specified use it; it will not be used as an
+ intermediate target unless it is safe. If no target, use a
+ temporary. */
+
+ if (modifier != EXPAND_STACK_PARM
+ && original_target
+ && safe_from_p (original_target, treeop0, 1)
+ && GET_MODE (original_target) == mode
+ && !MEM_P (original_target))
+ temp = original_target;
+ else
+ temp = assign_temp (type, 0, 1);
+
+ do_pending_stack_adjust ();
+ NO_DEFER_POP;
+ rtx_code_label *lab0 = gen_label_rtx ();
+ rtx_code_label *lab1 = gen_label_rtx ();
+ jumpifnot (treeop0, lab0, -1);
+ store_expr (treeop1, temp,
+ modifier == EXPAND_STACK_PARM,
+ false);
+
+ emit_jump_insn (gen_jump (lab1));
+ emit_barrier ();
+ emit_label (lab0);
+ store_expr (treeop2, temp,
+ modifier == EXPAND_STACK_PARM,
+ false);
+
+ emit_label (lab1);
+ OK_DEFER_POP;
+ return temp;
+ }
case VEC_COND_EXPR:
target = expand_vec_cond_expr (type, treeop0, treeop1, treeop2, target);
}
rtx
-expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
- enum expand_modifier modifier, rtx *alt_rtl)
+expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
+ enum expand_modifier modifier, rtx *alt_rtl,
+ bool inner_reference_p)
{
rtx op0, op1, temp, decl_rtl;
tree type;
int unsignedp;
- enum machine_mode mode;
+ machine_mode mode;
enum tree_code code = TREE_CODE (exp);
rtx subtarget, original_target;
int ignore;
if (g)
{
rtx r;
- location_t saved_loc = curr_insn_location ();
-
- set_curr_insn_location (gimple_location (g));
- r = expand_expr_real (gimple_assign_rhs_to_tree (g), target,
- tmode, modifier, NULL);
- set_curr_insn_location (saved_loc);
+ ops.code = gimple_assign_rhs_code (g);
+ switch (get_gimple_rhs_class (ops.code))
+ {
+ case GIMPLE_TERNARY_RHS:
+ ops.op2 = gimple_assign_rhs3 (g);
+ /* Fallthru */
+ case GIMPLE_BINARY_RHS:
+ ops.op1 = gimple_assign_rhs2 (g);
+
+ /* Try to expand conditonal compare. */
+ if (targetm.gen_ccmp_first)
+ {
+ gcc_checking_assert (targetm.gen_ccmp_next != NULL);
+ r = expand_ccmp_expr (g);
+ if (r)
+ break;
+ }
+ /* Fallthru */
+ case GIMPLE_UNARY_RHS:
+ ops.op0 = gimple_assign_rhs1 (g);
+ ops.type = TREE_TYPE (gimple_assign_lhs (g));
+ ops.location = gimple_location (g);
+ r = expand_expr_real_2 (&ops, target, tmode, modifier);
+ break;
+ case GIMPLE_SINGLE_RHS:
+ {
+ location_t saved_loc = curr_insn_location ();
+ set_curr_insn_location (gimple_location (g));
+ r = expand_expr_real (gimple_assign_rhs1 (g), target,
+ tmode, modifier, NULL, inner_reference_p);
+ set_curr_insn_location (saved_loc);
+ break;
+ }
+ default:
+ gcc_unreachable ();
+ }
if (REG_P (r) && !REG_EXPR (r))
set_reg_attrs_for_decl_rtl (SSA_NAME_VAR (exp), r);
return r;
&& DECL_MODE (exp) != BLKmode
&& GET_MODE (decl_rtl) != DECL_MODE (exp))
{
- enum machine_mode pmode;
+ machine_mode pmode;
/* Get the signedness to be used for this variable. Ensure we get
the same mode we got when the variable was declared. */
if (code == SSA_NAME
&& (g = SSA_NAME_DEF_STMT (ssa_name))
- && gimple_code (g) == GIMPLE_CALL)
- {
- gcc_assert (!gimple_call_internal_p (g));
- pmode = promote_function_mode (type, mode, &unsignedp,
- gimple_call_fntype (g),
- 2);
- }
+ && gimple_code (g) == GIMPLE_CALL
+ && !gimple_call_internal_p (g))
+ pmode = promote_function_mode (type, mode, &unsignedp,
+ gimple_call_fntype (g),
+ 2);
else
pmode = promote_decl_mode (exp, &unsignedp);
gcc_assert (GET_MODE (decl_rtl) == pmode);
temp = gen_lowpart_SUBREG (mode, decl_rtl);
SUBREG_PROMOTED_VAR_P (temp) = 1;
- SUBREG_PROMOTED_UNSIGNED_SET (temp, unsignedp);
+ SUBREG_PROMOTED_SET (temp, unsignedp);
return temp;
}
return decl_rtl;
case INTEGER_CST:
- temp = immed_double_const (TREE_INT_CST_LOW (exp),
- TREE_INT_CST_HIGH (exp), mode);
-
+ /* Given that TYPE_PRECISION (type) is not always equal to
+ GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
+ the former to the latter according to the signedness of the
+ type. */
+ temp = immed_wide_int_const (wide_int::from
+ (exp,
+ GET_MODE_PRECISION (TYPE_MODE (type)),
+ TYPE_SIGN (type)),
+ TYPE_MODE (type));
return temp;
case VECTOR_CST:
/* Handle evaluating a complex constant in a CONCAT target. */
if (original_target && GET_CODE (original_target) == CONCAT)
{
- enum machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
rtx rtarg, itarg;
rtarg = XEXP (original_target, 0);
case SAVE_EXPR:
{
tree val = treeop0;
- rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl);
+ rtx ret = expand_expr_real_1 (val, target, tmode, modifier, alt_rtl,
+ inner_reference_p);
if (!SAVE_EXPR_RESOLVED_P (exp))
{
{
addr_space_t as
= TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
- enum machine_mode address_mode;
+ machine_mode address_mode;
tree base = TREE_OPERAND (exp, 0);
gimple def_stmt;
enum insn_code icode;
might end up in a register. */
if (mem_ref_refers_to_non_mem_p (exp))
{
- HOST_WIDE_INT offset = mem_ref_offset (exp).low;
+ HOST_WIDE_INT offset = mem_ref_offset (exp).to_short_addr ();
base = TREE_OPERAND (base, 0);
if (offset == 0
&& tree_fits_uhwi_p (TYPE_SIZE (type))
op0 = memory_address_addr_space (mode, op0, as);
if (!integer_zerop (TREE_OPERAND (exp, 1)))
{
- rtx off
- = immed_double_int_const (mem_ref_offset (exp), address_mode);
+ rtx off = immed_wide_int_const (mem_ref_offset (exp), address_mode);
op0 = simplify_gen_binary (PLUS, address_mode, op0, off);
op0 = memory_address_addr_space (mode, op0, as);
}
MEM_VOLATILE_P (temp) = 1;
if (modifier != EXPAND_WRITE
&& modifier != EXPAND_MEMORY
+ && !inner_reference_p
&& mode != BLKmode
&& align < GET_MODE_ALIGNMENT (mode))
{
|| TREE_CODE (array) == CONST_DECL)
&& (init = ctor_for_folding (array)) != error_mark_node)
{
- if (TREE_CODE (init) == CONSTRUCTOR)
+ if (init == NULL_TREE)
+ {
+ tree value = build_zero_cst (type);
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ {
+ /* If VALUE is a CONSTRUCTOR, this optimization is only
+ useful if this doesn't store the CONSTRUCTOR into
+ memory. If it does, it is more efficient to just
+ load the data from the array directly. */
+ rtx ret = expand_constructor (value, target,
+ modifier, true);
+ if (ret == NULL_RTX)
+ value = NULL_TREE;
+ }
+
+ if (value)
+ return expand_expr (value, target, tmode, modifier);
+ }
+ else if (TREE_CODE (init) == CONSTRUCTOR)
{
unsigned HOST_WIDE_INT ix;
tree field, value;
if (compare_tree_int (index1, TREE_STRING_LENGTH (init)) < 0)
{
tree type = TREE_TYPE (TREE_TYPE (init));
- enum machine_mode mode = TYPE_MODE (type);
+ machine_mode mode = TYPE_MODE (type);
if (GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) == 1)
if (DECL_BIT_FIELD (field))
{
HOST_WIDE_INT bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
- enum machine_mode imode = TYPE_MODE (TREE_TYPE (field));
+ machine_mode imode = TYPE_MODE (TREE_TYPE (field));
if (TYPE_UNSIGNED (TREE_TYPE (field)))
{
case ARRAY_RANGE_REF:
normal_inner_ref:
{
- enum machine_mode mode1, mode2;
+ machine_mode mode1, mode2;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
int volatilep = 0, must_force_mem;
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep, true);
rtx orig_op0, memloc;
- bool mem_attrs_from_type = false;
+ bool clear_mem_expr = false;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
orig_op0 = op0
- = expand_expr (tem,
- (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
- && COMPLETE_TYPE_P (TREE_TYPE (tem))
- && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
- != INTEGER_CST)
- && modifier != EXPAND_STACK_PARM
- ? target : NULL_RTX),
- VOIDmode,
- modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier);
-
- /* If the bitfield is volatile, we want to access it in the
+ = expand_expr_real (tem,
+ (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+ && COMPLETE_TYPE_P (TREE_TYPE (tem))
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+ != INTEGER_CST)
+ && modifier != EXPAND_STACK_PARM
+ ? target : NULL_RTX),
+ VOIDmode,
+ modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier,
+ NULL, true);
+
+ /* If the field has a mode, we want to access it in the
field's mode, not the computed mode.
If a MEM has VOIDmode (external with incomplete type),
use BLKmode for it instead. */
if (MEM_P (op0))
{
- if (volatilep && flag_strict_volatile_bitfields > 0)
+ if (mode1 != VOIDmode)
op0 = adjust_address (op0, mode1, 0);
else if (GET_MODE (op0) == VOIDmode)
op0 = adjust_address (op0, BLKmode, 0);
and need be, put it there. */
else if (CONSTANT_P (op0) || (!MEM_P (op0) && must_force_mem))
{
- tree nt = build_qualified_type (TREE_TYPE (tem),
- (TYPE_QUALS (TREE_TYPE (tem))
- | TYPE_QUAL_CONST));
- memloc = assign_temp (nt, 1, 1);
+ memloc = assign_temp (TREE_TYPE (tem), 1, 1);
emit_move_insn (memloc, op0);
op0 = memloc;
- mem_attrs_from_type = true;
+ clear_mem_expr = true;
}
if (offset)
{
- enum machine_mode address_mode;
+ machine_mode address_mode;
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode,
EXPAND_SUM);
address_mode = get_address_mode (op0);
if (GET_MODE (offset_rtx) != address_mode)
- offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ {
+ /* We cannot be sure that the RTL in offset_rtx is valid outside
+ of a memory address context, so force it into a register
+ before attempting to convert it to the desired mode. */
+ offset_rtx = force_operand (offset_rtx, NULL_RTX);
+ offset_rtx = convert_to_mode (address_mode, offset_rtx, 0);
+ }
- if (GET_MODE (op0) == BLKmode
- /* A constant address in OP0 can have VOIDmode, we must
- not try to call force_reg in that case. */
- && GET_MODE (XEXP (op0, 0)) != VOIDmode
- && bitsize != 0
+ /* See the comment in expand_assignment for the rationale. */
+ if (mode1 != VOIDmode
+ && bitpos != 0
+ && bitsize > 0
&& (bitpos % bitsize) == 0
&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
- && MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
+ && MEM_ALIGN (op0) >= GET_MODE_ALIGNMENT (mode1))
{
op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
bitpos = 0;
&& modifier != EXPAND_CONST_ADDRESS
&& modifier != EXPAND_INITIALIZER
&& modifier != EXPAND_MEMORY)
- /* If the field is volatile, we always want an aligned
- access. Do this in following two situations:
- 1. the access is not already naturally
- aligned, otherwise "normal" (non-bitfield) volatile fields
- become non-addressable.
- 2. the bitsize is narrower than the access size. Need
- to extract bitfields from the access. */
- || (volatilep && flag_strict_volatile_bitfields > 0
- && (bitpos % GET_MODE_ALIGNMENT (mode) != 0
- || (mode1 != BLKmode
- && bitsize < GET_MODE_SIZE (mode1) * BITS_PER_UNIT)))
+ /* If the bitfield is volatile and the bitsize
+ is narrower than the access size of the bitfield,
+ we need to extract bitfields from the access. */
+ || (volatilep && TREE_CODE (exp) == COMPONENT_REF
+ && DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1))
+ && mode1 != BLKmode
+ && bitsize < GET_MODE_SIZE (mode1) * BITS_PER_UNIT)
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (mode1 != BLKmode
&& 0 != compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)),
bitsize)))
{
- enum machine_mode ext_mode = mode;
+ machine_mode ext_mode = mode;
if (ext_mode == BLKmode
&& ! (target != 0 && MEM_P (op0)
if (target == 0)
target = assign_temp (type, 1, 1);
+ /* ??? Unlike the similar test a few lines below, this one is
+ very likely obsolete. */
if (bitsize == 0)
return target;
return target;
}
+ /* If we have nothing to extract, the result will be 0 for targets
+ with SHIFT_COUNT_TRUNCATED == 0 and garbage otherwise. Always
+ return 0 for the sake of consistency, as reading a zero-sized
+ bitfield is valid in Ada and the value is fully specified. */
+ if (bitsize == 0)
+ return const0_rtx;
+
op0 = validize_mem (op0);
if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
/* If the result type is BLKmode, store the data into a temporary
of the appropriate type, but with the mode corresponding to the
- mode for the data we have (op0's mode). It's tempting to make
- this a constant type, since we know it's only being stored once,
- but that can cause problems if we are taking the address of this
- COMPONENT_REF because the MEM of any reference via that address
- will have flags corresponding to the type, which will not
- necessarily be constant. */
+ mode for the data we have (op0's mode). */
if (mode == BLKmode)
{
- rtx new_rtx;
-
- new_rtx = assign_stack_temp_for_type (ext_mode,
- GET_MODE_BITSIZE (ext_mode),
- type);
+ rtx new_rtx
+ = assign_stack_temp_for_type (ext_mode,
+ GET_MODE_BITSIZE (ext_mode),
+ type);
emit_move_insn (new_rtx, op0);
op0 = copy_rtx (new_rtx);
PUT_MODE (op0, BLKmode);
if (op0 == orig_op0)
op0 = copy_rtx (op0);
- /* If op0 is a temporary because of forcing to memory, pass only the
- type to set_mem_attributes so that the original expression is never
- marked as ADDRESSABLE through MEM_EXPR of the temporary. */
- if (mem_attrs_from_type)
- set_mem_attributes (op0, type, 0);
- else
- set_mem_attributes (op0, exp, 0);
+ set_mem_attributes (op0, exp, 0);
if (REG_P (XEXP (op0, 0)))
mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
+ /* If op0 is a temporary because the original expressions was forced
+ to memory, clear MEM_EXPR so that the original expression cannot
+ be marked as addressable through MEM_EXPR of the temporary. */
+ if (clear_mem_expr)
+ set_mem_expr (op0, NULL_TREE);
+
MEM_VOLATILE_P (op0) |= volatilep;
if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
|| modifier == EXPAND_CONST_ADDRESS
if (fndecl && DECL_BUILT_IN (fndecl))
{
gcc_assert (DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_FRONTEND);
- return expand_builtin (exp, target, subtarget, tmode, ignore);
+ if (CALL_WITH_BOUNDS_P (exp))
+ return expand_builtin_with_bounds (exp, target, subtarget,
+ tmode, ignore);
+ else
+ return expand_builtin (exp, target, subtarget, tmode, ignore);
}
}
return expand_call (exp, target, ignore);
&& TYPE_MODE (TREE_TYPE (treeop0)) != BLKmode
&& handled_component_p (treeop0))
{
- enum machine_mode mode1;
+ machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
tree offset;
int unsignedp;
{
/* See the normal_inner_ref case for the rationale. */
orig_op0
- = expand_expr (tem,
- (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_SUM ? EXPAND_NORMAL : modifier);
+ = expand_expr_real (tem,
+ (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_SUM ? EXPAND_NORMAL : modifier,
+ NULL, true);
if (MEM_P (orig_op0))
{
}
if (!op0)
- op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier);
+ op0 = expand_expr_real (treeop0, NULL_RTX, VOIDmode, modifier,
+ NULL, inner_reference_p);
/* If the input and output modes are both the same, we are done. */
if (mode == GET_MODE (op0))
else if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (TREE_TYPE (treeop0)))
op0 = convert_modes (mode, GET_MODE (op0), op0,
TYPE_UNSIGNED (TREE_TYPE (treeop0)));
+ /* If the output type is a bit-field type, do an extraction. */
+ else if (reduce_bit_field)
+ return extract_bit_field (op0, TYPE_PRECISION (type), 0,
+ TYPE_UNSIGNED (type), NULL_RTX,
+ mode, mode);
/* As a last resort, spill op0 to memory, and reload it in a
different mode. */
else if (!MEM_P (op0))
op0 = target;
}
- /* At this point, OP0 is in the correct mode. If the output type is
- such that the operand is known to be aligned, indicate that it is.
- Otherwise, we need only be concerned about alignment for non-BLKmode
- results. */
+ /* If OP0 is (now) a MEM, we need to deal with alignment issues. If the
+ output type is such that the operand is known to be aligned, indicate
+ that it is. Otherwise, we need only be concerned about alignment for
+ non-BLKmode results. */
if (MEM_P (op0))
{
enum insn_code icode;
op0 = copy_rtx (op0);
set_mem_align (op0, MAX (MEM_ALIGN (op0), TYPE_ALIGN (type)));
}
- else if (mode != BLKmode
- && MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode)
- /* If the target does have special handling for unaligned
- loads of mode then use them. */
- && ((icode = optab_handler (movmisalign_optab, mode))
- != CODE_FOR_nothing))
- {
- rtx reg, insn;
-
- op0 = adjust_address (op0, mode, 0);
- /* We've already validated the memory, and we're creating a
- new pseudo destination. The predicates really can't
- fail. */
- reg = gen_reg_rtx (mode);
-
- /* Nor can the insn generator. */
- insn = GEN_FCN (icode) (reg, op0);
- emit_insn (insn);
- return reg;
- }
- else if (STRICT_ALIGNMENT
+ else if (modifier != EXPAND_WRITE
+ && modifier != EXPAND_MEMORY
+ && !inner_reference_p
&& mode != BLKmode
&& MEM_ALIGN (op0) < GET_MODE_ALIGNMENT (mode))
{
- tree inner_type = TREE_TYPE (treeop0);
- HOST_WIDE_INT temp_size
- = MAX (int_size_in_bytes (inner_type),
- (HOST_WIDE_INT) GET_MODE_SIZE (mode));
- rtx new_rtx
- = assign_stack_temp_for_type (mode, temp_size, type);
- rtx new_with_op0_mode
- = adjust_address (new_rtx, GET_MODE (op0), 0);
-
- gcc_assert (!TREE_ADDRESSABLE (exp));
-
- if (GET_MODE (op0) == BLKmode)
- emit_block_move (new_with_op0_mode, op0,
- GEN_INT (GET_MODE_SIZE (mode)),
- (modifier == EXPAND_STACK_PARM
- ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
- else
- emit_move_insn (new_with_op0_mode, op0);
+ /* If the target does have special handling for unaligned
+ loads of mode then use them. */
+ if ((icode = optab_handler (movmisalign_optab, mode))
+ != CODE_FOR_nothing)
+ {
+ rtx reg;
+
+ op0 = adjust_address (op0, mode, 0);
+ /* We've already validated the memory, and we're creating a
+ new pseudo destination. The predicates really can't
+ fail. */
+ reg = gen_reg_rtx (mode);
+
+ /* Nor can the insn generator. */
+ rtx_insn *insn = GEN_FCN (icode) (reg, op0);
+ emit_insn (insn);
+ return reg;
+ }
+ else if (STRICT_ALIGNMENT)
+ {
+ tree inner_type = TREE_TYPE (treeop0);
+ HOST_WIDE_INT temp_size
+ = MAX (int_size_in_bytes (inner_type),
+ (HOST_WIDE_INT) GET_MODE_SIZE (mode));
+ rtx new_rtx
+ = assign_stack_temp_for_type (mode, temp_size, type);
+ rtx new_with_op0_mode
+ = adjust_address (new_rtx, GET_MODE (op0), 0);
+
+ gcc_assert (!TREE_ADDRESSABLE (exp));
+
+ if (GET_MODE (op0) == BLKmode)
+ emit_block_move (new_with_op0_mode, op0,
+ GEN_INT (GET_MODE_SIZE (mode)),
+ (modifier == EXPAND_STACK_PARM
+ ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+ else
+ emit_move_insn (new_with_op0_mode, op0);
- op0 = new_rtx;
+ op0 = new_rtx;
+ }
}
op0 = adjust_address (op0, mode, 0);
&& integer_onep (DECL_SIZE (TREE_OPERAND (lhs, 1)))
&& integer_onep (DECL_SIZE (TREE_OPERAND (TREE_OPERAND (rhs, 1), 1))))
{
- rtx label = gen_label_rtx ();
+ rtx_code_label *label = gen_label_rtx ();
int value = TREE_CODE (rhs) == BIT_IOR_EXPR;
do_jump (TREE_OPERAND (rhs, 1),
value ? label : 0,
/* WITH_SIZE_EXPR expands to its first argument. The caller should
have pulled out the size to use in whatever context it needed. */
return expand_expr_real (treeop0, original_target, tmode,
- modifier, alt_rtl);
+ modifier, alt_rtl, inner_reference_p);
default:
return expand_expr_real_2 (&ops, target, tmode, modifier);
}
else if (TYPE_UNSIGNED (type))
{
- rtx mask = immed_double_int_const (double_int::mask (prec),
- GET_MODE (exp));
- return expand_and (GET_MODE (exp), exp, mask, target);
+ machine_mode mode = GET_MODE (exp);
+ rtx mask = immed_wide_int_const
+ (wi::mask (prec, false, GET_MODE_PRECISION (mode)), mode);
+ return expand_and (mode, exp, mask, target);
}
else
{
|| !tree_fits_uhwi_p (TREE_OPERAND (offset, 1))
|| compare_tree_int (TREE_OPERAND (offset, 1),
BIGGEST_ALIGNMENT / BITS_PER_UNIT) <= 0
- || !exact_log2 (tree_to_uhwi (TREE_OPERAND (offset, 1)) + 1) < 0)
+ || exact_log2 (tree_to_uhwi (TREE_OPERAND (offset, 1)) + 1) < 0)
return 0;
/* Look at the first operand of BIT_AND_EXPR and strip any conversion.
set/jump/set sequence. */
static rtx
-do_store_flag (sepops ops, rtx target, enum machine_mode mode)
+do_store_flag (sepops ops, rtx target, machine_mode mode)
{
enum rtx_code code;
tree arg0, arg1, type;
- tree tem;
- enum machine_mode operand_mode;
+ machine_mode operand_mode;
int unsignedp;
rtx op0, op1;
rtx subtarget = target;
if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST
|| TREE_CODE (arg0) == FIXED_CST)
{
- tem = arg0; arg0 = arg1; arg1 = tem;
+ std::swap (arg0, arg1);
code = swap_condition (code);
}
int default_probability)
{
struct expand_operand ops[5];
- enum machine_mode index_mode = SImode;
+ machine_mode index_mode = SImode;
rtx op1, op2, index;
if (! HAVE_casesi)
/* Convert the index to SImode. */
if (GET_MODE_BITSIZE (TYPE_MODE (index_type)) > GET_MODE_BITSIZE (index_mode))
{
- enum machine_mode omode = TYPE_MODE (index_type);
+ machine_mode omode = TYPE_MODE (index_type);
rtx rangertx = expand_normal (range);
/* We must handle the endpoints in the original mode. */
}
/* Attempt to generate a tablejump instruction; same concept. */
-#ifndef HAVE_tablejump
-#define HAVE_tablejump 0
-#define gen_tablejump(x, y) (0)
-#endif
-
/* Subroutine of the next function.
INDEX is the value being switched on, with the lowest value
the default label. */
static void
-do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
+do_tablejump (rtx index, machine_mode mode, rtx range, rtx table_label,
rtx default_label, int default_probability)
{
rtx temp, vector;
GET_MODE_SIZE, because this indicates how large insns are. The other
uses should all be Pmode, because they are addresses. This code
could fail if addresses and insns are not the same size. */
- index = gen_rtx_PLUS
- (Pmode,
- gen_rtx_MULT (Pmode, index,
- gen_int_mode (GET_MODE_SIZE (CASE_VECTOR_MODE), Pmode)),
- gen_rtx_LABEL_REF (Pmode, table_label));
+ index = simplify_gen_binary (MULT, Pmode, index,
+ gen_int_mode (GET_MODE_SIZE (CASE_VECTOR_MODE),
+ Pmode));
+ index = simplify_gen_binary (PLUS, Pmode, index,
+ gen_rtx_LABEL_REF (Pmode, table_label));
+
#ifdef PIC_CASE_VECTOR_ADDRESS
if (flag_pic)
index = PIC_CASE_VECTOR_ADDRESS (index);
unsigned i;
int units;
tree elt;
- enum machine_mode inner, mode;
+ machine_mode inner, mode;
mode = TYPE_MODE (TREE_TYPE (exp));
RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
inner);
else
- RTVEC_ELT (v, i) = immed_double_int_const (tree_to_double_int (elt),
- inner);
+ RTVEC_ELT (v, i) = immed_wide_int_const (elt, inner);
}
return gen_rtx_CONST_VECTOR (mode, v);
return XEXP (DECL_RTL (personality), 0);
}
+/* Returns a tree for the size of EXP in bytes. */
+
+static tree
+tree_expr_size (const_tree exp)
+{
+ if (DECL_P (exp)
+ && DECL_SIZE_UNIT (exp) != 0)
+ return DECL_SIZE_UNIT (exp);
+ else
+ return size_in_bytes (TREE_TYPE (exp));
+}
+
+/* Return an rtx for the size in bytes of the value of EXP. */
+
+rtx
+expr_size (tree exp)
+{
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ {
+ size = tree_expr_size (exp);
+ gcc_assert (size);
+ gcc_assert (size == SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, exp));
+ }
+
+ return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL);
+}
+
+/* Return a wide integer for the size in bytes of the value of EXP, or -1
+ if the size can vary or is larger than an integer. */
+
+static HOST_WIDE_INT
+int_expr_size (tree exp)
+{
+ tree size;
+
+ if (TREE_CODE (exp) == WITH_SIZE_EXPR)
+ size = TREE_OPERAND (exp, 1);
+ else
+ {
+ size = tree_expr_size (exp);
+ gcc_assert (size);
+ }
+
+ if (size == 0 || !tree_fits_shwi_p (size))
+ return -1;
+
+ return tree_to_shwi (size);
+}
+
#include "gt-expr.h"