/* Convert tree expression to rtl instructions, for GNU compiler.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
struct move_by_pieces *);
static bool block_move_libcall_safe_for_call_parm (void);
static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned);
-static rtx emit_block_move_via_libcall (rtx, rtx, rtx);
+static rtx emit_block_move_via_libcall (rtx, rtx, rtx, bool);
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 void store_by_pieces_1 (struct store_by_pieces *, unsigned int);
static void store_by_pieces_2 (rtx (*) (rtx, ...), enum machine_mode,
struct store_by_pieces *);
-static bool clear_storage_via_clrmem (rtx, rtx, unsigned);
-static rtx clear_storage_via_libcall (rtx, rtx);
+static rtx clear_storage_via_libcall (rtx, rtx, bool);
static tree clear_storage_libcall_fn (int);
static rtx compress_float_constant (rtx, rtx);
static rtx get_subtarget (rtx);
static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
tree, tree, int);
-static unsigned HOST_WIDE_INT highest_pow2_factor (tree);
static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
static int is_aligning_offset (tree, tree);
#endif
static void do_tablejump (rtx, enum machine_mode, rtx, rtx, rtx);
static rtx const_vector_from_tree (tree);
+static void write_complex_part (rtx, rtx, bool);
/* Record for each mode whether we can move a register directly to or
from an object of that mode in memory. If we can't, we won't try
/* This array records the insn_code of insns to perform block moves. */
enum insn_code movmem_optab[NUM_MACHINE_MODES];
-/* This array records the insn_code of insns to perform block clears. */
-enum insn_code clrmem_optab[NUM_MACHINE_MODES];
+/* This array records the insn_code of insns to perform block sets. */
+enum insn_code setmem_optab[NUM_MACHINE_MODES];
-/* These arrays record the insn_code of two different kinds of insns
+/* These arrays record the insn_code of three different kinds of insns
to perform block compares. */
enum insn_code cmpstr_optab[NUM_MACHINE_MODES];
+enum insn_code cmpstrn_optab[NUM_MACHINE_MODES];
enum insn_code cmpmem_optab[NUM_MACHINE_MODES];
+/* Synchronization primitives. */
+enum insn_code sync_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_old_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_add_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_sub_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_ior_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_and_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_xor_optab[NUM_MACHINE_MODES];
+enum insn_code sync_new_nand_optab[NUM_MACHINE_MODES];
+enum insn_code sync_compare_and_swap[NUM_MACHINE_MODES];
+enum insn_code sync_compare_and_swap_cc[NUM_MACHINE_MODES];
+enum insn_code sync_lock_test_and_set[NUM_MACHINE_MODES];
+enum insn_code sync_lock_release[NUM_MACHINE_MODES];
+
/* SLOW_UNALIGNED_ACCESS is nonzero if unaligned accesses are very slow. */
#ifndef SLOW_UNALIGNED_ACCESS
}
if (GET_MODE_CLASS (from_mode) == MODE_PARTIAL_INT)
{
+ rtx new_from;
enum machine_mode full_mode
= smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
gcc_assert (sext_optab->handlers[full_mode][from_mode].insn_code
!= CODE_FOR_nothing);
- emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
- to, from, UNKNOWN);
if (to_mode == full_mode)
- return;
+ {
+ emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+ to, from, UNKNOWN);
+ return;
+ }
+
+ new_from = gen_reg_rtx (full_mode);
+ emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+ new_from, from, UNKNOWN);
/* else proceed to integer conversions below. */
from_mode = full_mode;
+ from = new_from;
}
/* Now both modes are integers. */
if ((code = can_extend_p (to_mode, from_mode, unsignedp))
!= CODE_FOR_nothing)
{
- if (flag_force_mem)
- from = force_not_mem (from);
-
emit_unop_insn (code, to, from, equiv_code);
return;
}
switch (method)
{
case BLOCK_OP_NORMAL:
+ case BLOCK_OP_TAILCALL:
may_use_call = true;
break;
else if (emit_block_move_via_movmem (x, y, size, align))
;
else if (may_use_call)
- retval = emit_block_move_via_libcall (x, y, size);
+ retval = emit_block_move_via_libcall (x, y, size,
+ method == BLOCK_OP_TAILCALL);
else
emit_block_move_via_loop (x, y, size, align);
rtx tmp = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
if (!tmp || !REG_P (tmp))
return false;
- if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode,
- NULL_TREE, 1))
+ if (targetm.calls.arg_partial_bytes (&args_so_far, mode, NULL, 1))
return false;
FUNCTION_ARG_ADVANCE (args_so_far, mode, NULL_TREE, 1);
}
Return the return value from memcpy, 0 otherwise. */
static rtx
-emit_block_move_via_libcall (rtx dst, rtx src, rtx size)
+emit_block_move_via_libcall (rtx dst, rtx src, rtx size, bool tailcall)
{
rtx dst_addr, src_addr;
tree call_expr, arg_list, fn, src_tree, dst_tree, size_tree;
call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arg_list, NULL_TREE);
+ CALL_EXPR_TAILCALL (call_expr) = tailcall;
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
tmps[i] = gen_reg_rtx (mode);
emit_move_insn (tmps[i], adjust_address (src, mode, bytepos));
}
+ else if (COMPLEX_MODE_P (mode)
+ && GET_MODE (src) == mode
+ && bytelen == GET_MODE_SIZE (mode))
+ /* Let emit_move_complex do the bulk of the work. */
+ tmps[i] = src;
else if (GET_CODE (src) == CONCAT)
{
unsigned int slen = GET_MODE_SIZE (GET_MODE (src));
its length in bytes. */
rtx
-clear_storage (rtx object, rtx size)
+clear_storage (rtx object, rtx size, enum block_op_methods method)
{
- rtx retval = 0;
- unsigned int align = (MEM_P (object) ? MEM_ALIGN (object)
- : GET_MODE_ALIGNMENT (GET_MODE (object)));
+ enum machine_mode mode = GET_MODE (object);
+ unsigned int align;
+
+ gcc_assert (method == BLOCK_OP_NORMAL || method == BLOCK_OP_TAILCALL);
/* If OBJECT is not BLKmode and SIZE is the same size as its mode,
just move a zero. Otherwise, do this a piece at a time. */
- if (GET_MODE (object) != BLKmode
+ if (mode != BLKmode
&& GET_CODE (size) == CONST_INT
- && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (object)))
- emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
- else
- {
- if (size == const0_rtx)
- ;
- else if (GET_CODE (size) == CONST_INT
- && CLEAR_BY_PIECES_P (INTVAL (size), align))
- clear_by_pieces (object, INTVAL (size), align);
- else if (clear_storage_via_clrmem (object, size, align))
- ;
- else
- retval = clear_storage_via_libcall (object, size);
- }
-
- return retval;
-}
-
-/* A subroutine of clear_storage. Expand a clrmem pattern;
- return true if successful. */
-
-static bool
-clear_storage_via_clrmem (rtx object, rtx size, unsigned int align)
-{
- /* Try the most limited insn first, because there's no point
- including more than one in the machine description unless
- the more limited one has some advantage. */
-
- rtx opalign = GEN_INT (align / BITS_PER_UNIT);
- enum machine_mode mode;
-
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
- mode = GET_MODE_WIDER_MODE (mode))
+ && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode))
{
- enum insn_code code = clrmem_optab[(int) mode];
- insn_operand_predicate_fn pred;
-
- if (code != CODE_FOR_nothing
- /* We don't need MODE to be narrower than
- BITS_PER_HOST_WIDE_INT here because if SIZE is less than
- the mode mask, as it is returned by the macro, it will
- definitely be less than the actual mode mask. */
- && ((GET_CODE (size) == CONST_INT
- && ((unsigned HOST_WIDE_INT) INTVAL (size)
- <= (GET_MODE_MASK (mode) >> 1)))
- || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
- && ((pred = insn_data[(int) code].operand[0].predicate) == 0
- || (*pred) (object, BLKmode))
- && ((pred = insn_data[(int) code].operand[2].predicate) == 0
- || (*pred) (opalign, VOIDmode)))
+ rtx zero = CONST0_RTX (mode);
+ if (zero != NULL)
{
- rtx op1;
- rtx last = get_last_insn ();
- rtx pat;
-
- op1 = convert_to_mode (mode, size, 1);
- pred = insn_data[(int) code].operand[1].predicate;
- if (pred != 0 && ! (*pred) (op1, mode))
- op1 = copy_to_mode_reg (mode, op1);
+ emit_move_insn (object, zero);
+ return NULL;
+ }
- pat = GEN_FCN ((int) code) (object, op1, opalign);
- if (pat)
+ if (COMPLEX_MODE_P (mode))
+ {
+ zero = CONST0_RTX (GET_MODE_INNER (mode));
+ if (zero != NULL)
{
- emit_insn (pat);
- return true;
+ write_complex_part (object, zero, 0);
+ write_complex_part (object, zero, 1);
+ return NULL;
}
- else
- delete_insns_since (last);
}
}
- return false;
+ if (size == const0_rtx)
+ return NULL;
+
+ align = MEM_ALIGN (object);
+
+ if (GET_CODE (size) == CONST_INT
+ && CLEAR_BY_PIECES_P (INTVAL (size), align))
+ clear_by_pieces (object, INTVAL (size), align);
+ else if (set_storage_via_setmem (object, size, const0_rtx, align))
+ ;
+ else
+ return clear_storage_via_libcall (object, size,
+ method == BLOCK_OP_TAILCALL);
+
+ return NULL;
}
/* A subroutine of clear_storage. Expand a call to memset.
Return the return value of memset, 0 otherwise. */
static rtx
-clear_storage_via_libcall (rtx object, rtx size)
+clear_storage_via_libcall (rtx object, rtx size, bool tailcall)
{
tree call_expr, arg_list, fn, object_tree, size_tree;
enum machine_mode size_mode;
call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build3 (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arg_list, NULL_TREE);
+ CALL_EXPR_TAILCALL (call_expr) = tailcall;
retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
return block_clear_fn;
}
\f
+/* Expand a setmem pattern; return true if successful. */
+
+bool
+set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align)
+{
+ /* Try the most limited insn first, because there's no point
+ including more than one in the machine description unless
+ the more limited one has some advantage. */
+
+ rtx opalign = GEN_INT (align / BITS_PER_UNIT);
+ enum machine_mode mode;
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ enum insn_code code = setmem_optab[(int) mode];
+ insn_operand_predicate_fn pred;
+
+ if (code != CODE_FOR_nothing
+ /* We don't need MODE to be narrower than
+ BITS_PER_HOST_WIDE_INT here because if SIZE is less than
+ the mode mask, as it is returned by the macro, it will
+ definitely be less than the actual mode mask. */
+ && ((GET_CODE (size) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (size)
+ <= (GET_MODE_MASK (mode) >> 1)))
+ || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
+ && ((pred = insn_data[(int) code].operand[0].predicate) == 0
+ || (*pred) (object, BLKmode))
+ && ((pred = insn_data[(int) code].operand[3].predicate) == 0
+ || (*pred) (opalign, VOIDmode)))
+ {
+ rtx opsize, opchar;
+ enum machine_mode char_mode;
+ rtx last = get_last_insn ();
+ rtx pat;
+
+ opsize = convert_to_mode (mode, size, 1);
+ pred = insn_data[(int) code].operand[1].predicate;
+ if (pred != 0 && ! (*pred) (opsize, mode))
+ opsize = copy_to_mode_reg (mode, opsize);
+
+ opchar = val;
+ char_mode = insn_data[(int) code].operand[2].mode;
+ if (char_mode != VOIDmode)
+ {
+ opchar = convert_to_mode (char_mode, opchar, 1);
+ pred = insn_data[(int) code].operand[2].predicate;
+ if (pred != 0 && ! (*pred) (opchar, char_mode))
+ opchar = copy_to_mode_reg (char_mode, opchar);
+ }
+
+ pat = GEN_FCN ((int) code) (object, opsize, opchar, opalign);
+ if (pat)
+ {
+ emit_insn (pat);
+ return true;
+ }
+ else
+ delete_insns_since (last);
+ }
+ }
+
+ return false;
+}
+
+\f
/* 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. */
imode = GET_MODE_INNER (cmode);
ibitsize = GET_MODE_BITSIZE (imode);
+ /* For MEMs simplify_gen_subreg may generate an invalid new address
+ because, e.g., the original address is considered mode-dependent
+ by the target, which restricts simplify_subreg from invoking
+ adjust_address_nv. Instead of preparing fallback support for an
+ invalid address, we call adjust_address_nv directly. */
+ if (MEM_P (cplx))
+ {
+ emit_move_insn (adjust_address_nv (cplx, imode,
+ imag_p ? GET_MODE_SIZE (imode) : 0),
+ val);
+ return;
+ }
+
/* If the sub-object is at least word sized, then we know that subregging
will work. This special case is important, since store_bit_field
wants to operate on integer modes, and there's rarely an OImode to
correspond to TCmode. */
- if (ibitsize >= BITS_PER_WORD)
+ if (ibitsize >= BITS_PER_WORD
+ /* For hard regs we have exact predicates. Assume we can split
+ the original object if it spans an even number of hard regs.
+ This special case is important for SCmode on 64-bit platforms
+ 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))
{
rtx part = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
- emit_move_insn (part, val);
+ if (part)
+ {
+ emit_move_insn (part, val);
+ return;
+ }
+ else
+ /* simplify_gen_subreg may fail for sub-word MEMs. */
+ gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
}
- else
- store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val);
+
+ store_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0, imode, val);
}
/* Extract one of the components of the complex value CPLX. Extract the
}
}
+ /* For MEMs simplify_gen_subreg may generate an invalid new address
+ because, e.g., the original address is considered mode-dependent
+ by the target, which restricts simplify_subreg from invoking
+ adjust_address_nv. Instead of preparing fallback support for an
+ invalid address, we call adjust_address_nv directly. */
+ if (MEM_P (cplx))
+ return adjust_address_nv (cplx, imode,
+ imag_p ? GET_MODE_SIZE (imode) : 0);
+
/* If the sub-object is at least word sized, then we know that subregging
will work. This special case is important, since extract_bit_field
wants to operate on integer modes, and there's rarely an OImode to
correspond to TCmode. */
- if (ibitsize >= BITS_PER_WORD)
+ if (ibitsize >= BITS_PER_WORD
+ /* For hard regs we have exact predicates. Assume we can split
+ the original object if it spans an even number of hard regs.
+ This special case is important for SCmode on 64-bit platforms
+ 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))
{
rtx ret = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
- gcc_assert (ret != NULL);
- return ret;
+ if (ret)
+ return ret;
+ else
+ /* simplify_gen_subreg may fail for sub-word MEMs. */
+ gcc_assert (MEM_P (cplx) && ibitsize < BITS_PER_WORD);
}
return extract_bit_field (cplx, ibitsize, imag_p ? ibitsize : 0,
true, NULL_RTX, imode, imode);
}
\f
-/* A subroutine of emit_move_insn_1. Generate a move from Y into X using
- ALT_MODE instead of the operand's natural mode, MODE. CODE is the insn
- code for the move in ALT_MODE, and is known to be valid. Returns the
- instruction emitted. */
+/* A subroutine of emit_move_insn_1. Yet another lowpart generator.
+ NEW_MODE and OLD_MODE are the same size. Return NULL if X cannot be
+ represented in NEW_MODE. If FORCE is true, this will never happen, as
+ we'll force-create a SUBREG if needed. */
static rtx
-emit_move_via_alt_mode (enum machine_mode alt_mode, enum machine_mode mode,
- enum insn_code code, rtx x, rtx y)
+emit_move_change_mode (enum machine_mode new_mode,
+ enum machine_mode old_mode, rtx x, bool force)
{
- /* Get X and Y in ALT_MODE. We can't use gen_lowpart here because it
- may call change_address which is not appropriate if we were
- called when a reload was in progress. We don't have to worry
- about changing the address since the size in bytes is supposed to
- be the same. Copy the MEM to change the mode and move any
- substitutions from the old MEM to the new one. */
+ rtx ret;
- if (reload_in_progress)
+ if (reload_in_progress && MEM_P (x))
{
- rtx x1 = x, y1 = y;
-
- x = gen_lowpart_common (alt_mode, x1);
- if (x == 0 && MEM_P (x1))
- {
- x = adjust_address_nv (x1, alt_mode, 0);
- copy_replacements (x1, x);
- }
+ /* We can't use gen_lowpart here because it may call change_address
+ which is not appropriate if we were called when a reload was in
+ progress. We don't have to worry about changing the address since
+ the size in bytes is supposed to be the same. Copy the MEM to
+ change the mode and move any substitutions from the old MEM to
+ the new one. */
- y = gen_lowpart_common (alt_mode, y1);
- if (y == 0 && MEM_P (y1))
- {
- y = adjust_address_nv (y1, alt_mode, 0);
- copy_replacements (y1, y);
- }
+ ret = adjust_address_nv (x, new_mode, 0);
+ copy_replacements (x, ret);
}
else
{
- x = simplify_gen_subreg (alt_mode, x, mode, 0);
- y = simplify_gen_subreg (alt_mode, y, mode, 0);
+ /* Note that we do want simplify_subreg's behavior of validating
+ that the new mode is ok for a hard register. If we were to use
+ simplify_gen_subreg, we would create the subreg, but would
+ probably run into the target not being able to implement it. */
+ /* Except, of course, when FORCE is true, when this is exactly what
+ we want. Which is needed for CCmodes on some targets. */
+ if (force)
+ ret = simplify_gen_subreg (new_mode, x, old_mode, 0);
+ else
+ ret = simplify_subreg (new_mode, x, old_mode, 0);
}
- return emit_insn (GEN_FCN (code) (x, y));
+ return ret;
}
/* A subroutine of emit_move_insn_1. Generate a move from Y into X using
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)
+emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
{
enum machine_mode imode;
enum insn_code code;
if (code == CODE_FOR_nothing)
return NULL_RTX;
- return emit_move_via_alt_mode (imode, mode, code, x, y);
+ x = emit_move_change_mode (imode, mode, x, force);
+ if (x == NULL_RTX)
+ return NULL_RTX;
+ y = emit_move_change_mode (imode, mode, y, force);
+ if (y == NULL_RTX)
+ return NULL_RTX;
+ return emit_insn (GEN_FCN (code) (x, y));
}
/* A subroutine of emit_move_insn_1. X is a push_operand in MODE.
if (push_operand (x, mode))
return emit_move_complex_push (mode, x, y);
- /* For memory to memory moves, optimial behaviour can be had with the
- existing block move logic. */
- if (MEM_P (x) && MEM_P (y))
- {
- emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)),
- BLOCK_OP_NO_LIBCALL);
- return get_last_insn ();
- }
-
/* See if we can coerce the target into moving both values at once. */
+ /* Move floating point as parts. */
+ if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ && mov_optab->handlers[GET_MODE_INNER (mode)].insn_code != CODE_FOR_nothing)
+ try_int = false;
/* Not possible if the values are inherently not adjacent. */
- if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
+ else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
try_int = false;
/* Is possible if both are registers (or subregs of registers). */
else if (register_operand (x, mode) && register_operand (y, mode))
if (try_int)
{
- rtx ret = emit_move_via_integer (mode, x, y);
+ rtx ret;
+
+ /* For memory to memory moves, optimal behavior can be had with the
+ existing block move logic. */
+ if (MEM_P (x) && MEM_P (y))
+ {
+ emit_block_move (x, y, GEN_INT (GET_MODE_SIZE (mode)),
+ BLOCK_OP_NO_LIBCALL);
+ return get_last_insn ();
+ }
+
+ ret = emit_move_via_integer (mode, x, y, true);
if (ret)
return ret;
}
{
enum insn_code code = mov_optab->handlers[CCmode].insn_code;
if (code != CODE_FOR_nothing)
- return emit_move_via_alt_mode (CCmode, mode, code, x, y);
+ {
+ x = emit_move_change_mode (CCmode, mode, x, true);
+ y = emit_move_change_mode (CCmode, mode, y, true);
+ return emit_insn (GEN_FCN (code) (x, y));
+ }
}
/* Otherwise, find the MODE_INT mode of the same width. */
- ret = emit_move_via_integer (mode, x, y);
+ ret = emit_move_via_integer (mode, x, y, false);
gcc_assert (ret != NULL);
return ret;
}
rtx ypart = operand_subword (y, i, 1, mode);
/* If we can't get a part of Y, put Y into memory if it is a
- constant. Otherwise, force it into a register. If we still
- can't get a part of Y, abort. */
+ constant. Otherwise, force it into a register. Then we must
+ be able to get a part of Y. */
if (ypart == 0 && CONSTANT_P (y))
{
y = force_const_mem (mode, y);
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);
+ rtx ret = emit_move_via_integer (mode, x, y, false);
if (ret)
return ret;
}
enum machine_mode orig_srcmode = GET_MODE (y);
enum machine_mode srcmode;
REAL_VALUE_TYPE r;
+ int oldcost, newcost;
REAL_VALUE_FROM_CONST_DOUBLE (r, y);
+ if (LEGITIMATE_CONSTANT_P (y))
+ oldcost = rtx_cost (y, SET);
+ else
+ oldcost = rtx_cost (force_const_mem (dstmode, y), SET);
+
for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
srcmode != orig_srcmode;
srcmode = GET_MODE_WIDER_MODE (srcmode))
the extension. */
if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
continue;
+ /* This is valid, but may not be cheaper than the original. */
+ newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+ if (oldcost < newcost)
+ continue;
}
else if (float_extend_from_mem[dstmode][srcmode])
- trunc_y = validize_mem (force_const_mem (srcmode, trunc_y));
+ {
+ trunc_y = force_const_mem (srcmode, trunc_y);
+ /* This is valid, but may not be cheaper than the original. */
+ newcost = rtx_cost (gen_rtx_FLOAT_EXTEND (dstmode, trunc_y), SET);
+ if (oldcost < newcost)
+ continue;
+ trunc_y = validize_mem (trunc_y);
+ }
else
continue;
-
+
emit_unop_insn (ic, x, trunc_y, UNKNOWN);
last_insn = get_last_insn ();
ALIGN (in bits) is maximum alignment we can assume.
If PARTIAL and REG are both nonzero, then copy that many of the first
- words of X into registers starting with REG, and push the rest of X.
- The amount of space pushed is decreased by PARTIAL words,
- rounded *down* to a multiple of PARM_BOUNDARY.
+ bytes of X into registers starting with REG, and push the rest of X.
+ The amount of space pushed is decreased by PARTIAL bytes.
REG must be a hard register in this case.
If REG is zero but PARTIAL is not, take any all others actions for an
argument partially in registers, but do not actually load any
/* Copy a block into the stack, entirely or partially. */
rtx temp;
- int used = partial * UNITS_PER_WORD;
+ int used;
int offset;
int skip;
- if (reg && GET_CODE (reg) == PARALLEL)
- {
- /* Use the size of the elt to compute offset. */
- rtx elt = XEXP (XVECEXP (reg, 0, 0), 0);
- used = partial * GET_MODE_SIZE (GET_MODE (elt));
- offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
- }
- else
- offset = used % (PARM_BOUNDARY / BITS_PER_UNIT);
+ offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
+ used = partial - offset;
gcc_assert (size);
- used -= offset;
-
/* USED is now the # of bytes we need not copy to the stack
because registers will take care of them. */
int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD;
int i;
int not_stack;
- /* # words of start of argument
+ /* # bytes of start of argument
that we must make space for but need not store. */
- int offset = partial % (PARM_BOUNDARY / BITS_PER_WORD);
+ int offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT);
int args_offset = INTVAL (args_so_far);
int skip;
offset = 0;
/* Now NOT_STACK gets the number of words that we don't need to
- allocate on the stack. */
- not_stack = partial - offset;
+ allocate on the stack. Convert OFFSET to words too. */
+ not_stack = (partial - offset) / UNITS_PER_WORD;
+ offset /= UNITS_PER_WORD;
/* If the partial register-part of the arg counts in its stack size,
skip the part of stack space corresponding to the registers.
if (GET_CODE (reg) == PARALLEL)
emit_group_load (reg, x, type, -1);
else
- move_block_to_reg (REGNO (reg), x, partial, mode);
+ {
+ gcc_assert (partial % UNITS_PER_WORD == 0);
+ move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode);
+ }
}
if (extra && args_addr == 0 && where_pad == stack_direction)
emit_move_insn (str_rtx, result);
return true;
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (TREE_CODE (op1) != INTEGER_CST)
+ break;
+ value = expand_expr (op1, NULL_RTX, GET_MODE (str_rtx), 0);
+ value = convert_modes (GET_MODE (str_rtx),
+ TYPE_MODE (TREE_TYPE (op1)), value,
+ TYPE_UNSIGNED (TREE_TYPE (op1)));
+
+ /* We may be accessing data outside the field, which means
+ we can alias adjacent data. */
+ if (MEM_P (str_rtx))
+ {
+ str_rtx = shallow_copy_rtx (str_rtx);
+ set_mem_alias_set (str_rtx, 0);
+ set_mem_expr (str_rtx, 0);
+ }
+
+ binop = TREE_CODE (src) == BIT_IOR_EXPR ? ior_optab : xor_optab;
+ if (bitpos + bitsize != GET_MODE_BITSIZE (GET_MODE (str_rtx)))
+ {
+ rtx mask = GEN_INT (((unsigned HOST_WIDE_INT) 1 << bitsize)
+ - 1);
+ value = expand_and (GET_MODE (str_rtx), value, mask,
+ NULL_RTX);
+ }
+ value = expand_shift (LSHIFT_EXPR, GET_MODE (str_rtx), value,
+ build_int_cst (NULL_TREE, bitpos),
+ NULL_RTX, 1);
+ result = expand_binop (GET_MODE (str_rtx), binop, str_rtx,
+ value, str_rtx, 1, OPTAB_WIDEN);
+ if (result != str_rtx)
+ emit_move_insn (str_rtx, result);
+ return true;
+
default:
break;
}
{
enum machine_mode mode1;
HOST_WIDE_INT bitsize, bitpos;
- rtx orig_to_rtx;
tree offset;
int unsignedp;
int volatilep = 0;
push_temp_slots ();
tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
- &unsignedp, &volatilep);
+ &unsignedp, &volatilep, true);
/* If we are going to use store_bit_field and extract_bit_field,
make sure to_rtx will be safe for multiple use. */
- orig_to_rtx = to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
+ to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
if (offset != 0)
{
- rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
+ rtx offset_rtx;
- gcc_assert (MEM_P (to_rtx));
+ if (!MEM_P (to_rtx))
+ {
+ /* We can get constant negative offsets into arrays with broken
+ user code. Translate this to a trap instead of ICEing. */
+ gcc_assert (TREE_CODE (offset) == INTEGER_CST);
+ expand_builtin_trap ();
+ to_rtx = gen_rtx_MEM (BLKmode, const0_rtx);
+ }
+ offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (offset_rtx) != Pmode)
offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
but TARGET is not valid memory reference, TEMP will differ
from TARGET although it is really the same location. */
&& !(alt_rtl && rtx_equal_p (alt_rtl, target))
- /* If there's nothing to copy, don't bother. Don't call expr_size
- unless necessary, because some front-ends (C++) expr_size-hook
- aborts on objects that are not supposed to be bit-copied or
- bit-initialized. */
+ /* If there's nothing to copy, don't bother. Don't call
+ expr_size unless necessary, because some front-ends (C++)
+ expr_size-hook must not be given objects that are not
+ supposed to be bit-copied or bit-initialized. */
&& expr_size (exp) != const0_rtx)
{
if (GET_MODE (temp) != GET_MODE (target)
}
if (size != const0_rtx)
- clear_storage (target, size);
+ clear_storage (target, size, BLOCK_OP_NORMAL);
if (label)
emit_label (label);
return NULL_RTX;
}
\f
-/* Examine CTOR. Discover how many scalar fields are set to nonzero
- values and place it in *P_NZ_ELTS. Discover how many scalar fields
- are set to non-constant values and place it in *P_NC_ELTS. */
+/* Examine CTOR to discover:
+ * how many scalar fields are set to nonzero values,
+ and place it in *P_NZ_ELTS;
+ * how many scalar fields are set to non-constant values,
+ and place it in *P_NC_ELTS; and
+ * how many scalar fields in total are in CTOR,
+ and place it in *P_ELT_COUNT.
+ * if a type is a union, and the initializer from the constructor
+ is not the largest element in the union, then set *p_must_clear. */
static void
categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_nc_elts)
+ HOST_WIDE_INT *p_nc_elts,
+ HOST_WIDE_INT *p_elt_count,
+ bool *p_must_clear)
{
- HOST_WIDE_INT nz_elts, nc_elts;
- tree list;
+ unsigned HOST_WIDE_INT idx;
+ HOST_WIDE_INT nz_elts, nc_elts, elt_count;
+ tree value, purpose;
nz_elts = 0;
nc_elts = 0;
+ elt_count = 0;
- for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
{
- tree value = TREE_VALUE (list);
- tree purpose = TREE_PURPOSE (list);
HOST_WIDE_INT mult;
mult = 1;
{
case CONSTRUCTOR:
{
- HOST_WIDE_INT nz = 0, nc = 0;
- categorize_ctor_elements_1 (value, &nz, &nc);
+ HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
+ categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
nz_elts += mult * nz;
nc_elts += mult * nc;
+ elt_count += mult * ic;
}
break;
case REAL_CST:
if (!initializer_zerop (value))
nz_elts += mult;
+ elt_count += mult;
break;
case STRING_CST:
nz_elts += mult * TREE_STRING_LENGTH (value);
+ elt_count += mult * TREE_STRING_LENGTH (value);
break;
case COMPLEX_CST:
nz_elts += mult;
if (!initializer_zerop (TREE_IMAGPART (value)))
nz_elts += mult;
+ elt_count += mult;
break;
case VECTOR_CST:
{
tree v;
for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v))
- if (!initializer_zerop (TREE_VALUE (v)))
- nz_elts += mult;
+ {
+ if (!initializer_zerop (TREE_VALUE (v)))
+ nz_elts += mult;
+ elt_count += mult;
+ }
}
break;
default:
nz_elts += mult;
+ elt_count += mult;
if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
nc_elts += mult;
break;
}
}
+ if (!*p_must_clear
+ && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
+ {
+ tree init_sub_type;
+ bool clear_this = true;
+
+ if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)))
+ {
+ /* We don't expect more than one element of the union to be
+ initialized. Not sure what we should do otherwise... */
+ gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor))
+ == 1);
+
+ init_sub_type = TREE_TYPE (VEC_index (constructor_elt,
+ CONSTRUCTOR_ELTS (ctor),
+ 0)->value);
+
+ /* ??? We could look at each element of the union, and find the
+ largest element. Which would avoid comparing the size of the
+ initialized element against any tail padding in the union.
+ Doesn't seem worth the effort... */
+ if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
+ TYPE_SIZE (init_sub_type)) == 1)
+ {
+ /* And now we have to find out if the element itself is fully
+ constructed. E.g. for union { struct { int a, b; } s; } u
+ = { .s = { .a = 1 } }. */
+ if (elt_count == count_type_elements (init_sub_type, false))
+ clear_this = false;
+ }
+ }
+
+ *p_must_clear = clear_this;
+ }
+
*p_nz_elts += nz_elts;
*p_nc_elts += nc_elts;
+ *p_elt_count += elt_count;
}
void
categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
- HOST_WIDE_INT *p_nc_elts)
+ HOST_WIDE_INT *p_nc_elts,
+ HOST_WIDE_INT *p_elt_count,
+ bool *p_must_clear)
{
*p_nz_elts = 0;
*p_nc_elts = 0;
- categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts);
+ *p_elt_count = 0;
+ *p_must_clear = false;
+ categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
+ p_must_clear);
}
/* Count the number of scalars in TYPE. Return -1 on overflow or
- variable-sized. */
+ variable-sized. If ALLOW_FLEXARR is true, don't count flexible
+ array member at the end of the structure. */
HOST_WIDE_INT
-count_type_elements (tree type)
+count_type_elements (tree type, bool allow_flexarr)
{
const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
switch (TREE_CODE (type))
if (telts && host_integerp (telts, 1))
{
HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
- HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
+ HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
if (n == 0)
return 0;
else if (max / n > m)
for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
if (TREE_CODE (f) == FIELD_DECL)
{
- t = count_type_elements (TREE_TYPE (f));
+ t = count_type_elements (TREE_TYPE (f), false);
if (t < 0)
- return -1;
+ {
+ /* Check for structures with flexible array member. */
+ tree tf = TREE_TYPE (f);
+ if (allow_flexarr
+ && TREE_CHAIN (f) == NULL
+ && TREE_CODE (tf) == ARRAY_TYPE
+ && TYPE_DOMAIN (tf)
+ && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
+ && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
+ && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
+ && int_size_in_bytes (type) >= 0)
+ break;
+
+ return -1;
+ }
n += t;
}
case VOID_TYPE:
case METHOD_TYPE:
- case FILE_TYPE:
- case SET_TYPE:
case FUNCTION_TYPE:
case LANG_TYPE:
default:
if (TREE_CODE (exp) == CONSTRUCTOR)
{
- HOST_WIDE_INT nz_elts, nc_elts, elts;
+ HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+ bool must_clear;
- /* If there are no ranges of true bits, it is all zero. */
- if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
+ categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+ if (must_clear)
+ return 1;
- categorize_ctor_elements (exp, &nz_elts, &nc_elts);
- elts = count_type_elements (TREE_TYPE (exp));
+ elts = count_type_elements (TREE_TYPE (exp), false);
return nz_elts < elts / 4;
}
return initializer_zerop (exp);
}
+
+/* Return 1 if EXP contains all zeros. */
+
+static int
+all_zeros_p (tree exp)
+{
+ if (TREE_CODE (exp) == CONSTRUCTOR)
+
+ {
+ HOST_WIDE_INT nz_elts, nc_elts, count;
+ bool must_clear;
+
+ categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+ return nz_elts == 0;
+ }
+
+ return initializer_zerop (exp);
+}
\f
/* Helper function for store_constructor.
TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
case UNION_TYPE:
case QUAL_UNION_TYPE:
{
- tree elt;
+ unsigned HOST_WIDE_INT idx;
+ tree field, value;
/* If size is zero or the target is already cleared, do nothing. */
if (size == 0 || cleared)
&& ! CONSTRUCTOR_ELTS (exp))
/* If the constructor is empty, clear the union. */
{
- clear_storage (target, expr_size (exp));
+ clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
cleared = 1;
}
register whose mode size isn't equal to SIZE since
clear_storage can't handle this case. */
else if (size > 0
- && ((list_length (CONSTRUCTOR_ELTS (exp))
+ && (((int)VEC_length (constructor_elt, CONSTRUCTOR_ELTS (exp))
!= fields_length (type))
|| mostly_zeros_p (exp))
&& (!REG_P (target)
|| ((HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (target))
== size)))
{
- clear_storage (target, GEN_INT (size));
+ clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
cleared = 1;
}
/* Store each element of the constructor into the
corresponding field of TARGET. */
-
- for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, field, value)
{
- tree field = TREE_PURPOSE (elt);
- tree value = TREE_VALUE (elt);
enum machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos = 0;
if (BYTES_BIG_ENDIAN)
value
- = fold (build2 (LSHIFT_EXPR, type, value,
- build_int_cst (NULL_TREE,
- BITS_PER_WORD - bitsize)));
+ = fold_build2 (LSHIFT_EXPR, type, value,
+ build_int_cst (NULL_TREE,
+ BITS_PER_WORD - bitsize));
bitsize = BITS_PER_WORD;
mode = word_mode;
}
}
case ARRAY_TYPE:
{
- tree elt;
- int i;
+ tree value, index;
+ unsigned HOST_WIDE_INT i;
int need_to_clear;
tree domain;
tree elttype = TREE_TYPE (type);
need_to_clear = 1;
else
{
+ unsigned HOST_WIDE_INT idx;
+ tree index, value;
HOST_WIDE_INT count = 0, zero_count = 0;
need_to_clear = ! const_bounds_p;
/* This loop is a more accurate version of the loop in
mostly_zeros_p (it handles RANGE_EXPR in an index). It
is also needed to check for missing elements. */
- for (elt = CONSTRUCTOR_ELTS (exp);
- elt != NULL_TREE && ! need_to_clear;
- elt = TREE_CHAIN (elt))
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, index, value)
{
- tree index = TREE_PURPOSE (elt);
HOST_WIDE_INT this_node_count;
+
+ if (need_to_clear)
+ break;
if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
{
this_node_count = 1;
count += this_node_count;
- if (mostly_zeros_p (TREE_VALUE (elt)))
+ if (mostly_zeros_p (value))
zero_count += this_node_count;
}
if (REG_P (target))
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
else
- clear_storage (target, GEN_INT (size));
+ clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
cleared = 1;
}
/* Store each element of the constructor into the
corresponding element of TARGET, determined by counting the
elements. */
- for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
- elt;
- elt = TREE_CHAIN (elt), i++)
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), i, index, value)
{
enum machine_mode mode;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
int unsignedp;
- tree value = TREE_VALUE (elt);
- tree index = TREE_PURPOSE (elt);
rtx xtarget = target;
if (cleared && initializer_zerop (value))
/* Assign value to element index. */
position
= convert (ssizetype,
- fold (build2 (MINUS_EXPR, TREE_TYPE (index),
- index, TYPE_MIN_VALUE (domain))));
+ fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+ index, TYPE_MIN_VALUE (domain)));
position = size_binop (MULT_EXPR, position,
convert (ssizetype,
TYPE_SIZE_UNIT (elttype)));
if (minelt)
index = fold_convert (ssizetype,
- fold (build2 (MINUS_EXPR,
- TREE_TYPE (index),
- index,
- TYPE_MIN_VALUE (domain))));
+ fold_build2 (MINUS_EXPR,
+ TREE_TYPE (index),
+ index,
+ TYPE_MIN_VALUE (domain)));
position = size_binop (MULT_EXPR, index,
convert (ssizetype,
case VECTOR_TYPE:
{
- tree elt;
+ unsigned HOST_WIDE_INT idx;
+ constructor_elt *ce;
int i;
int need_to_clear;
int icode = 0;
enum machine_mode eltmode = TYPE_MODE (elttype);
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
- rtx *vector = NULL;
+ rtvec vector = NULL;
unsigned n_elts;
gcc_assert (eltmode != BLKmode);
{
unsigned int i;
- vector = alloca (n_elts);
+ vector = rtvec_alloc (n_elts);
for (i = 0; i < n_elts; i++)
- vector [i] = CONST0_RTX (GET_MODE_INNER (mode));
+ RTVEC_ELT (vector, i) = CONST0_RTX (GET_MODE_INNER (mode));
}
}
else
{
unsigned HOST_WIDE_INT count = 0, zero_count = 0;
+ tree value;
- for (elt = CONSTRUCTOR_ELTS (exp);
- elt != NULL_TREE;
- elt = TREE_CHAIN (elt))
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
{
int n_elts_here = tree_low_cst
(int_const_binop (TRUNC_DIV_EXPR,
- TYPE_SIZE (TREE_TYPE (TREE_VALUE (elt))),
+ TYPE_SIZE (TREE_TYPE (value)),
TYPE_SIZE (elttype), 0), 1);
count += n_elts_here;
- if (mostly_zeros_p (TREE_VALUE (elt)))
+ if (mostly_zeros_p (value))
zero_count += n_elts_here;
}
if (REG_P (target))
emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
else
- clear_storage (target, GEN_INT (size));
+ clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
cleared = 1;
}
+ /* Inform later passes that the old value is dead. */
if (!cleared && REG_P (target))
- /* Inform later passes that the old value is dead. */
- emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
/* Store each element of the constructor into the corresponding
element of TARGET, determined by counting the elements. */
- for (elt = CONSTRUCTOR_ELTS (exp), i = 0;
- elt;
- elt = TREE_CHAIN (elt), i += bitsize / elt_size)
+ for (idx = 0, i = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), idx, ce);
+ idx++, i += bitsize / elt_size)
{
- tree value = TREE_VALUE (elt);
- tree index = TREE_PURPOSE (elt);
HOST_WIDE_INT eltpos;
+ tree value = ce->value;
bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
if (cleared && initializer_zerop (value))
continue;
- if (index != 0)
- eltpos = tree_low_cst (index, 1);
+ if (ce->index)
+ eltpos = tree_low_cst (ce->index, 1);
else
eltpos = i;
/* Vector CONSTRUCTORs should only be built from smaller
vectors in the case of BLKmode vectors. */
gcc_assert (TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE);
- vector[eltpos] = expand_expr (value, NULL_RTX, VOIDmode, 0);
+ RTVEC_ELT (vector, eltpos)
+ = expand_expr (value, NULL_RTX, VOIDmode, 0);
}
else
{
if (vector)
emit_insn (GEN_FCN (icode)
(target,
- gen_rtx_PARALLEL (GET_MODE (target),
- gen_rtvec_v (n_elts, vector))));
- break;
- }
-
- /* Set constructor assignments. */
- case SET_TYPE:
- {
- tree elt = CONSTRUCTOR_ELTS (exp);
- unsigned HOST_WIDE_INT nbytes = int_size_in_bytes (type), nbits;
- tree domain = TYPE_DOMAIN (type);
- tree domain_min, domain_max, bitlength;
-
- /* The default implementation strategy is to extract the
- constant parts of the constructor, use that to initialize
- the target, and then "or" in whatever non-constant ranges
- we need in addition.
-
- If a large set is all zero or all ones, it is probably
- better to set it using memset. Also, if a large set has
- just a single range, it may also be better to first clear
- all the first clear the set (using memset), and set the
- bits we want. */
-
- /* Check for all zeros. */
- if (elt == NULL_TREE && size > 0)
- {
- if (!cleared)
- clear_storage (target, GEN_INT (size));
- return;
- }
-
- domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
- domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
- bitlength = size_binop (PLUS_EXPR,
- size_diffop (domain_max, domain_min),
- ssize_int (1));
-
- nbits = tree_low_cst (bitlength, 1);
-
- /* For "small" sets, or "medium-sized" (up to 32 bytes) sets
- that are "complicated" (more than one range), initialize
- (the constant parts) by copying from a constant. */
- if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
- || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
- {
- unsigned int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
- enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
- char *bit_buffer = alloca (nbits);
- HOST_WIDE_INT word = 0;
- unsigned int bit_pos = 0;
- unsigned int ibit = 0;
- unsigned int offset = 0; /* In bytes from beginning of set. */
-
- elt = get_set_constructor_bits (exp, bit_buffer, nbits);
- for (;;)
- {
- if (bit_buffer[ibit])
- {
- if (BYTES_BIG_ENDIAN)
- word |= (1 << (set_word_size - 1 - bit_pos));
- else
- word |= 1 << bit_pos;
- }
-
- bit_pos++; ibit++;
- if (bit_pos >= set_word_size || ibit == nbits)
- {
- if (word != 0 || ! cleared)
- {
- rtx datum = gen_int_mode (word, mode);
- rtx to_rtx;
-
- /* The assumption here is that it is safe to
- use XEXP if the set is multi-word, but not
- if it's single-word. */
- if (MEM_P (target))
- to_rtx = adjust_address (target, mode, offset);
- else
- {
- gcc_assert (!offset);
- to_rtx = target;
- }
- emit_move_insn (to_rtx, datum);
- }
-
- if (ibit == nbits)
- break;
- word = 0;
- bit_pos = 0;
- offset += set_word_size / BITS_PER_UNIT;
- }
- }
- }
- else if (!cleared)
- /* Don't bother clearing storage if the set is all ones. */
- if (TREE_CHAIN (elt) != NULL_TREE
- || (TREE_PURPOSE (elt) == NULL_TREE
- ? nbits != 1
- : ( ! host_integerp (TREE_VALUE (elt), 0)
- || ! host_integerp (TREE_PURPOSE (elt), 0)
- || (tree_low_cst (TREE_VALUE (elt), 0)
- - tree_low_cst (TREE_PURPOSE (elt), 0) + 1
- != (HOST_WIDE_INT) nbits))))
- clear_storage (target, expr_size (exp));
-
- for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
- {
- /* Start of range of element or NULL. */
- tree startbit = TREE_PURPOSE (elt);
- /* End of range of element, or element value. */
- tree endbit = TREE_VALUE (elt);
- HOST_WIDE_INT startb, endb;
- rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
-
- bitlength_rtx = expand_expr (bitlength,
- NULL_RTX, MEM, EXPAND_CONST_ADDRESS);
-
- /* Handle non-range tuple element like [ expr ]. */
- if (startbit == NULL_TREE)
- {
- startbit = save_expr (endbit);
- endbit = startbit;
- }
-
- startbit = convert (sizetype, startbit);
- endbit = convert (sizetype, endbit);
- if (! integer_zerop (domain_min))
- {
- startbit = size_binop (MINUS_EXPR, startbit, domain_min);
- endbit = size_binop (MINUS_EXPR, endbit, domain_min);
- }
- startbit_rtx = expand_expr (startbit, NULL_RTX, MEM,
- EXPAND_CONST_ADDRESS);
- endbit_rtx = expand_expr (endbit, NULL_RTX, MEM,
- EXPAND_CONST_ADDRESS);
-
- if (REG_P (target))
- {
- targetx
- = assign_temp
- ((build_qualified_type (lang_hooks.types.type_for_mode
- (GET_MODE (target), 0),
- TYPE_QUAL_CONST)),
- 0, 1, 1);
- emit_move_insn (targetx, target);
- }
-
- else
- {
- gcc_assert (MEM_P (target));
- targetx = target;
- }
-
- /* Optimization: If startbit and endbit are constants divisible
- by BITS_PER_UNIT, call memset instead. */
- if (TREE_CODE (startbit) == INTEGER_CST
- && TREE_CODE (endbit) == INTEGER_CST
- && (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
- && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
- {
- emit_library_call (memset_libfunc, LCT_NORMAL,
- VOIDmode, 3,
- plus_constant (XEXP (targetx, 0),
- startb / BITS_PER_UNIT),
- Pmode,
- constm1_rtx, TYPE_MODE (integer_type_node),
- GEN_INT ((endb - startb) / BITS_PER_UNIT),
- TYPE_MODE (sizetype));
- }
- else
- emit_library_call (setbits_libfunc, LCT_NORMAL,
- VOIDmode, 4, XEXP (targetx, 0),
- Pmode, bitlength_rtx, TYPE_MODE (sizetype),
- startbit_rtx, TYPE_MODE (sizetype),
- endbit_rtx, TYPE_MODE (sizetype));
-
- if (REG_P (target))
- emit_move_insn (target, targetx);
- }
+ gen_rtx_PARALLEL (GET_MODE (target), vector)));
break;
}
+
default:
gcc_unreachable ();
}
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) == INTEGER_CST
&& compare_tree_int (TYPE_SIZE (TREE_TYPE (exp)), bitsize) != 0))
{
- rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ rtx temp;
+
+ /* If EXP is a NOP_EXPR of precision less than its mode, then that
+ implies a mask operation. If the precision is the same size as
+ the field we're storing into, that mask is redundant. This is
+ particularly common with bit field assignments generated by the
+ C front end. */
+ if (TREE_CODE (exp) == NOP_EXPR)
+ {
+ tree type = TREE_TYPE (exp);
+ if (INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) < GET_MODE_BITSIZE (TYPE_MODE (type))
+ && bitsize == TYPE_PRECISION (type))
+ {
+ type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) >= bitsize)
+ exp = TREE_OPERAND (exp, 0);
+ }
+ }
+
+ temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
/* If BITSIZE is narrower than the size of the type of EXP
we will be narrowing TEMP. Normally, what's wanted are the
If the field describes a variable-sized object, *PMODE is set to
VOIDmode and *PBITSIZE is set to -1. An access cannot be made in
- this case, but the address of the object can be found. */
+ this case, but the address of the object can be found.
+
+ If KEEP_ALIGNING is true and the target is STRICT_ALIGNMENT, we don't
+ look through nodes that serve as markers of a greater alignment than
+ the one that can be deduced from the expression. These nodes make it
+ possible for front-ends to prevent temporaries from being created by
+ the middle-end on alignment considerations. For that purpose, the
+ normal operating mode at high-level is to always pass FALSE so that
+ the ultimate containing object is really returned; moreover, the
+ associated predicate handled_component_p will always return TRUE
+ on these nodes, thus indicating that they are essentially handled
+ by get_inner_reference. TRUE should only be passed when the caller
+ is scanning the expression in order to build another representation
+ and specifically knows how to handle these nodes; as such, this is
+ the normal operating mode in the RTL expanders. */
tree
get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
HOST_WIDE_INT *pbitpos, tree *poffset,
enum machine_mode *pmode, int *punsignedp,
- int *pvolatilep)
+ int *pvolatilep, bool keep_aligning)
{
tree size_tree = 0;
enum machine_mode mode = VOIDmode;
index, then convert to sizetype and multiply by the size of
the array element. */
if (! integer_zerop (low_bound))
- index = fold (build2 (MINUS_EXPR, TREE_TYPE (index),
- index, low_bound));
+ index = fold_build2 (MINUS_EXPR, TREE_TYPE (index),
+ index, low_bound);
offset = size_binop (PLUS_EXPR, offset,
size_binop (MULT_EXPR,
bitsize_int (*pbitsize));
break;
- /* We can go inside most conversions: all NON_VALUE_EXPRs, all normal
- conversions that don't change the mode, and all view conversions
- except those that need to "step up" the alignment. */
-
- case NON_LVALUE_EXPR:
- break;
-
- case NOP_EXPR:
- case CONVERT_EXPR:
- if (TYPE_MODE (TREE_TYPE (exp))
- != TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
- goto done;
- break;
-
case VIEW_CONVERT_EXPR:
- if ((TYPE_ALIGN (TREE_TYPE (exp))
+ if (keep_aligning && STRICT_ALIGNMENT
+ && (TYPE_ALIGN (TREE_TYPE (exp))
> TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0))))
- && STRICT_ALIGNMENT
&& (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
< BIGGEST_ALIGNMENT)
&& (TYPE_ALIGN_OK (TREE_TYPE (exp))
case COMPONENT_REF:
case ARRAY_REF:
case ARRAY_RANGE_REF:
- case NON_LVALUE_EXPR:
case VIEW_CONVERT_EXPR:
case REALPART_EXPR:
case IMAGPART_EXPR:
return 1;
- /* ??? Sure they are handled, but get_inner_reference may return
- a different PBITSIZE, depending upon whether the expression is
- wrapped up in a NOP_EXPR or not, e.g. for bitfields. */
- case NOP_EXPR:
- case CONVERT_EXPR:
- return (TYPE_MODE (TREE_TYPE (t))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0))));
-
default:
return 0;
}
/* Return the highest power of two that EXP is known to be a multiple of.
This is used in updating alignment of MEMs in array references. */
-static unsigned HOST_WIDE_INT
+unsigned HOST_WIDE_INT
highest_pow2_factor (tree exp)
{
unsigned HOST_WIDE_INT c0, c1;
? !TREE_ASM_WRITTEN (var)
: !DECL_RTL_SET_P (var))
{
- if (TREE_CODE (var) == VAR_DECL && DECL_VALUE_EXPR (var))
+ if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
/* Should be ignored. */;
else if (lang_hooks.expand_decl (var))
/* OK. */;
/* If the DECL isn't in memory, then the DECL wasn't properly
marked TREE_ADDRESSABLE, which will be either a front-end
or a tree optimizer bug. */
- gcc_assert (GET_CODE (result) == MEM);
+ gcc_assert (MEM_P (result));
result = XEXP (result, 0);
/* ??? Is this needed anymore? */
return result;
}
+ /* Pass FALSE as the last argument to get_inner_reference although
+ we are expanding to RTL. The rationale is that we know how to
+ handle "aligning nodes" here: we can just bypass them because
+ they won't change the final object whose address will be returned
+ (they actually exist only for that purpose). */
inner = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
+ &mode1, &unsignedp, &volatilep, false);
break;
}
result = convert_memory_address (tmode, result);
tmp = convert_memory_address (tmode, tmp);
- if (modifier == EXPAND_SUM)
+ if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
result = gen_rtx_PLUS (tmode, result, tmp);
else
{
target = 0;
}
- /* If will do cse, generate all results into pseudo registers
- since 1) that allows cse to find more things
- and 2) otherwise cse could produce an insn the machine
- cannot support. An exception is a CONSTRUCTOR into a multi-word
- MEM: that's much more likely to be most efficient into the MEM.
- Another is a CALL_EXPR which must return in memory. */
-
- if (! cse_not_expected && mode != BLKmode && target
- && (!REG_P (target) || REGNO (target) < FIRST_PSEUDO_REGISTER)
- && ! (code == CONSTRUCTOR && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
- && ! (code == CALL_EXPR && aggregate_value_p (exp, exp)))
- target = 0;
switch (code)
{
|| GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp))) == MODE_VECTOR_FLOAT)
return const_vector_from_tree (exp);
else
- return expand_expr (build1 (CONSTRUCTOR, TREE_TYPE (exp),
- TREE_VECTOR_CST_ELTS (exp)),
+ return expand_expr (build_constructor_from_list
+ (TREE_TYPE (exp),
+ TREE_VECTOR_CST_ELTS (exp)),
ignore ? const0_rtx : target, tmode, modifier);
case CONST_DECL:
subexpressions. */
if (ignore)
{
- tree elt;
+ unsigned HOST_WIDE_INT idx;
+ tree value;
- for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
- expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
+ expand_expr (value, const0_rtx, VOIDmode, 0);
return const0_rtx;
}
+ /* Try to avoid creating a temporary at all. This is possible
+ if all of the initializer is zero.
+ FIXME: try to handle all [0..255] initializers we can handle
+ with memset. */
+ else if (TREE_STATIC (exp)
+ && !TREE_ADDRESSABLE (exp)
+ && target != 0 && mode == BLKmode
+ && all_zeros_p (exp))
+ {
+ clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
+ return target;
+ }
+
/* 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
case INDIRECT_REF:
{
tree exp1 = TREE_OPERAND (exp, 0);
- tree orig;
-
- if (code == MISALIGNED_INDIRECT_REF
- && !targetm.vectorize.misaligned_mem_ok (mode))
- abort ();
if (modifier != EXPAND_WRITE)
{
temp = gen_rtx_MEM (mode, op0);
- orig = REF_ORIGINAL (exp);
- if (!orig)
- orig = exp;
- set_mem_attributes (temp, orig, 0);
+ set_mem_attributes (temp, exp, 0);
+
+ /* Resolve the misalignment now, so that we don't have to remember
+ to resolve it later. Of course, this only works for reads. */
+ /* ??? When we get around to supporting writes, we'll have to handle
+ this in store_expr directly. The vectorizer isn't generating
+ those yet, however. */
+ if (code == MISALIGNED_INDIRECT_REF)
+ {
+ int icode;
+ rtx reg, insn;
+
+ gcc_assert (modifier == EXPAND_NORMAL
+ || modifier == EXPAND_STACK_PARM);
+
+ /* The vectorizer should have already checked the mode. */
+ icode = movmisalign_optab->handlers[mode].insn_code;
+ gcc_assert (icode != CODE_FOR_nothing);
+
+ /* 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, temp);
+ emit_insn (insn);
+
+ return reg;
+ }
return temp;
}
+ case TARGET_MEM_REF:
+ {
+ struct mem_address addr;
+
+ get_address_description (exp, &addr);
+ op0 = addr_for_mem_ref (&addr, true);
+ op0 = memory_address (mode, op0);
+ temp = gen_rtx_MEM (mode, op0);
+ set_mem_attributes (temp, TMR_ORIGINAL (exp), 0);
+ }
+ return temp;
+
case ARRAY_REF:
{
&& ! TREE_SIDE_EFFECTS (array)
&& TREE_CODE (index) == INTEGER_CST)
{
- tree elem;
-
- for (elem = CONSTRUCTOR_ELTS (array);
- (elem && !tree_int_cst_equal (TREE_PURPOSE (elem), index));
- elem = TREE_CHAIN (elem))
- ;
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
- if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
- return expand_expr (fold (TREE_VALUE (elem)), target, tmode,
- modifier);
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (array), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))
+ {
+ if (!TREE_SIDE_EFFECTS (value))
+ return expand_expr (fold (value), target, tmode, modifier);
+ break;
+ }
}
else if (optimize >= 1
if (TREE_CODE (init) == CONSTRUCTOR)
{
- tree elem;
-
- for (elem = CONSTRUCTOR_ELTS (init);
- (elem
- && !tree_int_cst_equal (TREE_PURPOSE (elem), index));
- elem = TREE_CHAIN (elem))
- ;
-
- if (elem && !TREE_SIDE_EFFECTS (TREE_VALUE (elem)))
- return expand_expr (fold (TREE_VALUE (elem)), target,
- tmode, modifier);
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
+
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix,
+ field, value)
+ if (tree_int_cst_equal (field, index))
+ {
+ if (!TREE_SIDE_EFFECTS (value))
+ return expand_expr (fold (value), target, tmode,
+ modifier);
+ break;
+ }
}
else if (TREE_CODE (init) == STRING_CST
&& 0 > compare_tree_int (index,
appropriate field if it is present. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == CONSTRUCTOR)
{
- tree elt;
+ unsigned HOST_WIDE_INT idx;
+ tree field, value;
- for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
- elt = TREE_CHAIN (elt))
- if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)),
+ idx, field, value)
+ if (field == TREE_OPERAND (exp, 1)
/* We can normally use the value of the field in the
CONSTRUCTOR. However, if this is a bitfield in
an integral mode that we can fit in a HOST_WIDE_INT,
since this is done implicitly by the constructor. If
the bitfield does not meet either of those conditions,
we can't do this optimization. */
- && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
- || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
- == MODE_INT)
- && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+ && (! DECL_BIT_FIELD (field)
+ || ((GET_MODE_CLASS (DECL_MODE (field)) == MODE_INT)
+ && (GET_MODE_BITSIZE (DECL_MODE (field))
<= HOST_BITS_PER_WIDE_INT))))
{
- if (DECL_BIT_FIELD (TREE_PURPOSE (elt))
+ if (DECL_BIT_FIELD (field)
&& modifier == EXPAND_STACK_PARM)
target = 0;
- op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
- if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+ op0 = expand_expr (value, target, tmode, modifier);
+ if (DECL_BIT_FIELD (field))
{
- HOST_WIDE_INT bitsize
- = TREE_INT_CST_LOW (DECL_SIZE (TREE_PURPOSE (elt)));
- enum machine_mode imode
- = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+ HOST_WIDE_INT bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
+ enum machine_mode imode = TYPE_MODE (TREE_TYPE (field));
- if (TYPE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+ if (TYPE_UNSIGNED (TREE_TYPE (field)))
{
op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
op0 = expand_and (imode, op0, op1, target);
tree offset;
int volatilep = 0;
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
+ &mode1, &unsignedp, &volatilep, true);
rtx orig_op0;
/* If we got back the original object, something is wrong. Perhaps
|| modifier == EXPAND_STACK_PARM)
? modifier : EXPAND_NORMAL);
- /* If this is a constant, put it into a register if it is a
- legitimate constant and OFFSET is 0 and memory if it isn't. */
+ /* If this is a constant, put it into a register if it is a legitimate
+ constant, OFFSET is 0, and we won't try to extract outside the
+ register (in case we were passed a partially uninitialized object
+ or a view_conversion to a larger size). Force the constant to
+ memory otherwise. */
if (CONSTANT_P (op0))
{
enum machine_mode mode = TYPE_MODE (TREE_TYPE (tem));
if (mode != BLKmode && LEGITIMATE_CONSTANT_P (op0)
- && offset == 0)
+ && offset == 0
+ && bitpos + bitsize <= GET_MODE_BITSIZE (mode))
op0 = force_reg (mode, op0);
else
op0 = validize_mem (force_const_mem (mode, op0));
}
- /* Otherwise, if this object not in memory and we either have an
- offset or a BLKmode result, put it there. This case can't occur in
- C, but can in Ada if we have unchecked conversion of an expression
- from a scalar type to an array or record type or for an
- ARRAY_RANGE_REF whose type is BLKmode. */
+ /* Otherwise, if this object not in memory and we either have an
+ offset, a BLKmode result, or a reference outside the object, put it
+ there. Such cases can occur in Ada if we have unchecked conversion
+ of an expression from a scalar type to an array or record type or
+ for an ARRAY_RANGE_REF whose type is BLKmode. */
else if (!MEM_P (op0)
&& (offset != 0
+ || (bitpos + bitsize > GET_MODE_BITSIZE (GET_MODE (op0)))
|| (code == ARRAY_RANGE_REF && mode == BLKmode)))
{
tree nt = build_qualified_type (TREE_TYPE (tem),
case VIEW_CONVERT_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
- /* If the input and output modes are both the same, we are done.
- Otherwise, if neither mode is BLKmode and both are integral and within
- a word, we can use gen_lowpart. If neither is true, make sure the
- operand is in memory and convert the MEM to the new mode. */
+ /* If the input and output modes are both the same, we are done. */
if (TYPE_MODE (type) == GET_MODE (op0))
;
+ /* If neither mode is BLKmode, and both modes are the same size
+ then we can use gen_lowpart. */
else if (TYPE_MODE (type) != BLKmode && GET_MODE (op0) != BLKmode
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
- && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT
- && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (op0)) <= UNITS_PER_WORD)
- op0 = gen_lowpart (TYPE_MODE (type), op0);
+ && GET_MODE_SIZE (TYPE_MODE (type))
+ == GET_MODE_SIZE (GET_MODE (op0)))
+ {
+ if (GET_CODE (op0) == SUBREG)
+ op0 = force_reg (GET_MODE (op0), op0);
+ op0 = gen_lowpart (TYPE_MODE (type), op0);
+ }
+ /* If both modes are integral, then we can convert from one to the
+ other. */
+ else if (SCALAR_INT_MODE_P (GET_MODE (op0))
+ && SCALAR_INT_MODE_P (TYPE_MODE (type)))
+ op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
+ TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ /* As a last resort, spill op0 to memory, and reload it in a
+ different mode. */
else if (!MEM_P (op0))
{
/* If the operand is not a MEM, force it into memory. Since we
}
else if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
- && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
&& TREE_CONSTANT (TREE_OPERAND (exp, 0)))
{
rtx constant_part;
optab other_optab = zextend_p ? smul_widen_optab : umul_widen_optab;
this_optab = zextend_p ? umul_widen_optab : smul_widen_optab;
- if (mode == GET_MODE_WIDER_MODE (innermode))
+ if (mode == GET_MODE_2XWIDER_MODE (innermode))
{
if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
{
return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
case RDIV_EXPR:
- /* Emit a/b as a*(1/b). Later we may manage CSE the reciprocal saving
- expensive divide. If not, combine will rebuild the original
- computation. */
- if (flag_unsafe_math_optimizations && optimize && !optimize_size
- && TREE_CODE (type) == REAL_TYPE
- && !real_onep (TREE_OPERAND (exp, 0)))
- return expand_expr (build2 (MULT_EXPR, type, TREE_OPERAND (exp, 0),
- build2 (RDIV_EXPR, type,
- build_real (type, dconst1),
- TREE_OPERAND (exp, 1))),
- target, tmode, modifier);
-
goto binop;
case TRUNC_MOD_EXPR:
/* At this point, a MEM target is no longer useful; we will get better
code without it. */
- if (MEM_P (target))
+ if (! REG_P (target))
target = gen_reg_rtx (mode);
/* If op1 was placed in target, swap op0 and op1. */
if (target != op0 && target == op1)
{
- rtx tem = op0;
+ temp = op0;
op0 = op1;
- op1 = tem;
+ op1 = temp;
}
+ /* We generate better code and avoid problems with op1 mentioning
+ target by forcing op1 into a pseudo if it isn't a constant. */
+ if (! CONSTANT_P (op1))
+ op1 = force_reg (mode, op1);
+
+#ifdef HAVE_conditional_move
+ /* Use a conditional move if possible. */
+ if (can_conditionally_move_p (mode))
+ {
+ enum rtx_code comparison_code;
+ rtx insn;
+
+ if (code == MAX_EXPR)
+ comparison_code = unsignedp ? GEU : GE;
+ else
+ comparison_code = unsignedp ? LEU : LE;
+
+ /* ??? 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. */
+ insn = emit_conditional_move (target, comparison_code,
+ op0, op1, mode,
+ op0, op1, mode,
+ unsignedp);
+
+ /* If we could do the conditional move, emit the sequence,
+ and return. */
+ if (insn)
+ {
+ rtx seq = get_insns ();
+ end_sequence ();
+ emit_insn (seq);
+ return target;
+ }
+
+ /* Otherwise discard the sequence and fall back to code with
+ branches. */
+ end_sequence ();
+ }
+#endif
if (target != op0)
emit_move_insn (target, op0);
- op0 = gen_label_rtx ();
+ temp = gen_label_rtx ();
/* If this mode is an integer too wide to compare properly,
compare word by word. Rely on cse to optimize constant cases. */
{
if (code == MAX_EXPR)
do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
- NULL_RTX, op0);
+ NULL_RTX, temp);
else
do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
- NULL_RTX, op0);
+ NULL_RTX, temp);
}
else
{
do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
- unsignedp, mode, NULL_RTX, NULL_RTX, op0);
+ unsignedp, mode, NULL_RTX, NULL_RTX, temp);
}
emit_move_insn (target, op1);
- emit_label (op0);
+ emit_label (temp);
return target;
case BIT_NOT_EXPR:
op2 = expand_expr (oprnd2, NULL_RTX, VOIDmode, 0);
temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
target, unsignedp);
- if (temp == 0)
- abort ();
+ gcc_assert (temp);
+ return temp;
+ }
+
+ case REDUC_MAX_EXPR:
+ case REDUC_MIN_EXPR:
+ case REDUC_PLUS_EXPR:
+ {
+ op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
+ this_optab = optab_for_tree_code (code, type);
+ temp = expand_unop (mode, this_optab, op0, target, unsignedp);
+ gcc_assert (temp);
return temp;
}
+ case VEC_LSHIFT_EXPR:
+ case VEC_RSHIFT_EXPR:
+ {
+ target = expand_vec_shift_expr (exp, target);
+ return target;
+ }
default:
return lang_hooks.expand_expr (exp, original_target, tmode,
if ((code == LT && integer_zerop (arg1))
|| (! only_cheap && code == GE && integer_zerop (arg1)))
;
- else if (BRANCH_COST >= 0
- && ! only_cheap && (code == NE || code == EQ)
+ else if (! only_cheap && (code == NE || code == EQ)
&& TREE_CODE (type) != REAL_TYPE
&& ((abs_optab->handlers[(int) operand_mode].insn_code
!= CODE_FOR_nothing)
if (! HAVE_tablejump)
return 0;
- index_expr = fold (build2 (MINUS_EXPR, index_type,
- convert (index_type, index_expr),
- convert (index_type, minval)));
+ index_expr = fold_build2 (MINUS_EXPR, index_type,
+ convert (index_type, index_expr),
+ convert (index_type, minval));
index = expand_expr (index_expr, NULL_RTX, VOIDmode, 0);
do_pending_stack_adjust ();