/* 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
{
enum machine_mode to_mode = GET_MODE (to);
enum machine_mode from_mode = GET_MODE (from);
- int to_real = GET_MODE_CLASS (to_mode) == MODE_FLOAT;
- int from_real = GET_MODE_CLASS (from_mode) == MODE_FLOAT;
+ int to_real = SCALAR_FLOAT_MODE_P (to_mode);
+ int from_real = SCALAR_FLOAT_MODE_P (from_mode);
enum insn_code code;
rtx libcall;
}
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);
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
+ && INTVAL (size) == (HOST_WIDE_INT) GET_MODE_SIZE (mode))
{
- 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))
- {
- 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
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. */
- || (GET_CODE (cplx) == REG
+ || (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)
- /* For MEMs we always try to make a "subreg", that is to adjust
- the MEM, because store_bit_field may generate overly
- convoluted RTL for sub-word fields. */
- || MEM_P (cplx))
+ && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
{
rtx part = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
}
}
+ /* 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
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. */
- || (GET_CODE (cplx) == REG
+ || (REG_P (cplx)
&& REGNO (cplx) < FIRST_PSEUDO_REGISTER
- && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0)
- /* For MEMs we always try to make a "subreg", that is to adjust
- the MEM, because extract_bit_field may generate overly
- convoluted RTL for sub-word fields. */
- || MEM_P (cplx))
+ && hard_regno_nregs[REGNO (cplx)][cmode] % 2 == 0))
{
rtx ret = simplify_gen_subreg (imode, cplx, cmode,
imag_p ? GET_MODE_SIZE (imode) : 0);
true, NULL_RTX, imode, imode);
}
\f
-/* A subroutine of emit_move_via_alt_mode. Yet another lowpart generator.
+/* 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. */
+ 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_change_mode (enum machine_mode new_mode,
- enum machine_mode old_mode, rtx x)
+ enum machine_mode old_mode, rtx x, bool force)
{
rtx ret;
}
else
{
- /* Note that we do want simplify_subreg's behaviour of validating
+ /* 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. */
- ret = simplify_subreg (new_mode, x, old_mode, 0);
+ /* 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 ret;
}
/* 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, or NULL if X or Y cannot be represented in ALT_MODE. */
-
-static rtx
-emit_move_via_alt_mode (enum machine_mode alt_mode, enum machine_mode mode,
- enum insn_code code, rtx x, rtx y)
-{
- x = emit_move_change_mode (alt_mode, mode, x);
- if (x == NULL_RTX)
- return NULL_RTX;
- y = emit_move_change_mode (alt_mode, mode, y);
- if (y == NULL_RTX)
- return NULL_RTX;
- return emit_insn (GEN_FCN (code) (x, y));
-}
-
-/* A subroutine of emit_move_insn_1. Generate a move from Y into X using
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)
+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.
#endif
if (code == PRE_DEC || code == POST_DEC)
adjust = -adjust;
+ else if (code == PRE_MODIFY || code == POST_MODIFY)
+ {
+ rtx expr = XEXP (XEXP (x, 0), 1);
+ HOST_WIDE_INT val;
+
+ gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
+ gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+ val = INTVAL (XEXP (expr, 1));
+ if (GET_CODE (expr) == MINUS)
+ val = -val;
+ gcc_assert (adjust == val || adjust == -val);
+ adjust = val;
+ }
/* Do not use anti_adjust_stack, since we don't want to update
stack_pointer_delta. */
{
case PRE_INC:
case PRE_DEC:
+ case PRE_MODIFY:
temp = stack_pointer_rtx;
break;
case POST_INC:
- temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode));
- break;
case POST_DEC:
- temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode));
+ case POST_MODIFY:
+ temp = plus_constant (stack_pointer_rtx, -adjust);
break;
default:
gcc_unreachable ();
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);
* 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. */
+ 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_elt_count)
+ HOST_WIDE_INT *p_elt_count,
+ bool *p_must_clear)
{
+ unsigned HOST_WIDE_INT idx;
HOST_WIDE_INT nz_elts, nc_elts, elt_count;
- tree list;
+ 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, count = 0;
- categorize_ctor_elements_1 (value, &nz, &nc, &count);
+ 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 * count;
+ elt_count += mult * ic;
}
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_elt_count)
+ HOST_WIDE_INT *p_elt_count,
+ bool *p_must_clear)
{
*p_nz_elts = 0;
*p_nc_elts = 0;
*p_elt_count = 0;
- categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count);
+ *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 FUNCTION_TYPE:
case LANG_TYPE:
default:
{
HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+ bool must_clear;
- categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count);
- elts = count_type_elements (TREE_TYPE (exp));
+ categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+ if (must_clear)
+ return 1;
+
+ 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))));
+ gen_rtx_PARALLEL (GET_MODE (target), vector)));
break;
}
&& 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 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))
}
if (UNARY_P (value))
{
+ int unsignedp = 0;
+
op1 = force_operand (XEXP (value, 0), NULL_RTX);
- return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+ switch (code)
+ {
+ case ZERO_EXTEND: case UNSIGNED_FIX: case UNSIGNED_FLOAT:
+ unsignedp = 1;
+ /* fall through. */
+ case TRUNCATE:
+ case SIGN_EXTEND: case FIX: case FLOAT:
+ return convert_to_mode (GET_MODE (value), op1, unsignedp);
+ default:
+ return expand_simple_unop (GET_MODE (value), code, op1, target, 0);
+ }
}
#ifdef INSN_SCHEDULING
/* 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
{
information. It would be better of the diagnostic routines
used the file/line information embedded in the tree nodes rather
than globals. */
- if (cfun && EXPR_HAS_LOCATION (exp))
+ if (cfun && cfun->ib_boundaries_block && EXPR_HAS_LOCATION (exp))
{
location_t saved_location = input_location;
input_location = EXPR_LOCATION (exp);
optab this_optab;
rtx subtarget, original_target;
int ignore;
- tree context;
+ tree context, subexp0, subexp1;
bool reduce_bit_field = false;
#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore \
? reduce_to_bit_field_precision ((expr), \
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;
+ unsigned HOST_WIDE_INT ix;
+ tree field, value;
- for (elem = CONSTRUCTOR_ELTS (array);
- (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);
+ 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;
from a narrower type. If this machine supports multiplying
in that narrower type with a result in the desired type,
do it that way, and avoid the explicit type-conversion. */
- if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
+
+ subexp0 = TREE_OPERAND (exp, 0);
+ subexp1 = TREE_OPERAND (exp, 1);
+ /* First, check if we have a multiplication of one signed and one
+ unsigned operand. */
+ if (TREE_CODE (subexp0) == NOP_EXPR
+ && TREE_CODE (subexp1) == NOP_EXPR
+ && TREE_CODE (type) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+ < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
+ && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subexp1, 0))))
+ && (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0)))
+ != TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp1, 0)))))
+ {
+ enum machine_mode innermode
+ = TYPE_MODE (TREE_TYPE (TREE_OPERAND (subexp0, 0)));
+ this_optab = usmul_widen_optab;
+ if (mode == GET_MODE_WIDER_MODE (innermode))
+ {
+ if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
+ expand_operands (TREE_OPERAND (subexp0, 0),
+ TREE_OPERAND (subexp1, 0),
+ NULL_RTX, &op0, &op1, 0);
+ else
+ expand_operands (TREE_OPERAND (subexp0, 0),
+ TREE_OPERAND (subexp1, 0),
+ NULL_RTX, &op1, &op0, 0);
+
+ goto binop3;
+ }
+ }
+ }
+ /* Check for a multiplication with matching signedness. */
+ else if (TREE_CODE (TREE_OPERAND (exp, 0)) == NOP_EXPR
&& TREE_CODE (type) == INTEGER_TYPE
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
< TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))
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:
/* 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
if (! CONSTANT_P (op1))
op1 = force_reg (mode, op1);
- if (target != op0)
- emit_move_insn (target, op0);
+ {
+ enum rtx_code comparison_code;
+ rtx cmpop1 = op1;
- op0 = gen_label_rtx ();
+ if (code == MAX_EXPR)
+ comparison_code = unsignedp ? GEU : GE;
+ else
+ comparison_code = unsignedp ? LEU : LE;
- /* If this mode is an integer too wide to compare properly,
- compare word by word. Rely on cse to optimize constant cases. */
- if (GET_MODE_CLASS (mode) == MODE_INT
- && ! can_compare_p (GE, mode, ccp_jump))
- {
- if (code == MAX_EXPR)
- do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
- NULL_RTX, op0);
- else
- do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
- NULL_RTX, op0);
- }
- else
- {
- do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
- unsignedp, mode, NULL_RTX, NULL_RTX, op0);
- }
+ /* Canonicalize to comparisons against 0. */
+ if (op1 == const1_rtx)
+ {
+ /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1)
+ or (a != 0 ? a : 1) for unsigned.
+ For MIN we are safe converting (a <= 1 ? a : 1)
+ into (a <= 0 ? a : 1) */
+ cmpop1 = const0_rtx;
+ if (code == MAX_EXPR)
+ comparison_code = unsignedp ? NE : GT;
+ }
+ if (op1 == constm1_rtx && !unsignedp)
+ {
+ /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1)
+ and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */
+ cmpop1 = const0_rtx;
+ 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. */
+ insn = emit_conditional_move (target, comparison_code,
+ op0, cmpop1, 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);
+
+ 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 (GET_MODE_CLASS (mode) == MODE_INT
+ && ! can_compare_p (GE, mode, ccp_jump))
+ {
+ if (code == MAX_EXPR)
+ do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
+ NULL_RTX, temp);
+ else
+ do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
+ NULL_RTX, temp);
+ }
+ else
+ {
+ do_compare_rtx_and_jump (target, cmpop1, comparison_code,
+ 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 ();